# XCM support in Smart Contracts With the coming Hub update, we want to create the best experience we can for Smart Contract (SC) developers. This includes adding support for XCM. ## Features XCM support in smart contracts encompasses a lot of features: 1. In XCM programs: - Handle withdrawing and depositing ERC20s and ERC721s - Execute SC calls - Perform cross-chain transfers 2. Off-chain: - Accurately estimate fees for any call that deals with XCM 3. In SCs: - Executing XCM programs - Sending XCM programs - Making cross-chain queries ## Releases Let's split the features into the different upcoming releases. 1. stable2506 (basic functionality) - ERC20 support in XCM - Executing XCM programs from a SC - Sending XCM programs from a SC - Accurately estimating fees for XCM calls (no calling SCs!) 2. stable2509 (complete functionality) - ERC721 support in XCM - Execute SC calls in XCM - Making cross-chain transfers - Library for SCs with high-level functions - Making cross-chain queries - Accurately estimating fees for XCM calls (SC calls included) Now I'll detail what's required for each of these in turn. ## In XCM programs ### Dealing with ERC20s and ERC721s ERC20s and ERC721s are assets that are implemented by a smart contract, fungible and non-fungible respectively. Dealing with them means being able to interpret instructions like [`WithdrawAsset`](https://github.com/paritytech/polkadot-sdk/blob/98cefb870b0fe6dbc7fa6d02ffefd1268ff2a5b7/polkadot/xcm/xcm-executor/src/lib.rs#L895) and [`DepositAsset`](https://github.com/paritytech/polkadot-sdk/blob/98cefb870b0fe6dbc7fa6d02ffefd1268ff2a5b7/polkadot/xcm/xcm-executor/src/lib.rs#L1758) when they reference ERC20s. NOTE: We mean **pure** ERC20 tokens here, not the [ERC20 precompiles for already existing assets](https://github.com/paritytech/polkadot-sdk/pull/8554), these can (and should) be referenced by their original Asset Ids. This was implemented in [SDK#7762](https://github.com/paritytech/polkadot-sdk/pull/7762). We need the same for [ERC721](https://eips.ethereum.org/EIPS/eip-721). We should make use of the [traits for NFTs](https://github.com/paritytech/polkadot-sdk/pull/5620) for that. ### Fees Calling SCs has some caveats regarding fees. When SCs are executed, they are given a gas limit, they meter gas during execution and [return the consumed gas at the end](https://github.com/paritytech/polkadot-sdk/blob/98cefb870b0fe6dbc7fa6d02ffefd1268ff2a5b7/substrate/frame/revive/src/primitives.rs#L68). This **consumed gas** value can be used to refund part of the fee paid. SCs also take **storage deposits** for any call that puts bytes in the contract's storage. They do this by [metering the times storage is written to](https://github.com/paritytech/polkadot-sdk/blob/98cefb870b0fe6dbc7fa6d02ffefd1268ff2a5b7/substrate/frame/revive/src/storage/meter.rs#L43) and [holding deposits based on that](https://github.com/paritytech/polkadot-sdk/blob/98cefb870b0fe6dbc7fa6d02ffefd1268ff2a5b7/substrate/frame/revive/src/storage/meter.rs#L487). For stable 2506, we decided to hardcode a gas limit for an ERC20 transfer operation and use that in the XCM executor. This limit makes it much easier to use the same fee model we currently have in XCM. In the future, we might look at taking fees directly from the `fees` register. Because users don't specify weight when they use `PayFees` (or even `BuyExecution` since most people set the weight limit to `Unlimited`), we would need to assume the weight of the message is the amount of weight that can be bought with the fees the user specified. This is a change in the current model and means that if the user overestimates fees the message might actually not fit in a block. Regarding storage deposits, we also **won't** take them from XCM fees, but rather directly from the user. This is not ideal, but these deposits are very specific. We don't even handle deposits when you call `Transact`. ## Off-chain A lot of the fee concerns from the previous section carry on to this section because of the need to accurately estimate all fees. ### Fee estimation We would need to make sure the `DryRunApi` can successfully dry-run a program with EVM calls. We already have calls for execution fees and delivery fees in `XcmPaymentApi`. If we wanted to include storage deposits or any other type of deposit we would need to improve our `DryRunApi`. ## In SCs All of the XCM functionality we want to expose to contracts will be exposed via `precompiles`, using the [pallet-revive precompile framework](https://github.com/paritytech/polkadot-sdk/pull/8262). The precompile is being developed in [SDK#8693](https://github.com/paritytech/polkadot-sdk/pull/8693/). The XCM precompile will have three functions: - execute - send - new_query The precompile from that PR has two, `execute` and `send`. Can we include queries later? ### Queries This could be further split into receiving and sending. #### Sending In order to send a query we need a host function for contracts that calls [pallet-xcm's new_query function](https://github.com/paritytech/polkadot-sdk/blob/42e9de7f4fdb191cd531b443c68cfe19886ec311/polkadot/xcm/pallet-xcm/src/lib.rs#L1476) to store a [Query](https://github.com/paritytech/polkadot-sdk/blob/42e9de7f4fdb191cd531b443c68cfe19886ec311/polkadot/xcm/pallet-xcm/src/lib.rs#L664). #### Scenarios Both scenarios assume that a new query is created using the XCM precompile. Then, an XCM message (e.g.: `Xcm(vec![Transact {...}, ReportTransactStatus(QueryResponseInfo {queryId …}])`) should be sent to the destination chain, essentially linking a `queryId` to some bytes that are meant to be executed. ##### Perform a remote call and get the result of the execution We need to have a way of getting the result of the execution of a remote call. This should return a [response](https://github.com/paritytech/polkadot-sdk/blob/master/polkadot/xcm/src/v5/mod.rs#L273) with the result. In case of failing, the response should contain the actual error. ##### Query external data / Call view functions Allow the smart contracts on Asset Hub to query data on external consensus systems. This might be a call to a specific pallet or a view function in a smart contract. We should be able to send [PVQ](https://github.com/polkadot-fellows/RFCs/pull/126) blobs using the new [ReportQuery](https://github.com/open-web3-stack/XCQ/issues/6) instruction. #### Receiving A message is received by the runtime to respond to a query with some query id. This will match the query id of the query created previously. We need a host function in contracts that calls [pallet-xcm's take_response](https://github.com/paritytech/polkadot-sdk/blob/42e9de7f4fdb191cd531b443c68cfe19886ec311/polkadot/xcm/pallet-xcm/src/lib.rs#L1503) to poll for the response, this could result in an callback, which could be handled by a function in the contract.