diff --git a/.snippets/code/builders/interoperability/xcm/core-concepts/location-to-account.js b/.snippets/code/builders/interoperability/xcm/core-concepts/location-to-account.js new file mode 100644 index 000000000..cb50b36b2 --- /dev/null +++ b/.snippets/code/builders/interoperability/xcm/core-concepts/location-to-account.js @@ -0,0 +1,25 @@ +import { ApiPromise, WsProvider } from '@polkadot/api'; + +const main = async () => { + // Construct API provider + const wsProvider = new WsProvider('INSERT_WSS_ENDPOINT'); + const api = await ApiPromise.create({ provider: wsProvider }); + + // Define the multilocation parameter + const multilocation = { + V4: { + parents: 1, + interior: 'Here', + }, + }; + + // Query the locationToAccountApi using convertLocation method + const result = + await api.call.locationToAccountApi.convertLocation(multilocation); + console.log('Conversion result:', result.toHuman()); + + // Disconnect the API + await api.disconnect(); +}; + +main().catch(console.error); diff --git a/.snippets/code/builders/interoperability/xcm/send-execute-xcm/dry-run/dry-run-call-return-data.json b/.snippets/code/builders/interoperability/xcm/send-execute-xcm/dry-run/dry-run-call-return-data.json new file mode 100644 index 000000000..ca82eae4b --- /dev/null +++ b/.snippets/code/builders/interoperability/xcm/send-execute-xcm/dry-run/dry-run-call-return-data.json @@ -0,0 +1,46 @@ +Ok: { + executionResult: { + Ok: { + actualWeight: { + refTime: 7,301,734,000 + proofSize: 20,928 + } + paysFee: Yes + } + } + emittedEvents: [ + { + method: Burned + section: balances + index: 0x030b + data: { + who: 0x88bcE0b038eFFa09e58fE6d24fDe4b5Af21aa798 + amount: 100,000,000,000,000,000 + } + } + { + method: Minted + section: balances + index: 0x030a + data: { + who: 0x3Cd0A705a2DC65e5b1E1205896BaA2be8A07c6e0 + amount: 100,000,000,000,000,000 + } + } + { + method: Attempted + section: polkadotXcm + index: 0x1c00 + data: { + outcome: { + Complete: { + used: { + refTime: 7,250,000,000 + proofSize: 19,374 + } + } + } + } + } + ] // Additional events returned here + // Omitted for clarity \ No newline at end of file diff --git a/.snippets/code/builders/interoperability/xcm/send-execute-xcm/dry-run/dry-run-call.js b/.snippets/code/builders/interoperability/xcm/send-execute-xcm/dry-run/dry-run-call.js new file mode 100644 index 000000000..74d4494f1 --- /dev/null +++ b/.snippets/code/builders/interoperability/xcm/send-execute-xcm/dry-run/dry-run-call.js @@ -0,0 +1,41 @@ +import { ApiPromise, WsProvider } from '@polkadot/api'; +import { hexToU8a } from '@polkadot/util'; + +const main = async () => { + try { + // Construct API provider + const wsProvider = new WsProvider('INSERT_WSS_ENDPOINT'); + const api = await ApiPromise.create({ provider: wsProvider }); + + console.log('Connected to the API. Preparing dry run call...'); + + // Create a test account (you should replace this with an actual account) + const testAccount = api.createType( + 'AccountId20', + '0x88bcE0b038eFFa09e58fE6d24fDe4b5Af21aa798' + ); + + // The call data (replace with your actual call data) + const callData = + '0x1c030408000400010403001300008a5d784563010d010204000103003cd0a705a2dc65e5b1e1205896baa2be8a07c6e007803822b001ba2e0100'; // Your hex-encoded call data + + // Convert hex to Uint8Array + const callDataU8a = hexToU8a(callData); + + // Perform the dry run call + const result = await api.call.dryRunApi.dryRunCall( + { system: { Signed: testAccount } }, // origin + callDataU8a // call + ); + + console.log('Dry run result:', result.toHuman()); + + // Disconnect the API + await api.disconnect(); + console.log('Disconnected from the API.'); + } catch (error) { + console.error('An error occurred:', error); + } +}; + +main().catch(console.error); diff --git a/.snippets/code/builders/interoperability/xcm/send-execute-xcm/dry-run/dry-run-xcm-return-data.json b/.snippets/code/builders/interoperability/xcm/send-execute-xcm/dry-run/dry-run-xcm-return-data.json new file mode 100644 index 000000000..a25d909f7 --- /dev/null +++ b/.snippets/code/builders/interoperability/xcm/send-execute-xcm/dry-run/dry-run-xcm-return-data.json @@ -0,0 +1,60 @@ +Ok: { + executionResult: { + Complete: { + used: { + refTime: 76,473,048,000 + proofSize: 222,483 + } + } + } + emittedEvents: [ + { + method: Burned + section: assets + index: 0x1d03 + data: { + assetId: 42,259,045,809,535,163,221,576,417,993,425,387,648 + owner: 0x506172656E740000000000000000000000000000 + balance: 1,000,000,000,000 + } + } + { + method: NewAccount + section: system + index: 0x0003 + data: { + account: 0x1Ccc29B6C837be6A0C03d544b5Aa8580f9fb9489 + } + } + { + method: Issued + section: assets + index: 0x1d01 + data: { + assetId: 42,259,045,809,535,163,221,576,417,993,425,387,648 + owner: 0x1Ccc29B6C837be6A0C03d544b5Aa8580f9fb9489 + amount: 959,944,978,002 + } + } + { + method: Issued + section: assets + index: 0x1d01 + data: { + assetId: 42,259,045,809,535,163,221,576,417,993,425,387,648 + owner: 0x6d6F646c70632f74727372790000000000000000 + amount: 40,055,021,998 + } + } + ] + forwardedXcms: [ + [ + { + V4: { + parents: 1 + interior: Here + } + } + [] + ] // Additional events returned here + // Omitted for clarity \ No newline at end of file diff --git a/.snippets/code/builders/interoperability/xcm/send-execute-xcm/dry-run/dry-run-xcm.js b/.snippets/code/builders/interoperability/xcm/send-execute-xcm/dry-run/dry-run-xcm.js new file mode 100644 index 000000000..3476f5a82 --- /dev/null +++ b/.snippets/code/builders/interoperability/xcm/send-execute-xcm/dry-run/dry-run-xcm.js @@ -0,0 +1,62 @@ +import { ApiPromise, WsProvider } from '@polkadot/api'; + +const main = async () => { + try { + // Construct API provider + const wsProvider = new WsProvider('INSERT_WSS_ENDPOINT'); + const api = await ApiPromise.create({ provider: wsProvider }); + console.log('Connected to the API. Preparing dry run XCM call...'); + + // Define the origin + const origin = { V4: { parents: 1, interior: 'Here' } }; + + const assetMultiLocation = { + parents: 0, + interior: { X1: { PalletInstance: 3 } }, + }; // The asset's location (adjust PalletInstance as needed) + + const amountToSend = 1000000000000; // Adjust this value as needed + + const message = { + V4: [ + { + WithdrawAsset: [ + { + id: { parents: 1, interior: 'Here' }, + fun: { Fungible: amountToSend }, + }, + ], + }, + { + BuyExecution: { + fees: { + id: { parents: 1, interior: 'Here' }, + fun: { Fungible: amountToSend }, + }, + weightLimit: { Unlimited: null }, + }, + }, + { + ClearOrigin: null, + }, + ], + }; + + // Perform the dry run XCM call + const result = await api.call.dryRunApi.dryRunXcm(origin, message); + + // Use JSON.stringify for better output formatting + console.log( + 'Dry run XCM result:', + JSON.stringify(result.toJSON(), null, 2) + ); + + // Disconnect the API + await api.disconnect(); + console.log('Disconnected from the API.'); + } catch (error) { + console.error('An error occurred:', error); + } +}; + +main().catch(console.error); diff --git a/builders/interoperability/xcm/core-concepts/multilocations.md b/builders/interoperability/xcm/core-concepts/multilocations.md index 1e53bdafd..6725083dc 100644 --- a/builders/interoperability/xcm/core-concepts/multilocations.md +++ b/builders/interoperability/xcm/core-concepts/multilocations.md @@ -357,3 +357,29 @@ To target another parachain (for example, a parachain that has an ID of 1234) fr }, }; ``` + +### Location to Account API {: #location-to-account-api } + +The Location to Account API is an easy way to convert a multilocation into an `AccountID20` address. The Location to Account API can be accessed from the [Runtime Calls](https://polkadot.js.org/apps/#/runtime){target=\_blank} tab of the **Developer** section of Polkadot.js Apps. The `convertLocation` method of the Location to Account API takes a multilocation as a parameter and returns an `AccountID20` address. + +```javascript +// Query the locationToAccountApi using convertLocation method +const result = + await api.call.locationToAccountApi.convertLocation(multilocation); +console.log('Conversion result:', result.toHuman()); +``` + +You can view the complete script below. + +??? code "View the complete script" + + ```js + --8<-- 'code/builders/interoperability/xcm/core-concepts/location-to-account.js' + ``` + +The method will return the `AccountID20` address corresponding to the provided multilocation as follows: + +```bash +Conversion result: { Ok: '0x506172656E740000000000000000000000000000' } +``` + diff --git a/builders/interoperability/xcm/send-execute-xcm.md b/builders/interoperability/xcm/send-execute-xcm.md index 8484b0e95..d5e3a840c 100644 --- a/builders/interoperability/xcm/send-execute-xcm.md +++ b/builders/interoperability/xcm/send-execute-xcm.md @@ -180,6 +180,75 @@ Now that you have the values for each of the parameters, you can write the scrip Once the transaction is processed, the 0.1 DEV tokens should be withdrawn from Alice's account along with the associated XCM fees, and the destination account should have received 0.1 DEV tokens in their account. A `polkadotXcm.Attempted` event will be emitted with the outcome. + +### Test an XCM Message with the XCM Dry Run API {: #test-an-xcm-message-with-the-dry-run-api } + +The XCM Dry Run API is an easy and convenient way to test the integrity of your XCM message without incurring any transaction fees. The XCM Dry Run API can be accessed from the [Runtime Calls](https://polkadot.js.org/apps/#/runtime){target=\_blank} tab of the **Developer** section of Polkadot.js Apps. + +#### Dry Run Call API Method {: #dry-run-call-api-method } + +This method takes as a parameter the origin and the call data and returns an execution result, actual weight, and event data. + +```javascript +const testAccount = api.createType( + 'AccountId20', + '0x88bcE0b038eFFa09e58fE6d24fDe4b5Af21aa798' +); +const callData = + '0x1c030408000400010403001300008a5d784563010d010204000103003cd0a705a2dc65e5b1e1205896baa2be8a07c6e007803822b001ba2e0100'; +const callDataU8a = hexToU8a(callData); + +const result = await api.call.dryRunApi.dryRunCall( + { system: { Signed: testAccount } }, + callDataU8a +); +``` + +??? code "View the complete script" + + ```js + --8<-- 'code/builders/interoperability/xcm/send-execute-xcm/dry-run/dry-run-call.js' + ``` + +Upon calling the XCM Dry Run API, the method will tell you whether the call would be successful and returns the event data that would be emitted if the XCM were to be actually submitted on chain. You can view the initial output of the `dryRunCall` below. + +??? code "View the complete output" + + ```json + --8<-- 'code/builders/interoperability/xcm/send-execute-xcm/dry-run/dry-run-call-return-data.json' + ``` + +#### Dry Run XCM API Method {: #dry-run-xcm-api-method } + +The `dryRunXCM` method of the XCM Dry Run API takes a full XCM message as a parameter instead of an encoded call, as well as the origin of the message. + +`dryRunXCM` takes as a parameter the origin and the XCM message and returns an execution result, actual weight, and event data. + +```javascript +// Define the origin +const origin = { V4: { parents: 1, interior: 'Here' } }; + +const message = []; // Insert XCM Message Here + +// Perform the dry run XCM call +const result = await api.call.dryRunApi.dryRunXcm(origin, message); +``` + +??? code "View the complete script" + + ```js + --8<-- 'code/builders/interoperability/xcm/send-execute-xcm/dry-run/dry-run-xcm.js' + ``` + +Upon calling the XCM Dry Run API, the method will tell you whether the call would be successful and returns the event data that would be emitted if the XCM were to be actually submitted on chain. You can view the initial output of the `dryRunXCM` below. + +??? code "View the complete output" + + ```json + --8<-- 'code/builders/interoperability/xcm/send-execute-xcm/dry-run/dry-run-xcm-return-data.json' + ``` + + ### Execute an XCM Message with the XCM Utilities Precompile {: #execute-xcm-utils-precompile } In this section, you'll use the `xcmExecute` function of the [XCM Utilities Precompile](/builders/interoperability/xcm/xcm-utils/){target=\_blank}, which is only supported on Moonbase Alpha, to execute an XCM message locally. The XCM Utilities Precompile is located at the following address: