From 0c08cb2c6c54261201f6dac1a9ca60653f6870a2 Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Mon, 30 Sep 2024 16:43:00 -0700 Subject: [PATCH 01/64] rev --- .../xcm/xc-registration/.pages | 1 + .../xcm/xc-registration/assets.md | 53 ++----------------- .../xcm/xc-registration/manage.md | 18 +++++++ 3 files changed, 23 insertions(+), 49 deletions(-) create mode 100644 builders/interoperability/xcm/xc-registration/manage.md diff --git a/builders/interoperability/xcm/xc-registration/.pages b/builders/interoperability/xcm/xc-registration/.pages index 5841d2409..d0f4546f4 100644 --- a/builders/interoperability/xcm/xc-registration/.pages +++ b/builders/interoperability/xcm/xc-registration/.pages @@ -4,3 +4,4 @@ nav: - 'Forum Templates': 'forum-templates.md' - 'XC Channel Registration': 'xc-integration.md' - 'XC Asset Registration': 'assets.md' + - 'XC Asset Management' : 'manage.md' diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index 682d9fd7f..fd73a71e1 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -39,66 +39,21 @@ To create a forum post on the [Moonbeam Community Forum](https://forum.moonbeam. ### Create a Proposal to Register an Asset {: #create-a-proposal } -To register an asset native to another chain on Moonbeam, you'll need to submit a governance proposal that will call the `assetManager.registerForeignAsset` extrinsic. Additionally, you'll need to set the asset's units per second value through the `assetManager.setAssetUnitsPerSecond` extrinsic. The units per second value is the units of tokens to charge per second of execution time during XCM transfers. How to calculate the units per second will be covered in the following section. +To register an asset native to another chain on Moonbeam, you'll need to submit a governance proposal that will call the `evmForeignAssets.createForeignAsset` extrinsic. Additionally, you'll need to register the asset's price (formerly known as units per second) through the `xcmWeightTrader.addAsset` extrinsic so that XCM fees can be properly calculated. An existing asset's price can be updated with `xcmWeightTrader.editAsset`. To get started, you'll need to collect some information about the asset: -- The ID of the parachain the asset lives on +- `assetId`: an arbitrary unique integer +- `xcmLocation`: a scale encoded xcm v4 multilocation of asset reserve relative to Moonbeam - The metadata of the asset. This includes: - The asset name - The asset symbol. You'll need to prepend "xc" to the asset symbol to indicate that the asset is an XCM-enabled asset - The number of decimals the asset has - - The units per second -- The multilocation of the asset as seen from Moonbeam -With this information in hand, you can get the encoded calldata for both calls and batch the calldata into a single transaction. From there, you can start the governance process, which includes using the calldata to submit a preimage and then using the preimage to create a proposal. If you're also opening a channel at the same time, you can add the channel-related calldata to the batch asset registration calldata and open a single proposal for everything. Asset and channel registration proposals on Moonbeam should be assigned to the General Admin Track. +With this information in hand, you can prepare a governance proposal to register a foreign asset. The allowed origins that permit registration of a foreign asset are `FastGeneralAdmin`, `OpenTechCommittee` or `Root`. ![Overview of the proposal process](/images/builders/interoperability/xcm/xc-registration/assets/assets-3.webp) -### Calculate the Asset's Units Per Second {: #calculate-units-per-second } - -Units per second is the number of tokens charged per second of execution of an XCM message. The target cost for an XCM transfer is $0.02 at the time of registration. The units per second might get updated through governance as the token price fluctuates. - -The easiest way to calculate an asset's units per second is through the [`calculate-units-per-second.ts` script](https://github.com/Moonsong-Labs/xcm-tools/blob/main/scripts/calculate-units-per-second.ts){target=\_blank} in the [xcm-tools](https://github.com/Moonsong-Labs/xcm-tools){target=\_blank} repository. The script accepts the following arguments: - -- `--decimals` or `--d` - decimals of the tokens you are calculating the units per second for -- `--xcm-weight-cost` or `--xwc` - total weight cost of the execution of the entire XCM message. The estimated weight per XCM operation on each Moonbeam chain is: - - === "Moonbeam" - - ```text - 800000000 - ``` - - === "Moonriver" - - ```text - 800000000 - ``` - - === "Moonbase Alpha" - - ```text - 638978000 - ``` - -- `--target` or `--t` - (optional) target price for XCM execution, defaults to `$0.02` -- `--asset` or `--a` - (optional) the token [Coingecko API ID](https://www.coingecko.com){target=\_blank} -- `--price` or `--p` - (optional) if the Coingecko API does not support the token, you can specify the price manually - -For example, to calculate the units per second of DOT (Polkadot token), which has 10 decimals, on Moonbeam, you can run: - -```bash -yarn calculate-units-per-second --d 10 --a polkadot --xwc 800000000 -``` - -Which should result in the following output (at the time of writing): - -```text -Token Price is $7.33 -The UnitsPerSecond needs to be set 34106412005 -``` - ### Generate the Encoded Calldata for the Asset Registration {: #generate-encoded-calldata-for-asset-registration } If you're not familiar with the governance system on Moonbeam, you can find out more information on the [Governance on Moonbeam](/learn/features/governance/){target=\_blank} page. With any governance proposal on Moonbeam, you'll need to submit a preimage, which defines the actions to be executed, and then use the preimage to submit a proposal. diff --git a/builders/interoperability/xcm/xc-registration/manage.md b/builders/interoperability/xcm/xc-registration/manage.md new file mode 100644 index 000000000..9684a6f44 --- /dev/null +++ b/builders/interoperability/xcm/xc-registration/manage.md @@ -0,0 +1,18 @@ +--- +title: Manage XC Assets +description: This guide includes everything you need to know about updating XC asset details, such as XCM multilocation details and asset price for fee data. +--- + +# Managing XC Assets + +## Introduction {: #introduction } + +After completing the [registration process](/builders/interoperability/xcm/xc-registration/assets/) for an XC asset, you may need to periodically update asset details, such as the XCM multilocation details or asset price. This guide will cover these topics and more. + +## Updating Foreign Asset XCM Location {: #updating-foreign-asset-xcm-location } + +You can update the multilocation of an asset with the `evmForeignAssets.changeXcmLocation` call, which takes as parameters, the `assetId` and the new multilocation. You'll need to raise a [governance proposal](/tokens/governance/proposals/) and submit the update under the `FastGeneralAdmin` track. If you're testing in Moonbase Alpha, you can optionally ask the Moonbeam Team to submit the extrinsic using Sudo to speed up the process. You can also submit the requisite governance proposal on Moonbase Alpha. + +## Freezing a Foreign Asset {: #freezing-a--foreign-asset } + +You can freeze a foreign asset by calling `evmForeignAssets.freezeForeignAsset`, which takes as parameters the `assetId` and an `allowXcmDeposit` boolean. If set to true, XCM deposits from remote chains will still be allowed and mint tokens. If set to false, XCM deposits from remote chains will fail as no minting will be permitted. \ No newline at end of file From 6e8beb0876b70ed6518ba009d395610d943e5c1b Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Tue, 22 Oct 2024 17:27:30 -0700 Subject: [PATCH 02/64] rev --- builders/interoperability/xcm/xc-registration/assets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index ca34aace9..cceb83d73 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -43,7 +43,7 @@ To register an asset native to another chain on Moonbeam, you'll need to submit To get started, you'll need to collect some information about the asset: -- `assetId`: an arbitrary unique integer +- `assetId`: unique identifier of the asset - `xcmLocation`: a scale encoded xcm v4 multilocation of asset reserve relative to Moonbeam - The metadata of the asset. This includes: - The asset name From 3e0c6593a0b5bfdf10590d0b39411e43e280633b Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Tue, 22 Oct 2024 17:27:58 -0700 Subject: [PATCH 03/64] rev --- builders/interoperability/xcm/xc-registration/assets.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index cceb83d73..37e3683b9 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -45,10 +45,9 @@ To get started, you'll need to collect some information about the asset: - `assetId`: unique identifier of the asset - `xcmLocation`: a scale encoded xcm v4 multilocation of asset reserve relative to Moonbeam -- The metadata of the asset. This includes: - - The asset name - - The asset symbol. You'll need to prepend "xc" to the asset symbol to indicate that the asset is an XCM-enabled asset - - The number of decimals the asset has +- The asset name +- The asset symbol. You'll need to prepend "xc" to the asset symbol to indicate that the asset is an XCM-enabled asset +- The number of decimals the asset has With this information in hand, you can prepare a governance proposal to register a foreign asset. The allowed origins that permit registration of a foreign asset are `FastGeneralAdmin`, `OpenTechCommittee` or `Root`. From 446028da80b9f5320943e2ef9f0ff47a519eb7a4 Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Tue, 22 Oct 2024 19:13:08 -0700 Subject: [PATCH 04/64] rev --- .../assets/create-foreign-asset.js | 56 +++++++++++++++++++ .../assets/terminal/createForeignAsset.md | 4 ++ .../xcm/xc-registration/assets.md | 49 ++++++++-------- 3 files changed, 82 insertions(+), 27 deletions(-) create mode 100644 .snippets/code/builders/interoperability/xcm/xc-registration/assets/create-foreign-asset.js create mode 100644 .snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/createForeignAsset.md diff --git a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/create-foreign-asset.js b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/create-foreign-asset.js new file mode 100644 index 000000000..6595bff08 --- /dev/null +++ b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/create-foreign-asset.js @@ -0,0 +1,56 @@ +import { ApiPromise, WsProvider } from '@polkadot/api'; +import { encodeAddress } from '@polkadot/util-crypto'; +import { u8aToHex } from '@polkadot/util'; + +async function getEncodedCallData() { + // Connect to Moonbase Alpha + const provider = new WsProvider('wss://moonbase-alpha.public.blastapi.io'); + const api = await ApiPromise.create({ provider }); + + // Example parameters with correct types + const assetId = '340282366920938463463374607431768211455'; + + // XCM V4 Multilocation structured according to Moonbeam's format + const xcmLocation = { + parents: 1, + interior: { + X1: [ + { Parachain: 888 } // Replace with actual parachain ID + ] + } + }; + + // Convert strings to Uint8Array for Bytes type + const assetName = Array.from(Buffer.from('My Foreign Asset')); + const assetSymbol = Array.from(Buffer.from('xcMFA')); + + // Decimals as a number (not string) + const decimals = 18; + + try { + // Create the call + const call = api.tx.evmForeignAssets.createForeignAsset( + assetId, + xcmLocation, + decimals, + assetSymbol, + assetName + ); + + // Get the encoded call data + const encodedData = call.method.toHex(); + console.log('Encoded Call Data:', encodedData); + + await api.disconnect(); + return encodedData; + } catch (error) { + console.error('Error details:', error); + await api.disconnect(); + throw error; + } +} + +// Execute the function +getEncodedCallData() + .catch(console.error) + .finally(() => process.exit()); \ No newline at end of file diff --git a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/createForeignAsset.md b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/createForeignAsset.md new file mode 100644 index 000000000..37975b308 --- /dev/null +++ b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/createForeignAsset.md @@ -0,0 +1,4 @@ +
+ node createForeignAsset.js + Encoded Call Data: 0x3800ffffffffffffffffffffffffffffffff010100e10d121478634d4641404d7920466f726569676e204173736574 +
diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index 37e3683b9..6221e5e33 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -49,46 +49,41 @@ To get started, you'll need to collect some information about the asset: - The asset symbol. You'll need to prepend "xc" to the asset symbol to indicate that the asset is an XCM-enabled asset - The number of decimals the asset has -With this information in hand, you can prepare a governance proposal to register a foreign asset. The allowed origins that permit registration of a foreign asset are `FastGeneralAdmin`, `OpenTechCommittee` or `Root`. +You can use the below script to generate the encoded call data for the `createForeignAsset` call. Remember to replace the example parameter values shown in the script with the ones relevant to your asset. -![Overview of the proposal process](/images/builders/interoperability/xcm/xc-registration/assets/assets-3.webp) - -### Generate the Encoded Calldata for the Asset Registration {: #generate-encoded-calldata-for-asset-registration } +???+ code "Get encoded call data for createForeignAsset" + ```typescript + --8<-- 'code/builders/interoperability/xcm/xc-registration/assets/create-foreign-asset.js' + ``` -If you're not familiar with the governance system on Moonbeam, you can find out more information on the [Governance on Moonbeam](/learn/features/governance/){target=\_blank} page. With any governance proposal on Moonbeam, you'll need to submit a preimage, which defines the actions to be executed, and then use the preimage to submit a proposal. +The resulting output will be something like: -To submit a preimage, you'll need to get the encoded calldata for each extrinsic that you want to execute. As previously mentioned, you'll use the `assetManager.registerForeignAsset`, and optionally, the `assetManager.setAssetUnitsPerSecond`, and `system.setStorage` extrinsics. +--8<-- 'code/builders/interoperability/xcm/xc-registration/assets/terminal/createForeignAsset.md' -You can use the [`xcm-asset-registrator.ts` script](https://github.com/Moonsong-Labs/xcm-tools/blob/main/scripts/xcm-asset-registrator.ts){target=\_blank} to calculate the encoded calldata and even submit the preimage and proposal if you desire. Proposals must be submitted via the General Admin Track. If you're registering an asset and opening a channel, you'll want to wait to submit the preimage and proposal until you have the calldata for the channel-related calls. +With this information in hand, you can prepare a governance proposal to register a foreign asset. Foreign asset registration proposals should be submitted through the `FastGeneralAdmin` track. -To get the encoded calldata for the `assetManager.registerForeignAsset` extrinsic, you can use the following arguments: +![Overview of the proposal process](/images/builders/interoperability/xcm/xc-registration/assets/assets-3.webp) -- `--ws-provider` or `--w` - the WebSocket provider to be used for the requests. The WSS network endpoints for each Moonbeam-based network are as follows: +### Generate the Encoded Calldata for the Asset Registration {: #generate-encoded-calldata-for-asset-registration } - === "Moonbeam" +If you're not familiar with the governance system on Moonbeam, you can find out more information on the [Governance on Moonbeam](/learn/features/governance/){target=\_blank} page. With any governance proposal on Moonbeam, you'll need to submit a preimage, which defines the actions to be executed, and then use the preimage to submit a proposal. - ```text - wss://wss.api.moonbeam.network - ``` +To submit a preimage, you'll need to get the encoded calldata for each extrinsic that you want to execute. As previously mentioned, you'll use the `evmForeignAssets.createForeignAsset` and the `xcmWeightTrader.addAsset` extrinsics. - === "Moonriver" +Proposals must be submitted via the `FastGeneralAdmin` track. If you're opening a channel and registering an asset and you'll want to wait until the channel is established prior to attempting to register the asset. - ```text - wss://wss.api.moonriver.moonbeam.network - ``` +To get the encoded calldata for the `evmForeignAssets.createForeignAsset` extrinsic, you will need to provide the following arguments: - === "Moonbase Alpha" +- `assetId` - unique identifier of the asset +- `xcmLocation` - the multilocation of the asset relative to Moonbeam +- `decimals` - the number of decimals of the asset +- `symbol` - the symbol of the asset. **Remember that "xc" should be prepended to the symbol to indicate the asset is an XCM-enabled asset** +- `name` - The asset name - ```text - {{ networks.moonbase.wss_url }} - ``` +To get the encoded calldata for the `xcmWeightTrader.addAsset` extrinsic, you will need to provide the following arguments: -- `--asset` or `--a` - the multilocation of the asset -- `--name` or `--n` - the name of the asset -- `--symbol` or `--sym` - the symbol of the asset. **Remember that "xc" should be prepended to the symbol to indicate the asset is an XCM-enabled asset** -- `--decimals` or `--d` - the number of decimals of the asset -- `--existential-deposit` or `--ed` - (optional) - the existential deposit of the registered asset. This should always be set to `1` -- `--sufficient` or `--suf` - (optional) - the sufficiency, which dictates whether an asset can be sent to an account without a native token balance. This should always be set to `true` +- `xcmLocation` - the multilocation of the asset relative to Moonbeam +- `relativePrice` - the the cost of an asset in terms of weight, used to determine how much of the asset is required to cover the fees for cross-chain (XCM) operations. It is calculated by comparing the asset's value to the network's native token in terms of the weight-to-fee conversion To create a batch transaction that also sets the units per second or revert code of the asset's precompile in addition to the asset registration, you can choose to add these arguments: From e24eac76cd328a2ae83e4cfff00ab22ca1199443 Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Tue, 22 Oct 2024 19:57:55 -0700 Subject: [PATCH 05/64] rev --- .../xcm/xc-registration/assets/batch-calls.js | 69 +++++++++++ .../xc-registration/assets/submit-preimage.js | 83 +++++++++++++ .../assets/terminal/batchCall.md | 8 ++ .../assets/terminal/submitPreimage.md | 12 ++ .../assets/terminal/weightTrader.md | 4 + .../xc-registration/assets/weight-trader.js | 47 ++++++++ .../xcm/xc-registration/assets.md | 112 ++++++------------ 7 files changed, 256 insertions(+), 79 deletions(-) create mode 100644 .snippets/code/builders/interoperability/xcm/xc-registration/assets/batch-calls.js create mode 100644 .snippets/code/builders/interoperability/xcm/xc-registration/assets/submit-preimage.js create mode 100644 .snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/batchCall.md create mode 100644 .snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/submitPreimage.md create mode 100644 .snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/weightTrader.md create mode 100644 .snippets/code/builders/interoperability/xcm/xc-registration/assets/weight-trader.js diff --git a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/batch-calls.js b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/batch-calls.js new file mode 100644 index 000000000..042a8ad22 --- /dev/null +++ b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/batch-calls.js @@ -0,0 +1,69 @@ +import { ApiPromise, WsProvider } from '@polkadot/api'; +import { encodeAddress } from '@polkadot/util-crypto'; +import { u8aToHex } from '@polkadot/util'; + +async function getEncodedBatchCallData() { + // Connect to Moonbase Alpha + const provider = new WsProvider('wss://moonbase-alpha.public.blastapi.io'); + const api = await ApiPromise.create({ provider }); + + try { + // Parameters for createForeignAsset + const assetId = '340282366920938463463374607431768211455'; + const xcmLocation = { + parents: 1, + interior: { + X1: [ + { Parachain: 888 } + ] + } + }; + const assetName = Array.from(Buffer.from('My Foreign Asset')); + const assetSymbol = Array.from(Buffer.from('xcMFA')); + const decimals = 18; + + // Parameters for xcmWeightTrader.addAsset + const relativePrice = '5000'; + + // Create individual calls + const createAssetCall = api.tx.evmForeignAssets.createForeignAsset( + assetId, + xcmLocation, + decimals, + assetSymbol, + assetName + ); + + const addAssetCall = api.tx.xcmWeightTrader.addAsset( + xcmLocation, + relativePrice + ); + + // Combine calls into a batch + const batchCall = api.tx.utility.batch([ + createAssetCall, + addAssetCall + ]); + + // Get the encoded call data for the batch + const encodedBatchData = batchCall.method.toHex(); + + console.log('Individual Calls:'); + console.log('Create Asset Call:', createAssetCall.method.toHex()); + console.log('Add Asset Call:', addAssetCall.method.toHex()); + console.log('\nBatch Call:'); + console.log('Encoded Batch Call Data:', encodedBatchData); + + await api.disconnect(); + return encodedBatchData; + } catch (error) { + console.error('Error details:', error); + await api.disconnect(); + throw error; + } +} + +// Execute the function +getEncodedBatchCallData() + .catch(console.error) + .finally(() => process.exit()); \ No newline at end of file diff --git a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/submit-preimage.js b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/submit-preimage.js new file mode 100644 index 000000000..8f45ebc39 --- /dev/null +++ b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/submit-preimage.js @@ -0,0 +1,83 @@ +import { ApiPromise, WsProvider } from '@polkadot/api'; +import { Keyring } from '@polkadot/keyring'; +import { cryptoWaitReady } from '@polkadot/util-crypto'; +import { u8aToHex } from '@polkadot/util'; + +async function submitPreimage() { + // Wait for the crypto libraries to be ready + await cryptoWaitReady(); + + // Connect to Moonbase Alpha + const provider = new WsProvider('wss://moonbase-alpha.public.blastapi.io'); + const api = await ApiPromise.create({ provider }); + + // Initialize keyring and add account + const keyring = new Keyring({ type: 'ethereum' }); // Use ethereum type for Moonbeam + + // IMPORTANT: Replace with your private key + const PRIVATE_KEY = 'INSERT-PRIVATE-KEY'; // e.g., '0x1234...' + const account = keyring.addFromUri(PRIVATE_KEY); + + console.log('Account address:', account.address); + + // The encoded call data to be submitted as preimage + const encodedCallData = '0x0100083800ffffffffffffffffffffffffffffffff010100e10d121478634d4641404d7920466f726569676e2041737365743a00010100e10d88130000000000000000000000000000'; + + try { + // Create the notePreimage call + const preimageCall = api.tx.preimage.notePreimage(encodedCallData); + + // Calculate the hash of the preimage + const preimageHash = await api.registry.hash(encodedCallData); + + console.log('Submitting preimage for encoded call data:'); + console.log('Original Call Data:', encodedCallData); + console.log('Note Preimage Encoded Call:', preimageCall.method.toHex()); + console.log('Preimage Hash:', preimageHash.toHex()); + + // Get the account's current nonce + const nonce = await api.rpc.system.accountNextIndex(account.address); + + // Submit and wait for transaction + const txHash = await new Promise((resolve, reject) => { + preimageCall.signAndSend(account, { nonce }, ({ status, dispatchError, events }) => { + if (dispatchError) { + if (dispatchError.isModule) { + // Handle module error + const decoded = api.registry.findMetaError(dispatchError.asModule); + const { docs, name, section } = decoded; + reject(new Error(`${section}.${name}: ${docs.join(' ')}`)); + } else { + // Handle other errors + reject(new Error(dispatchError.toString())); + } + } + + if (status.isInBlock) { + console.log(`Transaction included in blockHash ${status.asInBlock}`); + } else if (status.isFinalized) { + console.log(`Transaction finalized in blockHash ${status.asFinalized}`); + resolve(status.asFinalized); + } + }).catch(reject); + }); + + console.log('Transaction successful! Hash:', txHash.toHex()); + console.log('Preimage hash (save this for reference):', preimageHash.toHex()); + + await api.disconnect(); + return { + transactionHash: txHash.toHex(), + preimageHash: preimageHash.toHex() + }; + } catch (error) { + console.error('Error details:', error); + await api.disconnect(); + throw error; + } +} + +// Execute the function +submitPreimage() + .catch(console.error) + .finally(() => process.exit()); \ No newline at end of file diff --git a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/batchCall.md b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/batchCall.md new file mode 100644 index 000000000..3c3073abc --- /dev/null +++ b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/batchCall.md @@ -0,0 +1,8 @@ +
+ node batch-calls.js + Individual Calls: + Create Asset Call: 0x3800ffffffffffffffffffffffffffffffff010100e10d121478634d4641404d7920466f726569676e204173736574 + Add Asset Call: 0x3a00010100e10d88130000000000000000000000000000 + Batch Call: + Encoded Batch Call Data: 0x0100083800ffffffffffffffffffffffffffffffff010100e10d121478634d4641404d7920466f726569676e2041737365743a00010100e10d88130000000000000000000000000000 +
\ No newline at end of file diff --git a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/submitPreimage.md b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/submitPreimage.md new file mode 100644 index 000000000..2d7670bcb --- /dev/null +++ b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/submitPreimage.md @@ -0,0 +1,12 @@ +
+ node submit-preimage.js + Account address: 0x569BE8d8b04538318e1722f6e375FD381D2da865 + Submitting preimage for encoded call data: + Original Call Data: 0x0100083800ffffffffffffffffffffffffffffffff010100e10d121478634d4641404d7920466f726569676e2041737365743a00010100e10d88130000000000000000000000000000 + Note Preimage Encoded Call: 0x2c0025010100083800ffffffffffffffffffffffffffffffff010100e10d121478634d4641404d7920466f726569676e2041737365743a00010100e10d88130000000000000000000000000000 + Preimage Hash: 0x2ac24641cebeff3827ba10eb264d2db2990607c89a3fa2c8b2fef6b1e37e35e3 + Transaction included in blockHash 0xf84ef0d3238cbc656e482494778acc9d849f14b5173d34c727a720aee48a6e69 + Transaction finalized in blockHash 0xf84ef0d3238cbc656e482494778acc9d849f14b5173d34c727a720aee48a6e69 + Transaction successful! Hash: 0xf84ef0d3238cbc656e482494778acc9d849f14b5173d34c727a720aee48a6e69 + Preimage hash (save this for reference): 0x2ac24641cebeff3827ba10eb264d2db2990607c89a3fa2c8b2fef6b1e37e35e3 +
\ No newline at end of file diff --git a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/weightTrader.md b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/weightTrader.md new file mode 100644 index 000000000..f75b367d5 --- /dev/null +++ b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/weightTrader.md @@ -0,0 +1,4 @@ +
+ node xcmWeightTrader.js + Encoded Call Data: 0x3a00010100e10d88130000000000000000000000000000 +
diff --git a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/weight-trader.js b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/weight-trader.js new file mode 100644 index 000000000..98a6595a3 --- /dev/null +++ b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/weight-trader.js @@ -0,0 +1,47 @@ +import { ApiPromise, WsProvider } from '@polkadot/api'; +import { encodeAddress } from '@polkadot/util-crypto'; +import { u8aToHex } from '@polkadot/util'; + +async function getEncodedCallData() { + // Connect to Moonbase Alpha + const provider = new WsProvider('wss://moonbase-alpha.public.blastapi.io'); + const api = await ApiPromise.create({ provider }); + + // Corrected XCM V4 Multilocation structure + const xcmLocation = { + parents: 1, + interior: { + X1: [ + { Parachain: 888 } + ] + } + }; + + // Relative price as u128 + const relativePrice = '5000'; + + try { + // Create the call + const call = api.tx.xcmWeightTrader.addAsset( + xcmLocation, + relativePrice + ); + + // Get the encoded call data + const encodedData = call.method.toHex(); + console.log('Encoded Call Data:', encodedData); + + await api.disconnect(); + return encodedData; + } catch (error) { + console.error('Error details:', error); + console.error('Attempted XCM Location:', JSON.stringify(xcmLocation, null, 2)); + await api.disconnect(); + throw error; + } +} + +// Execute the function +getEncodedCallData() + .catch(console.error) + .finally(() => process.exit()); \ No newline at end of file diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index 6221e5e33..ebddee916 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -49,17 +49,6 @@ To get started, you'll need to collect some information about the asset: - The asset symbol. You'll need to prepend "xc" to the asset symbol to indicate that the asset is an XCM-enabled asset - The number of decimals the asset has -You can use the below script to generate the encoded call data for the `createForeignAsset` call. Remember to replace the example parameter values shown in the script with the ones relevant to your asset. - -???+ code "Get encoded call data for createForeignAsset" - ```typescript - --8<-- 'code/builders/interoperability/xcm/xc-registration/assets/create-foreign-asset.js' - ``` - -The resulting output will be something like: - ---8<-- 'code/builders/interoperability/xcm/xc-registration/assets/terminal/createForeignAsset.md' - With this information in hand, you can prepare a governance proposal to register a foreign asset. Foreign asset registration proposals should be submitted through the `FastGeneralAdmin` track. ![Overview of the proposal process](/images/builders/interoperability/xcm/xc-registration/assets/assets-3.webp) @@ -80,93 +69,58 @@ To get the encoded calldata for the `evmForeignAssets.createForeignAsset` extrin - `symbol` - the symbol of the asset. **Remember that "xc" should be prepended to the symbol to indicate the asset is an XCM-enabled asset** - `name` - The asset name -To get the encoded calldata for the `xcmWeightTrader.addAsset` extrinsic, you will need to provide the following arguments: +You can use the below script to generate the encoded call data for the `createForeignAsset` call. Remember to replace the example parameter values shown in the script with the ones relevant to your asset. -- `xcmLocation` - the multilocation of the asset relative to Moonbeam -- `relativePrice` - the the cost of an asset in terms of weight, used to determine how much of the asset is required to cover the fees for cross-chain (XCM) operations. It is calculated by comparing the asset's value to the network's native token in terms of the weight-to-fee conversion +???+ code "Get encoded call data for createForeignAsset" + ```typescript + --8<-- 'code/builders/interoperability/xcm/xc-registration/assets/create-foreign-asset.js' + ``` -To create a batch transaction that also sets the units per second or revert code of the asset's precompile in addition to the asset registration, you can choose to add these arguments: +The resulting output will be something like: -- `--units-per-second` or `--u` - (optional) - the units per second, which specifies the amount to charge per second of execution in the registered asset. You should have calculated this value in the [previous section](#calculate-units-per-second). If this is provided, the script will create a batch transaction for the governance proposal that, at a minimum, will register the asset and set the units per second on-chain -- `--revert-code` or `--revert` - (optional) - registers the revert code for the asset's precompile in the EVM. If this is provided, the script will create a batch transaction for the governance proposal that, at a minimum, will register the asset and set the revert code. +--8<-- 'code/builders/interoperability/xcm/xc-registration/assets/terminal/createForeignAsset.md' - !!! note - **This flag is not necessary for proposals on Moonbeam** as it includes a `system.setStorage` call that the [OpenGov](/learn/features/governance/#opengov) General Admin Origin can't execute. The dummy EVM bytecode can be set later with a call to the [Precompile Registry precompile](/builders/ethereum/precompiles/utility/registry/){target=\_blank}, which means that you don't need to worry about going through governance to set the revert code! Please check out the [Set XC-20 Precompile Bytecode](#set-bytecode) section to learn how to set the dummy bytecode. +To get the encoded calldata for the `xcmWeightTrader.addAsset` extrinsic, you will need to provide the following arguments: -As a practical example, the following command would generate the encoded calldata to register an asset from parachain 888 that has a general key of `1`: +- `xcmLocation` - the multilocation of the asset relative to Moonbeam +- `relativePrice` - the the cost of an asset in terms of weight, used to determine how much of the asset is required to cover the fees for cross-chain (XCM) operations. It is calculated by comparing the asset's value to the network's native token in terms of the weight-to-fee conversion -```bash -yarn register-asset -w wss://wss.api.moonbase.moonbeam.network \ ---asset '{ "parents": 1, "interior": { "X2": [{ "Parachain": 888 }, {"GeneralKey": "0x000000000000000001"}]}}' \ ---symbol "xcEXTN" --decimals 18 \ ---name "Example Token" \ ---units-per-second 20070165297881393351 \ ---ed 1 --sufficient true -``` +You can use the below script to generate the encoded call data for the `addAsset` call. Remember to replace the example parameter values shown in the script with the ones relevant to your asset. -Its output would look like the following: +??? code "Get encoded call data for xcmWeightTrader" + ```typescript + --8<-- 'code/builders/interoperability/xcm/xc-registration/assets/weight-trader.js' + ``` -```text -Encoded proposal for registerAsset is 0x1f0000010200e10d0624000000000000000001344578616d706c6520546f6b656e1878634558544e12000000000000000000000000000000000000 -Encoded proposal for setAssetUnitsPerSecond is 0x1f0100010200e10d0624000000000000000001c7a8978b008d8716010000000000000026000000 -Encoded calldata for tx is 0x0102081f0000010200e10d0624000000000000000001344578616d706c6520546f6b656e1878634558544e120000000000000000000000000000000000001f0100010200e10d0624000000000000000001c7a8978b008d8716010000000000000026000000 -``` +The resulting output will be something like: -### Programmatically Submit the Preimage and Proposal for Asset Registration {: #submit-preimage-proposal } +--8<-- 'code/builders/interoperability/xcm/xc-registration/assets/terminal/weightTrader.md' -The script provides the option to programmatically submit a preimage and democracy proposal for the asset registration if you pass in the following optional arguments: +To create a batch transaction that combines both the `xcmWeightTrader.addAsset` and the `evmForeignAssets.createForeignAsset` calls together, you can use the following script. Remember to replace the example parameter values shown in the script with the ones relevant to your asset. -- `--account-priv-key` or `--account` - (optional) - the private key of the account that will submit the preimage and proposal -- `--sudo` or `--x` - (optional) - wraps the transaction with `sudo.sudo`. This can be used for Moonbase Alpha, if you want to provide the SCALE encoded calldata to the team so that it is submitted via SUDO -- `--send-preimage-hash` or `--h` - (optional) - submits the preimage -- `--send-proposal-as` or `--s` - (optional) - specifies how the proposal should be sent. The following options are accepted: - - `democracy` - sends the proposal through regular democracy using Governance v1 - - `council-external` - sends the proposal as an external proposal that will be voted on by the council using Governance v1 - - `v2` - sends the proposal through OpenGov (Governance v2). This option should be used for Moonbeam. If you choose this option, you'll also need to use the `--track` argument to specify which [Track](/learn/features/governance/#general-definitions--general-definitions-gov2){target=\_blank} the proposal will go through and the `--delay` argument to specify the delay period (in blocks) after the proposal has passed and before the proposal is executed -- `--collectiveThreshold` or `--c` - (optional) - the number of council votes that are needed to approve the proposal. Defaults to `1` -- `--at-block` - (optional) - the block number at which the call should get executed -- `--track` - (optional) - the Track the proposal should go through for OpenGov proposals. For Moonbeam, the General Admin Origin should be used -- `--delay` - (optional) - the delay period (in blocks) after a proposal has passed and before it can be executed. Defaults to `100` blocks +??? code "Get encoded call data for batch call" + ```typescript + --8<-- 'code/builders/interoperability/xcm/xc-registration/assets/batch-calls.js' + ``` -Altogether, you can use the following command to submit a preimage and proposal using OpenGov, which batches the asset registration and sets the asset's units per second. +The resulting output will be something like: -=== "Moonbeam" +--8<-- 'code/builders/interoperability/xcm/xc-registration/assets/terminal/batchCall.md' - ```bash - yarn register-asset -w wss://wss.api.moonbeam.network \ - --asset 'INSERT_ASSET_MULTILOCATION' \ - --symbol "INSERT_TOKEN_SYMBOL" \ - --decimals INSERT_TOKEN_DECIMALS \ - --name "INSERT_TOKEN_NAME" \ - --units-per-second INSERT_UNITS_PER_SECOND \ - --existential-deposit 1 \ - --sufficient true \ - --account-priv-key "0x5fb92d6e98884f76de468fa3f6278f8807c48bebc13595d45af5bdc4da702133" \ - --send-preimage-hash true \ - --send-proposal-as v2 - --track '{ "Origins": "GeneralAdmin" }' - ``` +### Programmatically Submit the Preimage and Proposal for Asset Registration {: #submit-preimage-proposal } -=== "Moonriver" +You can programmatically submit the preimage of your batched call containing both the `xcmWeightTrader.addAsset` and the `evmForeignAssets.createForeignAsset` calls as shown in the following script. As this is an on-chain transaction, you'll need to provide a wallet. (Never store your private keys in a javascript file - this is provided for demonstration purposes only). Remember to replace the encoded call data with the respective relevant batch call for your asset. You can also adapt this script for a different network. - ```bash - yarn register-asset -w wss://wss.api.moonriver.moonbeam.network \ - --asset 'INSERT_ASSET_MULTILOCATION' \ - --symbol "INSERT_TOKEN_SYMBOL" \ - --decimals INSERT_TOKEN_DECIMALS \ - --name "INSERT_TOKEN_NAME" \ - --units-per-second INSERT_UNITS_PER_SECOND \ - --existential-deposit 1 \ - --sufficient true \ - --account-priv-key "0x5fb92d6e98884f76de468fa3f6278f8807c48bebc13595d45af5bdc4da702133" \ - --send-preimage-hash true \ - --send-proposal-as v2 - --track '{ "Origins": "GeneralAdmin" }' +??? code "Submit preimage for batch call" + ```typescript + --8<-- 'code/builders/interoperability/xcm/xc-registration/assets/submit-preimage.js' ``` -For Moonbase Alpha, you will not need to go through governance. Instead, you can use the `--sudo` flag and provide the output to the Moonbeam team so that the asset and channel can be added quickly through sudo. +The resulting output will be something like: + +--8<-- 'code/builders/interoperability/xcm/xc-registration/assets/terminal/submitPreimage.md' -You can see additional [examples in the `README.md` of the xcm-tools repository](https://github.com/Moonsong-Labs/xcm-tools#example-to-note-pre-image-and-propose-through-opengov2-with-custom-track){target=\_blank}. +For Moonbase Alpha, you do not need to go through governance, as Moonbase Alpha has `sudo` access. Instead, you can provide the output of the batch call data to the Moonbeam team, and the Moonbeam Team can submit the call with `sudo`. This will be a faster and easier process than going thru governance, however, you may still wish to go through governance on Moonbase Alpha in order to prepare for the governance process on Moonbeam. ### Test the Asset Registration on Moonbeam {: #test-asset-registration } From 8e602182de1d84921a9202b9944959b3685395f7 Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Tue, 22 Oct 2024 20:00:33 -0700 Subject: [PATCH 06/64] rev --- .../xcm/xc-registration/.pages | 1 - .../xcm/xc-registration/assets.md | 12 ++++++++++++ .../xcm/xc-registration/manage.md | 18 ------------------ 3 files changed, 12 insertions(+), 19 deletions(-) delete mode 100644 builders/interoperability/xcm/xc-registration/manage.md diff --git a/builders/interoperability/xcm/xc-registration/.pages b/builders/interoperability/xcm/xc-registration/.pages index d0f4546f4..5841d2409 100644 --- a/builders/interoperability/xcm/xc-registration/.pages +++ b/builders/interoperability/xcm/xc-registration/.pages @@ -4,4 +4,3 @@ nav: - 'Forum Templates': 'forum-templates.md' - 'XC Channel Registration': 'xc-integration.md' - 'XC Asset Registration': 'assets.md' - - 'XC Asset Management' : 'manage.md' diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index ebddee916..51086c364 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -382,3 +382,15 @@ You can use the following multilocation to register a local XC-20: ``` Since local XC-20s are ERC-20s on Moonbeam, there are no deposits required to create an ERC-20 on Moonbeam. There may, however, be deposits required to register the asset on another parachain. Please consult with the parachain team you wish to register the asset with for more information. + +## Managing XC Assets + +After completing the [registration process](#introduction) for an XC asset, you may need to periodically update asset details, such as the XCM multilocation details or asset price. This guide will cover these topics and more. + +### Updating Foreign Asset XCM Location {: #updating-foreign-asset-xcm-location } + +You can update the multilocation of an asset with the `evmForeignAssets.changeXcmLocation` call, which takes as parameters, the `assetId` and the new multilocation. You'll need to raise a [governance proposal](/tokens/governance/proposals/) and submit the update under the `FastGeneralAdmin` track. If you're testing in Moonbase Alpha, you can optionally ask the Moonbeam Team to submit the extrinsic using Sudo to speed up the process. You can also submit the requisite governance proposal on Moonbase Alpha. + +### Freezing a Foreign Asset {: #freezing-a--foreign-asset } + +You can freeze a foreign asset by calling `evmForeignAssets.freezeForeignAsset`, which takes as parameters the `assetId` and an `allowXcmDeposit` boolean. If set to true, XCM deposits from remote chains will still be allowed and mint tokens. If set to false, XCM deposits from remote chains will fail as no minting will be permitted. \ No newline at end of file diff --git a/builders/interoperability/xcm/xc-registration/manage.md b/builders/interoperability/xcm/xc-registration/manage.md deleted file mode 100644 index 9684a6f44..000000000 --- a/builders/interoperability/xcm/xc-registration/manage.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -title: Manage XC Assets -description: This guide includes everything you need to know about updating XC asset details, such as XCM multilocation details and asset price for fee data. ---- - -# Managing XC Assets - -## Introduction {: #introduction } - -After completing the [registration process](/builders/interoperability/xcm/xc-registration/assets/) for an XC asset, you may need to periodically update asset details, such as the XCM multilocation details or asset price. This guide will cover these topics and more. - -## Updating Foreign Asset XCM Location {: #updating-foreign-asset-xcm-location } - -You can update the multilocation of an asset with the `evmForeignAssets.changeXcmLocation` call, which takes as parameters, the `assetId` and the new multilocation. You'll need to raise a [governance proposal](/tokens/governance/proposals/) and submit the update under the `FastGeneralAdmin` track. If you're testing in Moonbase Alpha, you can optionally ask the Moonbeam Team to submit the extrinsic using Sudo to speed up the process. You can also submit the requisite governance proposal on Moonbase Alpha. - -## Freezing a Foreign Asset {: #freezing-a--foreign-asset } - -You can freeze a foreign asset by calling `evmForeignAssets.freezeForeignAsset`, which takes as parameters the `assetId` and an `allowXcmDeposit` boolean. If set to true, XCM deposits from remote chains will still be allowed and mint tokens. If set to false, XCM deposits from remote chains will fail as no minting will be permitted. \ No newline at end of file From 563698ea5db5c50fdee52d8413726e11cda65a90 Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Tue, 22 Oct 2024 20:18:58 -0700 Subject: [PATCH 07/64] add --- .../xc-registration/assets/submit-proposal.js | 108 ++++++++++++++++++ .../assets/terminal/submitProposal.md | 14 +++ .../xcm/xc-registration/assets.md | 13 ++- 3 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 .snippets/code/builders/interoperability/xcm/xc-registration/assets/submit-proposal.js create mode 100644 .snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/submitProposal.md diff --git a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/submit-proposal.js b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/submit-proposal.js new file mode 100644 index 000000000..1652e02dc --- /dev/null +++ b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/submit-proposal.js @@ -0,0 +1,108 @@ +import { ApiPromise, WsProvider } from '@polkadot/api'; +import { Keyring } from '@polkadot/keyring'; +import { cryptoWaitReady } from '@polkadot/util-crypto'; + +async function submitReferendum() { + // Wait for the crypto libraries to be ready + await cryptoWaitReady(); + + // Connect to Moonbase Alpha + const provider = new WsProvider('wss://moonbase-alpha.public.blastapi.io'); + const api = await ApiPromise.create({ provider }); + + // Initialize keyring and add account + const keyring = new Keyring({ type: 'ethereum' }); + + // IMPORTANT: Replace with your private key + const PRIVATE_KEY = 'INSERT-PRIVATE-KEY'; + const account = keyring.addFromUri(PRIVATE_KEY); + + console.log('Account address:', account.address); + + try { + // Get current block number for enactment calculation + const currentBlock = await api.query.system.number(); + const enactmentBlock = currentBlock.toNumber() + 100; + + // The preimage data and hash + const preimageHash = '0x2ac24641cebeff3827ba10eb264d2db2990607c89a3fa2c8b2fef6b1e37e35e3'; + + // Length of the original batch call data + // This should match the length of your original encoded call data + const preimageLength = 73; // This is the length of your batch call encoded data + + // Parameters for the referendum + const origin = { Origins: 'FastGeneralAdmin' }; + const proposal = { + Lookup: { + hash: preimageHash, + len: preimageLength + } + }; + const enactment = { After: 100 }; + + // Create the referendum submission call + const referendumCall = api.tx.referenda.submit( + origin, + proposal, + enactment + ); + + // Get the encoded call data + const encodedCall = referendumCall.method.toHex(); + console.log('\nReferendum submission details:'); + console.log('Encoded Call:', encodedCall); + console.log('Current Block:', currentBlock.toString()); + console.log('Enactment Block:', enactmentBlock); + console.log('Preimage Hash:', preimageHash); + console.log('Preimage Length:', preimageLength); + + // Get the account's current nonce + const nonce = await api.rpc.system.accountNextIndex(account.address); + + // Submit and wait for transaction + const txHash = await new Promise((resolve, reject) => { + referendumCall.signAndSend(account, { nonce }, ({ status, dispatchError, events }) => { + if (dispatchError) { + if (dispatchError.isModule) { + const decoded = api.registry.findMetaError(dispatchError.asModule); + const { docs, name, section } = decoded; + reject(new Error(`${section}.${name}: ${docs.join(' ')}`)); + } else { + reject(new Error(dispatchError.toString())); + } + } + + if (status.isInBlock) { + console.log(`Transaction included in blockHash ${status.asInBlock}`); + // Try to find the referendum index from events + events.forEach(({ event }) => { + if (event.section === 'referenda' && event.method === 'Submitted') { + const [referendumIndex] = event.data; + console.log(`Referendum submitted with index: ${referendumIndex}`); + } + }); + } else if (status.isFinalized) { + console.log(`Transaction finalized in blockHash ${status.asFinalized}`); + resolve(status.asFinalized); + } + }).catch(reject); + }); + + console.log('Transaction successful! Hash:', txHash.toHex()); + + await api.disconnect(); + return { + transactionHash: txHash.toHex() + }; + } catch (error) { + console.error('Error details:', error); + await api.disconnect(); + throw error; + } +} + +// Execute the function +submitReferendum() + .catch(console.error) + .finally(() => process.exit()); \ No newline at end of file diff --git a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/submitProposal.md b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/submitProposal.md new file mode 100644 index 000000000..98a54cea5 --- /dev/null +++ b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/submitProposal.md @@ -0,0 +1,14 @@ +
+ node submit-referendum.js + Account address: 0x569BE8d8b04538318e1722f6e375FD381D2da865 + Referendum submission details: + Encoded Call: 0x2a002b04022ac24641cebeff3827ba10eb264d2db2990607c89a3fa2c8b2fef6b1e37e35e3490000000164000000 + Current Block: 9150304 + Enactment Block: 9150404 + Preimage Hash: 0x2ac24641cebeff3827ba10eb264d2db2990607c89a3fa2c8b2fef6b1e37e35e3 + Preimage Length: 73 + Transaction included in blockHash 0x13d7f729af6fc803c863b6beba9e2e788f1d85114f5165c41f96b80dfdf49844 + Referendum submitted with index: 79 + Transaction finalized in blockHash 0x13d7f729af6fc803c863b6beba9e2e788f1d85114f5165c41f96b80dfdf49844 + Transaction successful! Hash: 0x13d7f729af6fc803c863b6beba9e2e788f1d85114f5165c41f96b80dfdf49844 +
\ No newline at end of file diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index 51086c364..3a550be48 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -122,6 +122,17 @@ The resulting output will be something like: For Moonbase Alpha, you do not need to go through governance, as Moonbase Alpha has `sudo` access. Instead, you can provide the output of the batch call data to the Moonbeam team, and the Moonbeam Team can submit the call with `sudo`. This will be a faster and easier process than going thru governance, however, you may still wish to go through governance on Moonbase Alpha in order to prepare for the governance process on Moonbeam. +After submitting the preimage, you can submit the proposal as follows: + +??? code "Submit proposal for batch call" + ```typescript + --8<-- 'code/builders/interoperability/xcm/xc-registration/assets/submit-proposal.js' + ``` + +The resulting output will be something like: + +--8<-- 'code/builders/interoperability/xcm/xc-registration/assets/terminal/submitProposal.md' + ### Test the Asset Registration on Moonbeam {: #test-asset-registration } After your asset is registered, the team will provide the asset ID and the [XC-20 precompile](/builders/interoperability/xcm/xc20/interact/#the-erc20-interface){target=\_blank} address. @@ -385,7 +396,7 @@ Since local XC-20s are ERC-20s on Moonbeam, there are no deposits required to cr ## Managing XC Assets -After completing the [registration process](#introduction) for an XC asset, you may need to periodically update asset details, such as the XCM multilocation details or asset price. This guide will cover these topics and more. +After completing the [registration process](#introduction) for an XC asset, you may need to periodically update asset details, such as the XCM multilocation details or asset price. This section will cover these topics. ### Updating Foreign Asset XCM Location {: #updating-foreign-asset-xcm-location } From 5499060ab06271116e2a34dc6ca35181bf8b5ed1 Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Tue, 22 Oct 2024 20:22:27 -0700 Subject: [PATCH 08/64] run grammarly --- .../xcm/xc-registration/assets.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index 3a550be48..d412ac2a9 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -23,7 +23,7 @@ yarn Registering External XC-20s on Moonbeam is a multi-step process that, at a high level, involves proposing the asset registration on the [Moonbeam Community Forum](https://forum.moonbeam.network){target=\_blank} and creating an on-chain governance proposal. -If a channel between Moonbeam and the origin chain of the asset does not yet exist, one will need to be opened. You can batch the channel-related calls with the asset registration calls, so you only need to submit a single proposal. You'll need to start by creating a couple of forum posts: an [XCM Disclosure](/builders/interoperability/xcm/xc-registration/forum-templates/#xcm-disclosures){target=\_blank} post and an [XCM Proposal](/builders/interoperability/xcm/xc-registration/forum-templates/#xcm-proposals){target=\_blank} post. +If a channel between Moonbeam and the origin chain of the asset does not yet exist, one will need to be opened. You can batch the channel-related calls with the asset registration calls, so you only need to submit a single proposal. You must start by creating a couple of forum posts: an [XCM Disclosure](/builders/interoperability/xcm/xc-registration/forum-templates/#xcm-disclosures){target=\_blank} post and an [XCM Proposal](/builders/interoperability/xcm/xc-registration/forum-templates/#xcm-proposals){target=\_blank} post. After you've collected feedback from community members, you can create a proposal to open a channel and register any assets. Please refer to the [Establishing an XC Integration with Moonbeam](/builders/interoperability/xcm/xc-registration/xc-integration/){target=\_blank} guide for more information on opening a channel. @@ -69,7 +69,7 @@ To get the encoded calldata for the `evmForeignAssets.createForeignAsset` extrin - `symbol` - the symbol of the asset. **Remember that "xc" should be prepended to the symbol to indicate the asset is an XCM-enabled asset** - `name` - The asset name -You can use the below script to generate the encoded call data for the `createForeignAsset` call. Remember to replace the example parameter values shown in the script with the ones relevant to your asset. +You can use the script below to generate the encoded call data for the `createForeignAsset` call. Remember to replace the example parameter values shown in the script with the ones relevant to your asset. ???+ code "Get encoded call data for createForeignAsset" ```typescript @@ -85,7 +85,7 @@ To get the encoded calldata for the `xcmWeightTrader.addAsset` extrinsic, you wi - `xcmLocation` - the multilocation of the asset relative to Moonbeam - `relativePrice` - the the cost of an asset in terms of weight, used to determine how much of the asset is required to cover the fees for cross-chain (XCM) operations. It is calculated by comparing the asset's value to the network's native token in terms of the weight-to-fee conversion -You can use the below script to generate the encoded call data for the `addAsset` call. Remember to replace the example parameter values shown in the script with the ones relevant to your asset. +You can use the script below to generate the encoded call data for the `addAsset` call. Remember to replace the example parameter values shown in the script with the ones relevant to your asset. ??? code "Get encoded call data for xcmWeightTrader" ```typescript @@ -109,7 +109,7 @@ The resulting output will be something like: ### Programmatically Submit the Preimage and Proposal for Asset Registration {: #submit-preimage-proposal } -You can programmatically submit the preimage of your batched call containing both the `xcmWeightTrader.addAsset` and the `evmForeignAssets.createForeignAsset` calls as shown in the following script. As this is an on-chain transaction, you'll need to provide a wallet. (Never store your private keys in a javascript file - this is provided for demonstration purposes only). Remember to replace the encoded call data with the respective relevant batch call for your asset. You can also adapt this script for a different network. +You can programmatically submit the preimage of your batched call containing both the `xcmWeightTrader.addAsset` and the `evmForeignAssets.createForeignAsset` calls as shown in the following script. As this is an on-chain transaction, you'll need to provide a wallet. (Never store your private keys in a javascript file - this is provided for demonstration purposes only). Remember to replace the encoded call data with your asset's relevant batch call. You can also adapt this script for a different network. ??? code "Submit preimage for batch call" ```typescript @@ -120,7 +120,7 @@ The resulting output will be something like: --8<-- 'code/builders/interoperability/xcm/xc-registration/assets/terminal/submitPreimage.md' -For Moonbase Alpha, you do not need to go through governance, as Moonbase Alpha has `sudo` access. Instead, you can provide the output of the batch call data to the Moonbeam team, and the Moonbeam Team can submit the call with `sudo`. This will be a faster and easier process than going thru governance, however, you may still wish to go through governance on Moonbase Alpha in order to prepare for the governance process on Moonbeam. +For Moonbase Alpha, you do not need to go through governance, as Moonbase Alpha has `sudo` access. Instead, you can provide the output of the batch call data to the Moonbeam team, and the Moonbeam Team can submit the call with `sudo`. This will be a faster and easier process than going through governance. However, you may still wish to go through governance on Moonbase Alpha in order to prepare for the governance process on Moonbeam. After submitting the preimage, you can submit the proposal as follows: @@ -137,9 +137,9 @@ The resulting output will be something like: After your asset is registered, the team will provide the asset ID and the [XC-20 precompile](/builders/interoperability/xcm/xc20/interact/#the-erc20-interface){target=\_blank} address. -Your XC-20 precompile address is calculated by converting the asset ID decimal number to hex and prepending it with F's until you get a 40 hex character (plus the “0x”) address. For more information on how it is calculated, please refer to the [Calculate External XC-20 Precompile Addresses](/builders/interoperability/xcm/xc20/interact/#calculate-xc20-address){target=\_blank} section of the External XC-20 guide. +Your XC-20 precompile address is calculated by converting the asset ID decimal number to hex and prepending it with F's until you get a 40-hex character (plus the “0x”) address. For more information on how it is calculated, please refer to the [Calculate External XC-20 Precompile Addresses](/builders/interoperability/xcm/xc20/interact/#calculate-xc20-address){target=\_blank} section of the External XC-20 guide. -After the asset is successfully registered, you can try transferring tokens from your parachain to the Moonbeam-based network you are integrating with. +After the asset is successfully registered, you can transfer tokens from your parachain to the Moonbeam-based network you are integrating with. !!! note Remember that Moonbeam-based networks use AccountKey20 (Ethereum-style addresses). @@ -215,7 +215,7 @@ After running the script to set the bytecode, you should see `The XC-20 precompi ## Register Moonbeam Assets on Another Chain {: #register-moonbeam-assets-on-another-chain } -In order to enable cross-chain transfers of Moonbeam assets, including Moonbeam native assets (GLMR, MOVR, DEV) and local XC-20s (XCM-enabled ERC-20s) deployed on Moonbeam, between Moonbeam and another chain, you'll need to register the assets on the other chain. Since each chain stores cross-chain assets differently, the exact steps to register Moonbeam assets on another chain will vary depending on the chain. At the very least, you'll need to know the metadata and the multilocation of the assets on Moonbeam. +To enable cross-chain transfers of Moonbeam assets, including Moonbeam native assets (GLMR, MOVR, DEV) and local XC-20s (XCM-enabled ERC-20s) deployed on Moonbeam, between Moonbeam and another chain, you'll need to register the assets on the other chain. Since each chain stores cross-chain assets differently, the exact steps to register Moonbeam assets on another chain will vary depending on the chain. At the very least, you'll need to know the metadata and the multilocation of the assets on Moonbeam. There are additional steps aside from asset registration that will need to be taken to enable cross-chain integration with Moonbeam. For more information, please refer to the [Establishing an XC Integration with Moonbeam](/builders/interoperability/xcm/xc-registration/xc-integration/){target=\_blank} guide. @@ -400,7 +400,7 @@ After completing the [registration process](#introduction) for an XC asset, you ### Updating Foreign Asset XCM Location {: #updating-foreign-asset-xcm-location } -You can update the multilocation of an asset with the `evmForeignAssets.changeXcmLocation` call, which takes as parameters, the `assetId` and the new multilocation. You'll need to raise a [governance proposal](/tokens/governance/proposals/) and submit the update under the `FastGeneralAdmin` track. If you're testing in Moonbase Alpha, you can optionally ask the Moonbeam Team to submit the extrinsic using Sudo to speed up the process. You can also submit the requisite governance proposal on Moonbase Alpha. +You can update the multilocation of an asset with the `evmForeignAssets.changeXcmLocation` call, which takes as parameters, the `assetId` and the new multilocation. You'll need to raise a [governance proposal](/tokens/governance/proposals/) and submit the update under the `FastGeneralAdmin` track. If you're testing in Moonbase Alpha, you can ask the Moonbeam Team to submit the extrinsic using Sudo to speed up the process. You can also submit the requisite governance proposal on Moonbase Alpha. ### Freezing a Foreign Asset {: #freezing-a--foreign-asset } From 54470e9a2eeaf310581c71a3d3734e3d44c4b283 Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Tue, 22 Oct 2024 20:24:59 -0700 Subject: [PATCH 09/64] run prettier --- .../xcm/xc-registration/assets/batch-calls.js | 101 ++++----- .../assets/create-foreign-asset.js | 94 ++++---- .../xc-registration/assets/submit-preimage.js | 138 ++++++------ .../xc-registration/assets/submit-proposal.js | 206 ++++++++++-------- .../xc-registration/assets/weight-trader.js | 64 +++--- 5 files changed, 313 insertions(+), 290 deletions(-) diff --git a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/batch-calls.js b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/batch-calls.js index 042a8ad22..702b23ef4 100644 --- a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/batch-calls.js +++ b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/batch-calls.js @@ -3,67 +3,62 @@ import { encodeAddress } from '@polkadot/util-crypto'; import { u8aToHex } from '@polkadot/util'; async function getEncodedBatchCallData() { - // Connect to Moonbase Alpha - const provider = new WsProvider('wss://moonbase-alpha.public.blastapi.io'); - const api = await ApiPromise.create({ provider }); + // Connect to Moonbase Alpha + const provider = new WsProvider('wss://moonbase-alpha.public.blastapi.io'); + const api = await ApiPromise.create({ provider }); - try { - // Parameters for createForeignAsset - const assetId = '340282366920938463463374607431768211455'; - const xcmLocation = { - parents: 1, - interior: { - X1: [ - { Parachain: 888 } - ] - } - }; - const assetName = Array.from(Buffer.from('My Foreign Asset')); - const assetSymbol = Array.from(Buffer.from('xcMFA')); - const decimals = 18; + try { + // Parameters for createForeignAsset + const assetId = '340282366920938463463374607431768211455'; + const xcmLocation = { + parents: 1, + interior: { + X1: [{ Parachain: 888 }], + }, + }; + const assetName = Array.from(Buffer.from('My Foreign Asset')); + const assetSymbol = Array.from(Buffer.from('xcMFA')); + const decimals = 18; - // Parameters for xcmWeightTrader.addAsset - const relativePrice = '5000'; + // Parameters for xcmWeightTrader.addAsset + const relativePrice = '5000'; - // Create individual calls - const createAssetCall = api.tx.evmForeignAssets.createForeignAsset( - assetId, - xcmLocation, - decimals, - assetSymbol, - assetName - ); + // Create individual calls + const createAssetCall = api.tx.evmForeignAssets.createForeignAsset( + assetId, + xcmLocation, + decimals, + assetSymbol, + assetName + ); - const addAssetCall = api.tx.xcmWeightTrader.addAsset( - xcmLocation, - relativePrice - ); + const addAssetCall = api.tx.xcmWeightTrader.addAsset( + xcmLocation, + relativePrice + ); - // Combine calls into a batch - const batchCall = api.tx.utility.batch([ - createAssetCall, - addAssetCall - ]); + // Combine calls into a batch + const batchCall = api.tx.utility.batch([createAssetCall, addAssetCall]); - // Get the encoded call data for the batch - const encodedBatchData = batchCall.method.toHex(); - - console.log('Individual Calls:'); - console.log('Create Asset Call:', createAssetCall.method.toHex()); - console.log('Add Asset Call:', addAssetCall.method.toHex()); - console.log('\nBatch Call:'); - console.log('Encoded Batch Call Data:', encodedBatchData); + // Get the encoded call data for the batch + const encodedBatchData = batchCall.method.toHex(); - await api.disconnect(); - return encodedBatchData; - } catch (error) { - console.error('Error details:', error); - await api.disconnect(); - throw error; - } + console.log('Individual Calls:'); + console.log('Create Asset Call:', createAssetCall.method.toHex()); + console.log('Add Asset Call:', addAssetCall.method.toHex()); + console.log('\nBatch Call:'); + console.log('Encoded Batch Call Data:', encodedBatchData); + + await api.disconnect(); + return encodedBatchData; + } catch (error) { + console.error('Error details:', error); + await api.disconnect(); + throw error; + } } // Execute the function getEncodedBatchCallData() - .catch(console.error) - .finally(() => process.exit()); \ No newline at end of file + .catch(console.error) + .finally(() => process.exit()); diff --git a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/create-foreign-asset.js b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/create-foreign-asset.js index 6595bff08..dc606e26a 100644 --- a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/create-foreign-asset.js +++ b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/create-foreign-asset.js @@ -3,54 +3,54 @@ import { encodeAddress } from '@polkadot/util-crypto'; import { u8aToHex } from '@polkadot/util'; async function getEncodedCallData() { - // Connect to Moonbase Alpha - const provider = new WsProvider('wss://moonbase-alpha.public.blastapi.io'); - const api = await ApiPromise.create({ provider }); - - // Example parameters with correct types - const assetId = '340282366920938463463374607431768211455'; - - // XCM V4 Multilocation structured according to Moonbeam's format - const xcmLocation = { - parents: 1, - interior: { - X1: [ - { Parachain: 888 } // Replace with actual parachain ID - ] - } - }; - - // Convert strings to Uint8Array for Bytes type - const assetName = Array.from(Buffer.from('My Foreign Asset')); - const assetSymbol = Array.from(Buffer.from('xcMFA')); - - // Decimals as a number (not string) - const decimals = 18; - - try { - // Create the call - const call = api.tx.evmForeignAssets.createForeignAsset( - assetId, - xcmLocation, - decimals, - assetSymbol, - assetName - ); - - // Get the encoded call data - const encodedData = call.method.toHex(); - console.log('Encoded Call Data:', encodedData); - - await api.disconnect(); - return encodedData; - } catch (error) { - console.error('Error details:', error); - await api.disconnect(); - throw error; - } + // Connect to Moonbase Alpha + const provider = new WsProvider('wss://moonbase-alpha.public.blastapi.io'); + const api = await ApiPromise.create({ provider }); + + // Example parameters with correct types + const assetId = '340282366920938463463374607431768211455'; + + // XCM V4 Multilocation structured according to Moonbeam's format + const xcmLocation = { + parents: 1, + interior: { + X1: [ + { Parachain: 888 }, // Replace with actual parachain ID + ], + }, + }; + + // Convert strings to Uint8Array for Bytes type + const assetName = Array.from(Buffer.from('My Foreign Asset')); + const assetSymbol = Array.from(Buffer.from('xcMFA')); + + // Decimals as a number (not string) + const decimals = 18; + + try { + // Create the call + const call = api.tx.evmForeignAssets.createForeignAsset( + assetId, + xcmLocation, + decimals, + assetSymbol, + assetName + ); + + // Get the encoded call data + const encodedData = call.method.toHex(); + console.log('Encoded Call Data:', encodedData); + + await api.disconnect(); + return encodedData; + } catch (error) { + console.error('Error details:', error); + await api.disconnect(); + throw error; + } } // Execute the function getEncodedCallData() - .catch(console.error) - .finally(() => process.exit()); \ No newline at end of file + .catch(console.error) + .finally(() => process.exit()); diff --git a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/submit-preimage.js b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/submit-preimage.js index 8f45ebc39..42b831632 100644 --- a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/submit-preimage.js +++ b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/submit-preimage.js @@ -4,80 +4,96 @@ import { cryptoWaitReady } from '@polkadot/util-crypto'; import { u8aToHex } from '@polkadot/util'; async function submitPreimage() { - // Wait for the crypto libraries to be ready - await cryptoWaitReady(); + // Wait for the crypto libraries to be ready + await cryptoWaitReady(); - // Connect to Moonbase Alpha - const provider = new WsProvider('wss://moonbase-alpha.public.blastapi.io'); - const api = await ApiPromise.create({ provider }); + // Connect to Moonbase Alpha + const provider = new WsProvider('wss://moonbase-alpha.public.blastapi.io'); + const api = await ApiPromise.create({ provider }); - // Initialize keyring and add account - const keyring = new Keyring({ type: 'ethereum' }); // Use ethereum type for Moonbeam - - // IMPORTANT: Replace with your private key - const PRIVATE_KEY = 'INSERT-PRIVATE-KEY'; // e.g., '0x1234...' - const account = keyring.addFromUri(PRIVATE_KEY); + // Initialize keyring and add account + const keyring = new Keyring({ type: 'ethereum' }); // Use ethereum type for Moonbeam - console.log('Account address:', account.address); + // IMPORTANT: Replace with your private key + const PRIVATE_KEY = 'INSERT-PRIVATE-KEY'; // e.g., '0x1234...' + const account = keyring.addFromUri(PRIVATE_KEY); - // The encoded call data to be submitted as preimage - const encodedCallData = '0x0100083800ffffffffffffffffffffffffffffffff010100e10d121478634d4641404d7920466f726569676e2041737365743a00010100e10d88130000000000000000000000000000'; + console.log('Account address:', account.address); - try { - // Create the notePreimage call - const preimageCall = api.tx.preimage.notePreimage(encodedCallData); + // The encoded call data to be submitted as preimage + const encodedCallData = + '0x0100083800ffffffffffffffffffffffffffffffff010100e10d121478634d4641404d7920466f726569676e2041737365743a00010100e10d88130000000000000000000000000000'; - // Calculate the hash of the preimage - const preimageHash = await api.registry.hash(encodedCallData); + try { + // Create the notePreimage call + const preimageCall = api.tx.preimage.notePreimage(encodedCallData); - console.log('Submitting preimage for encoded call data:'); - console.log('Original Call Data:', encodedCallData); - console.log('Note Preimage Encoded Call:', preimageCall.method.toHex()); - console.log('Preimage Hash:', preimageHash.toHex()); + // Calculate the hash of the preimage + const preimageHash = await api.registry.hash(encodedCallData); - // Get the account's current nonce - const nonce = await api.rpc.system.accountNextIndex(account.address); + console.log('Submitting preimage for encoded call data:'); + console.log('Original Call Data:', encodedCallData); + console.log('Note Preimage Encoded Call:', preimageCall.method.toHex()); + console.log('Preimage Hash:', preimageHash.toHex()); - // Submit and wait for transaction - const txHash = await new Promise((resolve, reject) => { - preimageCall.signAndSend(account, { nonce }, ({ status, dispatchError, events }) => { - if (dispatchError) { - if (dispatchError.isModule) { - // Handle module error - const decoded = api.registry.findMetaError(dispatchError.asModule); - const { docs, name, section } = decoded; - reject(new Error(`${section}.${name}: ${docs.join(' ')}`)); - } else { - // Handle other errors - reject(new Error(dispatchError.toString())); - } - } + // Get the account's current nonce + const nonce = await api.rpc.system.accountNextIndex(account.address); - if (status.isInBlock) { - console.log(`Transaction included in blockHash ${status.asInBlock}`); - } else if (status.isFinalized) { - console.log(`Transaction finalized in blockHash ${status.asFinalized}`); - resolve(status.asFinalized); - } - }).catch(reject); - }); + // Submit and wait for transaction + const txHash = await new Promise((resolve, reject) => { + preimageCall + .signAndSend( + account, + { nonce }, + ({ status, dispatchError, events }) => { + if (dispatchError) { + if (dispatchError.isModule) { + // Handle module error + const decoded = api.registry.findMetaError( + dispatchError.asModule + ); + const { docs, name, section } = decoded; + reject(new Error(`${section}.${name}: ${docs.join(' ')}`)); + } else { + // Handle other errors + reject(new Error(dispatchError.toString())); + } + } - console.log('Transaction successful! Hash:', txHash.toHex()); - console.log('Preimage hash (save this for reference):', preimageHash.toHex()); + if (status.isInBlock) { + console.log( + `Transaction included in blockHash ${status.asInBlock}` + ); + } else if (status.isFinalized) { + console.log( + `Transaction finalized in blockHash ${status.asFinalized}` + ); + resolve(status.asFinalized); + } + } + ) + .catch(reject); + }); - await api.disconnect(); - return { - transactionHash: txHash.toHex(), - preimageHash: preimageHash.toHex() - }; - } catch (error) { - console.error('Error details:', error); - await api.disconnect(); - throw error; - } + console.log('Transaction successful! Hash:', txHash.toHex()); + console.log( + 'Preimage hash (save this for reference):', + preimageHash.toHex() + ); + + await api.disconnect(); + return { + transactionHash: txHash.toHex(), + preimageHash: preimageHash.toHex(), + }; + } catch (error) { + console.error('Error details:', error); + await api.disconnect(); + throw error; + } } // Execute the function submitPreimage() - .catch(console.error) - .finally(() => process.exit()); \ No newline at end of file + .catch(console.error) + .finally(() => process.exit()); diff --git a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/submit-proposal.js b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/submit-proposal.js index 1652e02dc..0891e5227 100644 --- a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/submit-proposal.js +++ b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/submit-proposal.js @@ -3,106 +3,120 @@ import { Keyring } from '@polkadot/keyring'; import { cryptoWaitReady } from '@polkadot/util-crypto'; async function submitReferendum() { - // Wait for the crypto libraries to be ready - await cryptoWaitReady(); - - // Connect to Moonbase Alpha - const provider = new WsProvider('wss://moonbase-alpha.public.blastapi.io'); - const api = await ApiPromise.create({ provider }); - - // Initialize keyring and add account - const keyring = new Keyring({ type: 'ethereum' }); - - // IMPORTANT: Replace with your private key - const PRIVATE_KEY = 'INSERT-PRIVATE-KEY'; - const account = keyring.addFromUri(PRIVATE_KEY); - - console.log('Account address:', account.address); - - try { - // Get current block number for enactment calculation - const currentBlock = await api.query.system.number(); - const enactmentBlock = currentBlock.toNumber() + 100; - - // The preimage data and hash - const preimageHash = '0x2ac24641cebeff3827ba10eb264d2db2990607c89a3fa2c8b2fef6b1e37e35e3'; - - // Length of the original batch call data - // This should match the length of your original encoded call data - const preimageLength = 73; // This is the length of your batch call encoded data - - // Parameters for the referendum - const origin = { Origins: 'FastGeneralAdmin' }; - const proposal = { - Lookup: { - hash: preimageHash, - len: preimageLength + // Wait for the crypto libraries to be ready + await cryptoWaitReady(); + + // Connect to Moonbase Alpha + const provider = new WsProvider('wss://moonbase-alpha.public.blastapi.io'); + const api = await ApiPromise.create({ provider }); + + // Initialize keyring and add account + const keyring = new Keyring({ type: 'ethereum' }); + + // IMPORTANT: Replace with your private key + const PRIVATE_KEY = 'INSERT-PRIVATE-KEY'; + const account = keyring.addFromUri(PRIVATE_KEY); + + console.log('Account address:', account.address); + + try { + // Get current block number for enactment calculation + const currentBlock = await api.query.system.number(); + const enactmentBlock = currentBlock.toNumber() + 100; + + // The preimage data and hash + const preimageHash = + '0x2ac24641cebeff3827ba10eb264d2db2990607c89a3fa2c8b2fef6b1e37e35e3'; + + // Length of the original batch call data + // This should match the length of your original encoded call data + const preimageLength = 73; // This is the length of your batch call encoded data + + // Parameters for the referendum + const origin = { Origins: 'FastGeneralAdmin' }; + const proposal = { + Lookup: { + hash: preimageHash, + len: preimageLength, + }, + }; + const enactment = { After: 100 }; + + // Create the referendum submission call + const referendumCall = api.tx.referenda.submit(origin, proposal, enactment); + + // Get the encoded call data + const encodedCall = referendumCall.method.toHex(); + console.log('\nReferendum submission details:'); + console.log('Encoded Call:', encodedCall); + console.log('Current Block:', currentBlock.toString()); + console.log('Enactment Block:', enactmentBlock); + console.log('Preimage Hash:', preimageHash); + console.log('Preimage Length:', preimageLength); + + // Get the account's current nonce + const nonce = await api.rpc.system.accountNextIndex(account.address); + + // Submit and wait for transaction + const txHash = await new Promise((resolve, reject) => { + referendumCall + .signAndSend( + account, + { nonce }, + ({ status, dispatchError, events }) => { + if (dispatchError) { + if (dispatchError.isModule) { + const decoded = api.registry.findMetaError( + dispatchError.asModule + ); + const { docs, name, section } = decoded; + reject(new Error(`${section}.${name}: ${docs.join(' ')}`)); + } else { + reject(new Error(dispatchError.toString())); + } } - }; - const enactment = { After: 100 }; - - // Create the referendum submission call - const referendumCall = api.tx.referenda.submit( - origin, - proposal, - enactment - ); - - // Get the encoded call data - const encodedCall = referendumCall.method.toHex(); - console.log('\nReferendum submission details:'); - console.log('Encoded Call:', encodedCall); - console.log('Current Block:', currentBlock.toString()); - console.log('Enactment Block:', enactmentBlock); - console.log('Preimage Hash:', preimageHash); - console.log('Preimage Length:', preimageLength); - - // Get the account's current nonce - const nonce = await api.rpc.system.accountNextIndex(account.address); - - // Submit and wait for transaction - const txHash = await new Promise((resolve, reject) => { - referendumCall.signAndSend(account, { nonce }, ({ status, dispatchError, events }) => { - if (dispatchError) { - if (dispatchError.isModule) { - const decoded = api.registry.findMetaError(dispatchError.asModule); - const { docs, name, section } = decoded; - reject(new Error(`${section}.${name}: ${docs.join(' ')}`)); - } else { - reject(new Error(dispatchError.toString())); - } - } - if (status.isInBlock) { - console.log(`Transaction included in blockHash ${status.asInBlock}`); - // Try to find the referendum index from events - events.forEach(({ event }) => { - if (event.section === 'referenda' && event.method === 'Submitted') { - const [referendumIndex] = event.data; - console.log(`Referendum submitted with index: ${referendumIndex}`); - } - }); - } else if (status.isFinalized) { - console.log(`Transaction finalized in blockHash ${status.asFinalized}`); - resolve(status.asFinalized); + if (status.isInBlock) { + console.log( + `Transaction included in blockHash ${status.asInBlock}` + ); + // Try to find the referendum index from events + events.forEach(({ event }) => { + if ( + event.section === 'referenda' && + event.method === 'Submitted' + ) { + const [referendumIndex] = event.data; + console.log( + `Referendum submitted with index: ${referendumIndex}` + ); } - }).catch(reject); - }); - - console.log('Transaction successful! Hash:', txHash.toHex()); - - await api.disconnect(); - return { - transactionHash: txHash.toHex() - }; - } catch (error) { - console.error('Error details:', error); - await api.disconnect(); - throw error; - } + }); + } else if (status.isFinalized) { + console.log( + `Transaction finalized in blockHash ${status.asFinalized}` + ); + resolve(status.asFinalized); + } + } + ) + .catch(reject); + }); + + console.log('Transaction successful! Hash:', txHash.toHex()); + + await api.disconnect(); + return { + transactionHash: txHash.toHex(), + }; + } catch (error) { + console.error('Error details:', error); + await api.disconnect(); + throw error; + } } // Execute the function submitReferendum() - .catch(console.error) - .finally(() => process.exit()); \ No newline at end of file + .catch(console.error) + .finally(() => process.exit()); diff --git a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/weight-trader.js b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/weight-trader.js index 98a6595a3..aec2a1fb6 100644 --- a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/weight-trader.js +++ b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/weight-trader.js @@ -3,45 +3,43 @@ import { encodeAddress } from '@polkadot/util-crypto'; import { u8aToHex } from '@polkadot/util'; async function getEncodedCallData() { - // Connect to Moonbase Alpha - const provider = new WsProvider('wss://moonbase-alpha.public.blastapi.io'); - const api = await ApiPromise.create({ provider }); + // Connect to Moonbase Alpha + const provider = new WsProvider('wss://moonbase-alpha.public.blastapi.io'); + const api = await ApiPromise.create({ provider }); - // Corrected XCM V4 Multilocation structure - const xcmLocation = { - parents: 1, - interior: { - X1: [ - { Parachain: 888 } - ] - } - }; + // Corrected XCM V4 Multilocation structure + const xcmLocation = { + parents: 1, + interior: { + X1: [{ Parachain: 888 }], + }, + }; - // Relative price as u128 - const relativePrice = '5000'; + // Relative price as u128 + const relativePrice = '5000'; - try { - // Create the call - const call = api.tx.xcmWeightTrader.addAsset( - xcmLocation, - relativePrice - ); + try { + // Create the call + const call = api.tx.xcmWeightTrader.addAsset(xcmLocation, relativePrice); - // Get the encoded call data - const encodedData = call.method.toHex(); - console.log('Encoded Call Data:', encodedData); + // Get the encoded call data + const encodedData = call.method.toHex(); + console.log('Encoded Call Data:', encodedData); - await api.disconnect(); - return encodedData; - } catch (error) { - console.error('Error details:', error); - console.error('Attempted XCM Location:', JSON.stringify(xcmLocation, null, 2)); - await api.disconnect(); - throw error; - } + await api.disconnect(); + return encodedData; + } catch (error) { + console.error('Error details:', error); + console.error( + 'Attempted XCM Location:', + JSON.stringify(xcmLocation, null, 2) + ); + await api.disconnect(); + throw error; + } } // Execute the function getEncodedCallData() - .catch(console.error) - .finally(() => process.exit()); \ No newline at end of file + .catch(console.error) + .finally(() => process.exit()); From 0a7cca0a8f846425d9c9c5de89b94108b93f2dea Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Tue, 22 Oct 2024 20:25:42 -0700 Subject: [PATCH 10/64] rev --- builders/interoperability/xcm/xc-registration/assets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index d412ac2a9..2c5ef67ae 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -83,7 +83,7 @@ The resulting output will be something like: To get the encoded calldata for the `xcmWeightTrader.addAsset` extrinsic, you will need to provide the following arguments: - `xcmLocation` - the multilocation of the asset relative to Moonbeam -- `relativePrice` - the the cost of an asset in terms of weight, used to determine how much of the asset is required to cover the fees for cross-chain (XCM) operations. It is calculated by comparing the asset's value to the network's native token in terms of the weight-to-fee conversion +- `relativePrice` - the cost of an asset in terms of weight, used to determine how much of the asset is required to cover the fees for cross-chain (XCM) operations. It is calculated by comparing the asset's value to the network's native token in terms of the weight-to-fee conversion You can use the script below to generate the encoded call data for the `addAsset` call. Remember to replace the example parameter values shown in the script with the ones relevant to your asset. From e1f2dd13b518a3a1f1870a3e4b185556e7ca912d Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Thu, 12 Dec 2024 17:38:15 -0800 Subject: [PATCH 11/64] revision --- builders/interoperability/xcm/xc-registration/assets.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index 2c5ef67ae..10e0e6db8 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -49,7 +49,7 @@ To get started, you'll need to collect some information about the asset: - The asset symbol. You'll need to prepend "xc" to the asset symbol to indicate that the asset is an XCM-enabled asset - The number of decimals the asset has -With this information in hand, you can prepare a governance proposal to register a foreign asset. Foreign asset registration proposals should be submitted through the `FastGeneralAdmin` track. +With this information in hand, you can prepare a governance proposal to register a foreign asset. Foreign asset registration proposals should be submitted through the `GeneralAdmin` track. ![Overview of the proposal process](/images/builders/interoperability/xcm/xc-registration/assets/assets-3.webp) @@ -59,7 +59,7 @@ If you're not familiar with the governance system on Moonbeam, you can find out To submit a preimage, you'll need to get the encoded calldata for each extrinsic that you want to execute. As previously mentioned, you'll use the `evmForeignAssets.createForeignAsset` and the `xcmWeightTrader.addAsset` extrinsics. -Proposals must be submitted via the `FastGeneralAdmin` track. If you're opening a channel and registering an asset and you'll want to wait until the channel is established prior to attempting to register the asset. +Proposals must be submitted via the `GeneralAdmin` track. If you're opening a channel and registering an asset and you'll want to wait until the channel is established prior to attempting to register the asset. To get the encoded calldata for the `evmForeignAssets.createForeignAsset` extrinsic, you will need to provide the following arguments: @@ -400,7 +400,7 @@ After completing the [registration process](#introduction) for an XC asset, you ### Updating Foreign Asset XCM Location {: #updating-foreign-asset-xcm-location } -You can update the multilocation of an asset with the `evmForeignAssets.changeXcmLocation` call, which takes as parameters, the `assetId` and the new multilocation. You'll need to raise a [governance proposal](/tokens/governance/proposals/) and submit the update under the `FastGeneralAdmin` track. If you're testing in Moonbase Alpha, you can ask the Moonbeam Team to submit the extrinsic using Sudo to speed up the process. You can also submit the requisite governance proposal on Moonbase Alpha. +You can update the multilocation of an asset with the `evmForeignAssets.changeXcmLocation` call, which takes as parameters, the `assetId` and the new multilocation. You'll need to raise a [governance proposal](/tokens/governance/proposals/) and submit the update under the `GeneralAdmin` track. If you're testing in Moonbase Alpha, you can ask the Moonbeam Team to submit the extrinsic using Sudo to speed up the process. You can also submit the requisite governance proposal on Moonbase Alpha. ### Freezing a Foreign Asset {: #freezing-a--foreign-asset } From faa5e73be402e03cf78907b721613aaf6c72109c Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Thu, 12 Dec 2024 19:10:57 -0800 Subject: [PATCH 12/64] revisions --- .../xcm/xc-registration/assets/batch-calls.js | 64 --------- .../assets/calculate-relative-price.ts | 109 ++++++++++++++++ .../assets/create-foreign-asset.js | 56 -------- .../xc-registration/assets/submit-preimage.js | 99 -------------- .../xc-registration/assets/submit-proposal.js | 122 ------------------ .../assets/terminal/batchCall.md | 8 -- .../assets/terminal/createForeignAsset.md | 4 - .../assets/terminal/submitPreimage.md | 12 -- .../assets/terminal/submitProposal.md | 14 -- .../assets/terminal/weightTrader.md | 4 - .../xc-registration/assets/weight-trader.js | 3 +- .../xcm/xc-registration/assets.md | 74 ++--------- 12 files changed, 125 insertions(+), 444 deletions(-) delete mode 100644 .snippets/code/builders/interoperability/xcm/xc-registration/assets/batch-calls.js create mode 100644 .snippets/code/builders/interoperability/xcm/xc-registration/assets/calculate-relative-price.ts delete mode 100644 .snippets/code/builders/interoperability/xcm/xc-registration/assets/create-foreign-asset.js delete mode 100644 .snippets/code/builders/interoperability/xcm/xc-registration/assets/submit-preimage.js delete mode 100644 .snippets/code/builders/interoperability/xcm/xc-registration/assets/submit-proposal.js delete mode 100644 .snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/batchCall.md delete mode 100644 .snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/createForeignAsset.md delete mode 100644 .snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/submitPreimage.md delete mode 100644 .snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/submitProposal.md delete mode 100644 .snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/weightTrader.md diff --git a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/batch-calls.js b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/batch-calls.js deleted file mode 100644 index 702b23ef4..000000000 --- a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/batch-calls.js +++ /dev/null @@ -1,64 +0,0 @@ -import { ApiPromise, WsProvider } from '@polkadot/api'; -import { encodeAddress } from '@polkadot/util-crypto'; -import { u8aToHex } from '@polkadot/util'; - -async function getEncodedBatchCallData() { - // Connect to Moonbase Alpha - const provider = new WsProvider('wss://moonbase-alpha.public.blastapi.io'); - const api = await ApiPromise.create({ provider }); - - try { - // Parameters for createForeignAsset - const assetId = '340282366920938463463374607431768211455'; - const xcmLocation = { - parents: 1, - interior: { - X1: [{ Parachain: 888 }], - }, - }; - const assetName = Array.from(Buffer.from('My Foreign Asset')); - const assetSymbol = Array.from(Buffer.from('xcMFA')); - const decimals = 18; - - // Parameters for xcmWeightTrader.addAsset - const relativePrice = '5000'; - - // Create individual calls - const createAssetCall = api.tx.evmForeignAssets.createForeignAsset( - assetId, - xcmLocation, - decimals, - assetSymbol, - assetName - ); - - const addAssetCall = api.tx.xcmWeightTrader.addAsset( - xcmLocation, - relativePrice - ); - - // Combine calls into a batch - const batchCall = api.tx.utility.batch([createAssetCall, addAssetCall]); - - // Get the encoded call data for the batch - const encodedBatchData = batchCall.method.toHex(); - - console.log('Individual Calls:'); - console.log('Create Asset Call:', createAssetCall.method.toHex()); - console.log('Add Asset Call:', addAssetCall.method.toHex()); - console.log('\nBatch Call:'); - console.log('Encoded Batch Call Data:', encodedBatchData); - - await api.disconnect(); - return encodedBatchData; - } catch (error) { - console.error('Error details:', error); - await api.disconnect(); - throw error; - } -} - -// Execute the function -getEncodedBatchCallData() - .catch(console.error) - .finally(() => process.exit()); diff --git a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/calculate-relative-price.ts b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/calculate-relative-price.ts new file mode 100644 index 000000000..945a76cf8 --- /dev/null +++ b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/calculate-relative-price.ts @@ -0,0 +1,109 @@ +import axios from 'axios'; +import chalk from 'chalk'; + +// CoinGecko IDs for the networks +const NETWORK_IDS = { + GLMR: 'moonbeam', + MOVR: 'moonriver' +}; + +async function calculateRelativePrice( + assetPrice: number, + network: 'GLMR' | 'MOVR' +): Promise { + try { + // Fetch the native token price from CoinGecko + const response = await axios.get( + `https://api.coingecko.com/api/v3/simple/price?ids=${NETWORK_IDS[network]}&vs_currencies=usd` + ); + + const nativeTokenPrice = response.data[NETWORK_IDS[network]].usd; + + // Calculate relative price with 18 decimal places + // Formula: (nativeTokenPrice / assetPrice) * 10^18 + // This gives us how many units of the asset we need to equal 1 unit of native token + const relativePrice = (nativeTokenPrice / assetPrice) * Math.pow(10, 18); + + // Return as string to preserve precision + return relativePrice.toFixed(0); + + } catch (error) { + if (error instanceof Error) { + throw new Error(`Failed to calculate relative price: ${error.message}`); + } + throw error; + } +} + +function validateInput(price: string, network: string): { assetPrice: number; network: 'GLMR' | 'MOVR' } { + // Validate price + const assetPrice = parseFloat(price); + if (isNaN(assetPrice) || assetPrice <= 0) { + throw new Error('Price must be a positive number'); + } + + // Validate network + const upperNetwork = network.toUpperCase() as 'GLMR' | 'MOVR'; + if (!['GLMR', 'MOVR'].includes(upperNetwork)) { + throw new Error('Network must be either GLMR or MOVR'); + } + + return { assetPrice, network: upperNetwork }; +} + +function printUsage() { + console.log('\nUsage:'); + console.log('npx ts-node relative-price-calculator.ts '); + console.log('\nExample:'); + console.log('npx ts-node relative-price-calculator.ts 0.25 GLMR'); + console.log('\nParameters:'); + console.log('price - The price of your asset in USD'); + console.log('network - Either GLMR or MOVR'); +} + +async function main() { + try { + // Get command line arguments + const [,, price, network] = process.argv; + + // Check if help flag is passed + if (price === '--help' || price === '-h') { + printUsage(); + return; + } + + // Check if required arguments are provided + if (!price || !network) { + console.error('Error: Missing required arguments'); + printUsage(); + process.exit(1); + } + + // Validate inputs + const { assetPrice, network: validNetwork } = validateInput(price, network); + + console.log(`\nCalculating relative price for asset worth $${assetPrice} against ${validNetwork}...`); + const relativePrice = await calculateRelativePrice(assetPrice, validNetwork); + const nativeTokenPrice = (await axios.get( + `https://api.coingecko.com/api/v3/simple/price?ids=${NETWORK_IDS[validNetwork]}&vs_currencies=usd` + )).data[NETWORK_IDS[validNetwork]].usd; + + const decimalRatio = nativeTokenPrice / assetPrice; + + console.log(`\nResults:`); + console.log(`Asset Price: $${assetPrice}`); + console.log(`Network: ${validNetwork}`); + console.log(`Native Token Price (from CoinGecko): $${nativeTokenPrice}`); + console.log(`\nRelative Price Analysis:`); + console.log(`1 ${validNetwork} is equal to approximately ${decimalRatio.toFixed(3)} of your specified token.`); + console.log(`With 18 decimals, 1 ${validNetwork} or in WEI, 1000000000000000000 is equal to a relative price of ${relativePrice} units of your token`); + console.log(chalk.bold(`\nRelative Price: ${relativePrice}`)); + console.log(`\nThe relative price you should specify in asset registration steps is ${relativePrice}\n`); + + } catch (error) { + console.error('\nError:', error instanceof Error ? error.message : error); + process.exit(1); + } +} + +main(); \ No newline at end of file diff --git a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/create-foreign-asset.js b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/create-foreign-asset.js deleted file mode 100644 index dc606e26a..000000000 --- a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/create-foreign-asset.js +++ /dev/null @@ -1,56 +0,0 @@ -import { ApiPromise, WsProvider } from '@polkadot/api'; -import { encodeAddress } from '@polkadot/util-crypto'; -import { u8aToHex } from '@polkadot/util'; - -async function getEncodedCallData() { - // Connect to Moonbase Alpha - const provider = new WsProvider('wss://moonbase-alpha.public.blastapi.io'); - const api = await ApiPromise.create({ provider }); - - // Example parameters with correct types - const assetId = '340282366920938463463374607431768211455'; - - // XCM V4 Multilocation structured according to Moonbeam's format - const xcmLocation = { - parents: 1, - interior: { - X1: [ - { Parachain: 888 }, // Replace with actual parachain ID - ], - }, - }; - - // Convert strings to Uint8Array for Bytes type - const assetName = Array.from(Buffer.from('My Foreign Asset')); - const assetSymbol = Array.from(Buffer.from('xcMFA')); - - // Decimals as a number (not string) - const decimals = 18; - - try { - // Create the call - const call = api.tx.evmForeignAssets.createForeignAsset( - assetId, - xcmLocation, - decimals, - assetSymbol, - assetName - ); - - // Get the encoded call data - const encodedData = call.method.toHex(); - console.log('Encoded Call Data:', encodedData); - - await api.disconnect(); - return encodedData; - } catch (error) { - console.error('Error details:', error); - await api.disconnect(); - throw error; - } -} - -// Execute the function -getEncodedCallData() - .catch(console.error) - .finally(() => process.exit()); diff --git a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/submit-preimage.js b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/submit-preimage.js deleted file mode 100644 index 42b831632..000000000 --- a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/submit-preimage.js +++ /dev/null @@ -1,99 +0,0 @@ -import { ApiPromise, WsProvider } from '@polkadot/api'; -import { Keyring } from '@polkadot/keyring'; -import { cryptoWaitReady } from '@polkadot/util-crypto'; -import { u8aToHex } from '@polkadot/util'; - -async function submitPreimage() { - // Wait for the crypto libraries to be ready - await cryptoWaitReady(); - - // Connect to Moonbase Alpha - const provider = new WsProvider('wss://moonbase-alpha.public.blastapi.io'); - const api = await ApiPromise.create({ provider }); - - // Initialize keyring and add account - const keyring = new Keyring({ type: 'ethereum' }); // Use ethereum type for Moonbeam - - // IMPORTANT: Replace with your private key - const PRIVATE_KEY = 'INSERT-PRIVATE-KEY'; // e.g., '0x1234...' - const account = keyring.addFromUri(PRIVATE_KEY); - - console.log('Account address:', account.address); - - // The encoded call data to be submitted as preimage - const encodedCallData = - '0x0100083800ffffffffffffffffffffffffffffffff010100e10d121478634d4641404d7920466f726569676e2041737365743a00010100e10d88130000000000000000000000000000'; - - try { - // Create the notePreimage call - const preimageCall = api.tx.preimage.notePreimage(encodedCallData); - - // Calculate the hash of the preimage - const preimageHash = await api.registry.hash(encodedCallData); - - console.log('Submitting preimage for encoded call data:'); - console.log('Original Call Data:', encodedCallData); - console.log('Note Preimage Encoded Call:', preimageCall.method.toHex()); - console.log('Preimage Hash:', preimageHash.toHex()); - - // Get the account's current nonce - const nonce = await api.rpc.system.accountNextIndex(account.address); - - // Submit and wait for transaction - const txHash = await new Promise((resolve, reject) => { - preimageCall - .signAndSend( - account, - { nonce }, - ({ status, dispatchError, events }) => { - if (dispatchError) { - if (dispatchError.isModule) { - // Handle module error - const decoded = api.registry.findMetaError( - dispatchError.asModule - ); - const { docs, name, section } = decoded; - reject(new Error(`${section}.${name}: ${docs.join(' ')}`)); - } else { - // Handle other errors - reject(new Error(dispatchError.toString())); - } - } - - if (status.isInBlock) { - console.log( - `Transaction included in blockHash ${status.asInBlock}` - ); - } else if (status.isFinalized) { - console.log( - `Transaction finalized in blockHash ${status.asFinalized}` - ); - resolve(status.asFinalized); - } - } - ) - .catch(reject); - }); - - console.log('Transaction successful! Hash:', txHash.toHex()); - console.log( - 'Preimage hash (save this for reference):', - preimageHash.toHex() - ); - - await api.disconnect(); - return { - transactionHash: txHash.toHex(), - preimageHash: preimageHash.toHex(), - }; - } catch (error) { - console.error('Error details:', error); - await api.disconnect(); - throw error; - } -} - -// Execute the function -submitPreimage() - .catch(console.error) - .finally(() => process.exit()); diff --git a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/submit-proposal.js b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/submit-proposal.js deleted file mode 100644 index 0891e5227..000000000 --- a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/submit-proposal.js +++ /dev/null @@ -1,122 +0,0 @@ -import { ApiPromise, WsProvider } from '@polkadot/api'; -import { Keyring } from '@polkadot/keyring'; -import { cryptoWaitReady } from '@polkadot/util-crypto'; - -async function submitReferendum() { - // Wait for the crypto libraries to be ready - await cryptoWaitReady(); - - // Connect to Moonbase Alpha - const provider = new WsProvider('wss://moonbase-alpha.public.blastapi.io'); - const api = await ApiPromise.create({ provider }); - - // Initialize keyring and add account - const keyring = new Keyring({ type: 'ethereum' }); - - // IMPORTANT: Replace with your private key - const PRIVATE_KEY = 'INSERT-PRIVATE-KEY'; - const account = keyring.addFromUri(PRIVATE_KEY); - - console.log('Account address:', account.address); - - try { - // Get current block number for enactment calculation - const currentBlock = await api.query.system.number(); - const enactmentBlock = currentBlock.toNumber() + 100; - - // The preimage data and hash - const preimageHash = - '0x2ac24641cebeff3827ba10eb264d2db2990607c89a3fa2c8b2fef6b1e37e35e3'; - - // Length of the original batch call data - // This should match the length of your original encoded call data - const preimageLength = 73; // This is the length of your batch call encoded data - - // Parameters for the referendum - const origin = { Origins: 'FastGeneralAdmin' }; - const proposal = { - Lookup: { - hash: preimageHash, - len: preimageLength, - }, - }; - const enactment = { After: 100 }; - - // Create the referendum submission call - const referendumCall = api.tx.referenda.submit(origin, proposal, enactment); - - // Get the encoded call data - const encodedCall = referendumCall.method.toHex(); - console.log('\nReferendum submission details:'); - console.log('Encoded Call:', encodedCall); - console.log('Current Block:', currentBlock.toString()); - console.log('Enactment Block:', enactmentBlock); - console.log('Preimage Hash:', preimageHash); - console.log('Preimage Length:', preimageLength); - - // Get the account's current nonce - const nonce = await api.rpc.system.accountNextIndex(account.address); - - // Submit and wait for transaction - const txHash = await new Promise((resolve, reject) => { - referendumCall - .signAndSend( - account, - { nonce }, - ({ status, dispatchError, events }) => { - if (dispatchError) { - if (dispatchError.isModule) { - const decoded = api.registry.findMetaError( - dispatchError.asModule - ); - const { docs, name, section } = decoded; - reject(new Error(`${section}.${name}: ${docs.join(' ')}`)); - } else { - reject(new Error(dispatchError.toString())); - } - } - - if (status.isInBlock) { - console.log( - `Transaction included in blockHash ${status.asInBlock}` - ); - // Try to find the referendum index from events - events.forEach(({ event }) => { - if ( - event.section === 'referenda' && - event.method === 'Submitted' - ) { - const [referendumIndex] = event.data; - console.log( - `Referendum submitted with index: ${referendumIndex}` - ); - } - }); - } else if (status.isFinalized) { - console.log( - `Transaction finalized in blockHash ${status.asFinalized}` - ); - resolve(status.asFinalized); - } - } - ) - .catch(reject); - }); - - console.log('Transaction successful! Hash:', txHash.toHex()); - - await api.disconnect(); - return { - transactionHash: txHash.toHex(), - }; - } catch (error) { - console.error('Error details:', error); - await api.disconnect(); - throw error; - } -} - -// Execute the function -submitReferendum() - .catch(console.error) - .finally(() => process.exit()); diff --git a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/batchCall.md b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/batchCall.md deleted file mode 100644 index 3c3073abc..000000000 --- a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/batchCall.md +++ /dev/null @@ -1,8 +0,0 @@ -
- node batch-calls.js - Individual Calls: - Create Asset Call: 0x3800ffffffffffffffffffffffffffffffff010100e10d121478634d4641404d7920466f726569676e204173736574 - Add Asset Call: 0x3a00010100e10d88130000000000000000000000000000 - Batch Call: - Encoded Batch Call Data: 0x0100083800ffffffffffffffffffffffffffffffff010100e10d121478634d4641404d7920466f726569676e2041737365743a00010100e10d88130000000000000000000000000000 -
\ No newline at end of file diff --git a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/createForeignAsset.md b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/createForeignAsset.md deleted file mode 100644 index 37975b308..000000000 --- a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/createForeignAsset.md +++ /dev/null @@ -1,4 +0,0 @@ -
- node createForeignAsset.js - Encoded Call Data: 0x3800ffffffffffffffffffffffffffffffff010100e10d121478634d4641404d7920466f726569676e204173736574 -
diff --git a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/submitPreimage.md b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/submitPreimage.md deleted file mode 100644 index 2d7670bcb..000000000 --- a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/submitPreimage.md +++ /dev/null @@ -1,12 +0,0 @@ -
- node submit-preimage.js - Account address: 0x569BE8d8b04538318e1722f6e375FD381D2da865 - Submitting preimage for encoded call data: - Original Call Data: 0x0100083800ffffffffffffffffffffffffffffffff010100e10d121478634d4641404d7920466f726569676e2041737365743a00010100e10d88130000000000000000000000000000 - Note Preimage Encoded Call: 0x2c0025010100083800ffffffffffffffffffffffffffffffff010100e10d121478634d4641404d7920466f726569676e2041737365743a00010100e10d88130000000000000000000000000000 - Preimage Hash: 0x2ac24641cebeff3827ba10eb264d2db2990607c89a3fa2c8b2fef6b1e37e35e3 - Transaction included in blockHash 0xf84ef0d3238cbc656e482494778acc9d849f14b5173d34c727a720aee48a6e69 - Transaction finalized in blockHash 0xf84ef0d3238cbc656e482494778acc9d849f14b5173d34c727a720aee48a6e69 - Transaction successful! Hash: 0xf84ef0d3238cbc656e482494778acc9d849f14b5173d34c727a720aee48a6e69 - Preimage hash (save this for reference): 0x2ac24641cebeff3827ba10eb264d2db2990607c89a3fa2c8b2fef6b1e37e35e3 -
\ No newline at end of file diff --git a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/submitProposal.md b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/submitProposal.md deleted file mode 100644 index 98a54cea5..000000000 --- a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/submitProposal.md +++ /dev/null @@ -1,14 +0,0 @@ -
- node submit-referendum.js - Account address: 0x569BE8d8b04538318e1722f6e375FD381D2da865 - Referendum submission details: - Encoded Call: 0x2a002b04022ac24641cebeff3827ba10eb264d2db2990607c89a3fa2c8b2fef6b1e37e35e3490000000164000000 - Current Block: 9150304 - Enactment Block: 9150404 - Preimage Hash: 0x2ac24641cebeff3827ba10eb264d2db2990607c89a3fa2c8b2fef6b1e37e35e3 - Preimage Length: 73 - Transaction included in blockHash 0x13d7f729af6fc803c863b6beba9e2e788f1d85114f5165c41f96b80dfdf49844 - Referendum submitted with index: 79 - Transaction finalized in blockHash 0x13d7f729af6fc803c863b6beba9e2e788f1d85114f5165c41f96b80dfdf49844 - Transaction successful! Hash: 0x13d7f729af6fc803c863b6beba9e2e788f1d85114f5165c41f96b80dfdf49844 -
\ No newline at end of file diff --git a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/weightTrader.md b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/weightTrader.md deleted file mode 100644 index f75b367d5..000000000 --- a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/weightTrader.md +++ /dev/null @@ -1,4 +0,0 @@ -
- node xcmWeightTrader.js - Encoded Call Data: 0x3a00010100e10d88130000000000000000000000000000 -
diff --git a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/weight-trader.js b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/weight-trader.js index aec2a1fb6..142f3c0e4 100644 --- a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/weight-trader.js +++ b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/weight-trader.js @@ -16,7 +16,8 @@ async function getEncodedCallData() { }; // Relative price as u128 - const relativePrice = '5000'; + const relativePrice = 'INSERT-RELATIVE-PRICE'; // Insert value generated + // from the relative price script e.g. 1299476000000000000 try { // Create the call diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index 10e0e6db8..6251743f3 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -55,91 +55,45 @@ With this information in hand, you can prepare a governance proposal to register ### Generate the Encoded Calldata for the Asset Registration {: #generate-encoded-calldata-for-asset-registration } -If you're not familiar with the governance system on Moonbeam, you can find out more information on the [Governance on Moonbeam](/learn/features/governance/){target=\_blank} page. With any governance proposal on Moonbeam, you'll need to submit a preimage, which defines the actions to be executed, and then use the preimage to submit a proposal. +Submitting a governance proposal on Moonbeam requires two steps: first, submit a preimage that defines the actions to be executed, then use that preimage to submit the proposal. For more details, see the [Governance on Moonbeam](/learn/features/governance/){target=\_blank} page. To submit a preimage for asset registration, you'll need the encoded calldata for both the `evmForeignAssets.createForeignAsset` and `xcmWeightTrader.addAsset` extrinsics. -To submit a preimage, you'll need to get the encoded calldata for each extrinsic that you want to execute. As previously mentioned, you'll use the `evmForeignAssets.createForeignAsset` and the `xcmWeightTrader.addAsset` extrinsics. - -Proposals must be submitted via the `GeneralAdmin` track. If you're opening a channel and registering an asset and you'll want to wait until the channel is established prior to attempting to register the asset. - -To get the encoded calldata for the `evmForeignAssets.createForeignAsset` extrinsic, you will need to provide the following arguments: +Proposals must be submitted via the `GeneralAdmin` track. If you're opening a channel and registering an asset and you'll want to wait until the channel is established prior to attempting to register the asset. To get the encoded calldata for the `evmForeignAssets.createForeignAsset` extrinsic, you will need to provide the following arguments: - `assetId` - unique identifier of the asset - `xcmLocation` - the multilocation of the asset relative to Moonbeam - `decimals` - the number of decimals of the asset -- `symbol` - the symbol of the asset. **Remember that "xc" should be prepended to the symbol to indicate the asset is an XCM-enabled asset** +- `symbol` - the symbol of the asset. Remember that "xc" should be prepended to the symbol to indicate the asset is an XCM-enabled asset - `name` - The asset name -You can use the script below to generate the encoded call data for the `createForeignAsset` call. Remember to replace the example parameter values shown in the script with the ones relevant to your asset. - -???+ code "Get encoded call data for createForeignAsset" - ```typescript - --8<-- 'code/builders/interoperability/xcm/xc-registration/assets/create-foreign-asset.js' - ``` - -The resulting output will be something like: - ---8<-- 'code/builders/interoperability/xcm/xc-registration/assets/terminal/createForeignAsset.md' +Using the above information, you can generate the encoded call data for the `createForeignAsset` call either via the Polkadot API or on [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fwss.api.moonbeam.network#/extrinsics){target=\_blank}. To get the encoded calldata for the `xcmWeightTrader.addAsset` extrinsic, you will need to provide the following arguments: - `xcmLocation` - the multilocation of the asset relative to Moonbeam -- `relativePrice` - the cost of an asset in terms of weight, used to determine how much of the asset is required to cover the fees for cross-chain (XCM) operations. It is calculated by comparing the asset's value to the network's native token in terms of the weight-to-fee conversion - -You can use the script below to generate the encoded call data for the `addAsset` call. Remember to replace the example parameter values shown in the script with the ones relevant to your asset. - -??? code "Get encoded call data for xcmWeightTrader" - ```typescript - --8<-- 'code/builders/interoperability/xcm/xc-registration/assets/weight-trader.js' - ``` - -The resulting output will be something like: - ---8<-- 'code/builders/interoperability/xcm/xc-registration/assets/terminal/weightTrader.md' +- `relativePrice` - A numeric value (u128) that represents the amount of a non-native asset needed to equal the value of one unit of the network's native token (e.g., GLMR), expressed with 18 decimal places. This value is used to calculate cross-chain transaction fees by determining how much of the non-native asset is required to cover XCM operation costs. For example, if an asset is worth half as much as the native token, its `relativePrice` would be `500,000,000,000,000,000` (to represent 0.5 with 18 decimal places) -To create a batch transaction that combines both the `xcmWeightTrader.addAsset` and the `evmForeignAssets.createForeignAsset` calls together, you can use the following script. Remember to replace the example parameter values shown in the script with the ones relevant to your asset. +You can use the following script (also available as part of [XCM-tools](https://github.com/Moonsong-Labs/xcm-tools){target=\_blank} ) to calculate the correct `relativePrice` value for your asset. -??? code "Get encoded call data for batch call" +??? code "Calculate Relative Price" ```typescript - --8<-- 'code/builders/interoperability/xcm/xc-registration/assets/batch-calls.js' + --8<-- 'code/builders/interoperability/xcm/xc-registration/assets/calculate-relative-price.ts' ``` -The resulting output will be something like: +Using the above information, you can generate the encoded call data for the `addAsset` call either via the Polkadot API or on [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fwss.api.moonbeam.network#/extrinsics){target=\_blank}. ---8<-- 'code/builders/interoperability/xcm/xc-registration/assets/terminal/batchCall.md' +To create a batch transaction that combines both the `xcmWeightTrader.addAsset` and the `evmForeignAssets.createForeignAsset` calls together, you can use the [Polkadot API's Batch Method](/builders/substrate/libraries/polkadot-js-api/#batching-transactions){target=\_blank}. -### Programmatically Submit the Preimage and Proposal for Asset Registration {: #submit-preimage-proposal } +### Submit the Preimage and Proposal for Asset Registration {: #submit-preimage-proposal } -You can programmatically submit the preimage of your batched call containing both the `xcmWeightTrader.addAsset` and the `evmForeignAssets.createForeignAsset` calls as shown in the following script. As this is an on-chain transaction, you'll need to provide a wallet. (Never store your private keys in a javascript file - this is provided for demonstration purposes only). Remember to replace the encoded call data with your asset's relevant batch call. You can also adapt this script for a different network. - -??? code "Submit preimage for batch call" - ```typescript - --8<-- 'code/builders/interoperability/xcm/xc-registration/assets/submit-preimage.js' - ``` - -The resulting output will be something like: - ---8<-- 'code/builders/interoperability/xcm/xc-registration/assets/terminal/submitPreimage.md' +Your next task is to submit the preimage of your batched call containing both the `xcmWeightTrader.addAsset` and the `evmForeignAssets.createForeignAsset` by following the guidelines in the [Submit a Democracy Proposal Guide](/tokens/governance/proposals/#submitting-a-preimage-of-the-proposal){target=\_blank}. For Moonbase Alpha, you do not need to go through governance, as Moonbase Alpha has `sudo` access. Instead, you can provide the output of the batch call data to the Moonbeam team, and the Moonbeam Team can submit the call with `sudo`. This will be a faster and easier process than going through governance. However, you may still wish to go through governance on Moonbase Alpha in order to prepare for the governance process on Moonbeam. -After submitting the preimage, you can submit the proposal as follows: - -??? code "Submit proposal for batch call" - ```typescript - --8<-- 'code/builders/interoperability/xcm/xc-registration/assets/submit-proposal.js' - ``` - -The resulting output will be something like: - ---8<-- 'code/builders/interoperability/xcm/xc-registration/assets/terminal/submitProposal.md' +After submitting the preimage, you can submit the proposal by following the guidelines in the [Submitting a Proposal](/tokens/governance/proposals/#submitting-a-proposal-v2){target=\_blank} section ### Test the Asset Registration on Moonbeam {: #test-asset-registration } -After your asset is registered, the team will provide the asset ID and the [XC-20 precompile](/builders/interoperability/xcm/xc20/interact/#the-erc20-interface){target=\_blank} address. - -Your XC-20 precompile address is calculated by converting the asset ID decimal number to hex and prepending it with F's until you get a 40-hex character (plus the “0x”) address. For more information on how it is calculated, please refer to the [Calculate External XC-20 Precompile Addresses](/builders/interoperability/xcm/xc20/interact/#calculate-xc20-address){target=\_blank} section of the External XC-20 guide. - -After the asset is successfully registered, you can transfer tokens from your parachain to the Moonbeam-based network you are integrating with. +After your asset is registered, the team will provide the asset ID and the [XC-20 precompile](/builders/interoperability/xcm/xc20/interact/#the-erc20-interface){target=\_blank} address. Your XC-20 precompile address is calculated by converting the asset ID decimal number to hex and prepending it with F's until you get a 40-hex character (plus the “0x”) address. For more information on how it is calculated, please refer to the [Calculate External XC-20 Precompile Addresses](/builders/interoperability/xcm/xc20/interact/#calculate-xc20-address){target=\_blank} section of the External XC-20 guide. After the asset is successfully registered, you can transfer tokens from your parachain to the Moonbeam-based network you are integrating with. !!! note Remember that Moonbeam-based networks use AccountKey20 (Ethereum-style addresses). From 0561cd760ccbefe4b5de87113a53d3710d00444b Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Tue, 14 Jan 2025 17:33:51 -0800 Subject: [PATCH 13/64] add --- builders/interoperability/xcm/xc-registration/assets.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index 6251743f3..474cdc36c 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -358,4 +358,8 @@ You can update the multilocation of an asset with the `evmForeignAssets.changeXc ### Freezing a Foreign Asset {: #freezing-a--foreign-asset } -You can freeze a foreign asset by calling `evmForeignAssets.freezeForeignAsset`, which takes as parameters the `assetId` and an `allowXcmDeposit` boolean. If set to true, XCM deposits from remote chains will still be allowed and mint tokens. If set to false, XCM deposits from remote chains will fail as no minting will be permitted. \ No newline at end of file +You can freeze a foreign asset by calling `evmForeignAssets.freezeForeignAsset`, which takes as parameters the `assetId` and an `allowXcmDeposit` boolean. If set to true, XCM deposits from remote chains will still be allowed and mint tokens. If set to false, XCM deposits from remote chains will fail as no minting will be permitted. + +### Paying XCM Fees with Foreign Assets {: #paying-xcm-fees-with-foreign-assets } + +After you've registered the foreign asset via the `evmForeignAssets` and the `xcmWeightTrader` pallet, your asset will now be among the supported assets for paying XCM fees. To verify, you can query the `xcmWeightTrader` pallet and the `supportedAssets` chain state query. Toggle the **Include Option** slider off to see the complete list, or, you can filter the list by the multilocation of your asset. \ No newline at end of file From 33c1390b078884152526b8675032bc5bb9c7f977 Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Thu, 23 Jan 2025 11:37:40 -0800 Subject: [PATCH 14/64] rev --- .../assets/calculate-relative-price.ts | 186 ++++++++++-------- 1 file changed, 99 insertions(+), 87 deletions(-) diff --git a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/calculate-relative-price.ts b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/calculate-relative-price.ts index 945a76cf8..1e6af44c2 100644 --- a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/calculate-relative-price.ts +++ b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/calculate-relative-price.ts @@ -1,109 +1,121 @@ -import axios from 'axios'; -import chalk from 'chalk'; +import axios from "axios"; // CoinGecko IDs for the networks const NETWORK_IDS = { - GLMR: 'moonbeam', - MOVR: 'moonriver' + GLMR: "moonbeam", + MOVR: "moonriver", }; async function calculateRelativePrice( - assetPrice: number, - network: 'GLMR' | 'MOVR' + assetPrice: number, + network: "GLMR" | "MOVR" ): Promise { - try { - // Fetch the native token price from CoinGecko - const response = await axios.get( - `https://api.coingecko.com/api/v3/simple/price?ids=${NETWORK_IDS[network]}&vs_currencies=usd` - ); - - const nativeTokenPrice = response.data[NETWORK_IDS[network]].usd; - - // Calculate relative price with 18 decimal places - // Formula: (nativeTokenPrice / assetPrice) * 10^18 - // This gives us how many units of the asset we need to equal 1 unit of native token - const relativePrice = (nativeTokenPrice / assetPrice) * Math.pow(10, 18); - - // Return as string to preserve precision - return relativePrice.toFixed(0); - - } catch (error) { - if (error instanceof Error) { - throw new Error(`Failed to calculate relative price: ${error.message}`); - } - throw error; + try { + // Fetch the native token price from CoinGecko + const response = await axios.get( + `https://api.coingecko.com/api/v3/simple/price?ids=${NETWORK_IDS[network]}&vs_currencies=usd` + ); + + const nativeTokenPrice = response.data[NETWORK_IDS[network]].usd; + + // Calculate relative price with 18 decimal places + // Formula: (nativeTokenPrice / assetPrice) * 10^18 + // This gives us how many units of the asset we need to equal 1 unit of native token + const relativePrice = (nativeTokenPrice / assetPrice) * Math.pow(10, 18); + + // Return as string to preserve precision + return relativePrice.toFixed(0); + } catch (error) { + if (error instanceof Error) { + throw new Error(`Failed to calculate relative price: ${error.message}`); } + throw error; + } } -function validateInput(price: string, network: string): { assetPrice: number; network: 'GLMR' | 'MOVR' } { - // Validate price - const assetPrice = parseFloat(price); - if (isNaN(assetPrice) || assetPrice <= 0) { - throw new Error('Price must be a positive number'); - } +function validateInput( + price: string, + network: string +): { assetPrice: number; network: "GLMR" | "MOVR" } { + // Validate price + const assetPrice = parseFloat(price); + if (isNaN(assetPrice) || assetPrice <= 0) { + throw new Error("Price must be a positive number"); + } - // Validate network - const upperNetwork = network.toUpperCase() as 'GLMR' | 'MOVR'; - if (!['GLMR', 'MOVR'].includes(upperNetwork)) { - throw new Error('Network must be either GLMR or MOVR'); - } + // Validate network + const upperNetwork = network.toUpperCase() as "GLMR" | "MOVR"; + if (!["GLMR", "MOVR"].includes(upperNetwork)) { + throw new Error("Network must be either GLMR or MOVR"); + } - return { assetPrice, network: upperNetwork }; + return { assetPrice, network: upperNetwork }; } function printUsage() { - console.log('\nUsage:'); - console.log('npx ts-node relative-price-calculator.ts '); - console.log('\nExample:'); - console.log('npx ts-node relative-price-calculator.ts 0.25 GLMR'); - console.log('\nParameters:'); - console.log('price - The price of your asset in USD'); - console.log('network - Either GLMR or MOVR'); + console.log("\nUsage:"); + console.log("npx ts-node relative-price-calculator.ts "); + console.log("\nExample:"); + console.log("npx ts-node relative-price-calculator.ts 0.25 GLMR"); + console.log("\nParameters:"); + console.log("price - The price of your asset in USD"); + console.log("network - Either GLMR or MOVR"); } async function main() { - try { - // Get command line arguments - const [,, price, network] = process.argv; - - // Check if help flag is passed - if (price === '--help' || price === '-h') { - printUsage(); - return; - } - - // Check if required arguments are provided - if (!price || !network) { - console.error('Error: Missing required arguments'); - printUsage(); - process.exit(1); - } - - // Validate inputs - const { assetPrice, network: validNetwork } = validateInput(price, network); - - console.log(`\nCalculating relative price for asset worth $${assetPrice} against ${validNetwork}...`); - const relativePrice = await calculateRelativePrice(assetPrice, validNetwork); - const nativeTokenPrice = (await axios.get( - `https://api.coingecko.com/api/v3/simple/price?ids=${NETWORK_IDS[validNetwork]}&vs_currencies=usd` - )).data[NETWORK_IDS[validNetwork]].usd; - - const decimalRatio = nativeTokenPrice / assetPrice; - - console.log(`\nResults:`); - console.log(`Asset Price: $${assetPrice}`); - console.log(`Network: ${validNetwork}`); - console.log(`Native Token Price (from CoinGecko): $${nativeTokenPrice}`); - console.log(`\nRelative Price Analysis:`); - console.log(`1 ${validNetwork} is equal to approximately ${decimalRatio.toFixed(3)} of your specified token.`); - console.log(`With 18 decimals, 1 ${validNetwork} or in WEI, 1000000000000000000 is equal to a relative price of ${relativePrice} units of your token`); - console.log(chalk.bold(`\nRelative Price: ${relativePrice}`)); - console.log(`\nThe relative price you should specify in asset registration steps is ${relativePrice}\n`); - - } catch (error) { - console.error('\nError:', error instanceof Error ? error.message : error); - process.exit(1); + try { + // Get command line arguments + const [, , price, network] = process.argv; + + // Check if help flag is passed + if (price === "--help" || price === "-h") { + printUsage(); + return; } + + // Check if required arguments are provided + if (!price || !network) { + console.error("Error: Missing required arguments"); + printUsage(); + process.exit(1); + } + + // Validate inputs + const { assetPrice, network: validNetwork } = validateInput(price, network); + + console.log( + `\nCalculating relative price for asset worth $${assetPrice} against ${validNetwork}...` + ); + const relativePrice = await calculateRelativePrice(assetPrice, validNetwork); + const nativeTokenPrice = ( + await axios.get( + `https://api.coingecko.com/api/v3/simple/price?ids=${NETWORK_IDS[validNetwork]}&vs_currencies=usd` + ) + ).data[NETWORK_IDS[validNetwork]].usd; + + const decimalRatio = nativeTokenPrice / assetPrice; + + console.log(`\nResults:`); + console.log(`Asset Price: $${assetPrice}`); + console.log(`Network: ${validNetwork}`); + console.log(`Native Token Price (from CoinGecko): $${nativeTokenPrice}`); + console.log(`\nRelative Price Analysis:`); + console.log( + `1 ${validNetwork} is equal to approximately ${decimalRatio.toFixed( + 3 + )} of your specified token.` + ); + console.log( + `With 18 decimals, 1 ${validNetwork} or in WEI, 1000000000000000000 is equal to a relative price of ${relativePrice} units of your token` + ); + console.log(`\nRelative Price: ${relativePrice}`); + console.log( + `\nThe relative price you should specify in asset registration steps is ${relativePrice}\n` + ); + } catch (error) { + console.error("\nError:", error instanceof Error ? error.message : error); + process.exit(1); + } } main(); \ No newline at end of file From e01b31637e522d63c8346b7ff50d55b5f63690e2 Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Thu, 23 Jan 2025 11:48:51 -0800 Subject: [PATCH 15/64] clarify asset ID creation process --- builders/interoperability/xcm/xc-registration/assets.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index 474cdc36c..0019001b2 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -43,7 +43,7 @@ To register an asset native to another chain on Moonbeam, you'll need to submit To get started, you'll need to collect some information about the asset: -- `assetId`: unique identifier of the asset +- `assetId`: unique identifier of the asset. This can be any unique arbitrary integer, but it's recommended that you create this using the [`calculate-external-asset-info.ts`](https://github.com/Moonsong-Labs/xcm-tools/blob/main/scripts/calculate-external-asset-info.ts){target=\_blank} script. This provides a standardized way to generate a unique `assetId` - `xcmLocation`: a scale encoded xcm v4 multilocation of asset reserve relative to Moonbeam - The asset name - The asset symbol. You'll need to prepend "xc" to the asset symbol to indicate that the asset is an XCM-enabled asset @@ -59,7 +59,7 @@ Submitting a governance proposal on Moonbeam requires two steps: first, submit a Proposals must be submitted via the `GeneralAdmin` track. If you're opening a channel and registering an asset and you'll want to wait until the channel is established prior to attempting to register the asset. To get the encoded calldata for the `evmForeignAssets.createForeignAsset` extrinsic, you will need to provide the following arguments: -- `assetId` - unique identifier of the asset +- `assetId` - unique identifier of the asset, generated from the [`calculate-external-asset-info.ts`](https://github.com/Moonsong-Labs/xcm-tools/blob/main/scripts/calculate-external-asset-info.ts){target=\_blank} script - `xcmLocation` - the multilocation of the asset relative to Moonbeam - `decimals` - the number of decimals of the asset - `symbol` - the symbol of the asset. Remember that "xc" should be prepended to the symbol to indicate the asset is an XCM-enabled asset From a1aff3e029e5cc8c8f56f564ea4505934f1ff024 Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Fri, 24 Jan 2025 09:21:57 -0800 Subject: [PATCH 16/64] update relative price --- .../xcm/xc-registration/assets/calculate-relative-price.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/calculate-relative-price.ts b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/calculate-relative-price.ts index 1e6af44c2..ad9c41d3e 100644 --- a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/calculate-relative-price.ts +++ b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/calculate-relative-price.ts @@ -19,9 +19,9 @@ async function calculateRelativePrice( const nativeTokenPrice = response.data[NETWORK_IDS[network]].usd; // Calculate relative price with 18 decimal places - // Formula: (nativeTokenPrice / assetPrice) * 10^18 + // Formula: (assetPrice / nativeTokenPrice) * 10^18 // This gives us how many units of the asset we need to equal 1 unit of native token - const relativePrice = (nativeTokenPrice / assetPrice) * Math.pow(10, 18); + const relativePrice = ( assetPrice / nativeTokenPrice ) * Math.pow(10, 18); // Return as string to preserve precision return relativePrice.toFixed(0); @@ -118,4 +118,4 @@ async function main() { } } -main(); \ No newline at end of file +main(); From ca00d3aa43211d3c69858aac52c81f05bf863d2b Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Fri, 24 Jan 2025 09:41:30 -0800 Subject: [PATCH 17/64] clarify relative price etc --- builders/interoperability/xcm/xc-registration/assets.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index 0019001b2..2484f16e2 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -70,7 +70,7 @@ Using the above information, you can generate the encoded call data for the `cre To get the encoded calldata for the `xcmWeightTrader.addAsset` extrinsic, you will need to provide the following arguments: - `xcmLocation` - the multilocation of the asset relative to Moonbeam -- `relativePrice` - A numeric value (u128) that represents the amount of a non-native asset needed to equal the value of one unit of the network's native token (e.g., GLMR), expressed with 18 decimal places. This value is used to calculate cross-chain transaction fees by determining how much of the non-native asset is required to cover XCM operation costs. For example, if an asset is worth half as much as the native token, its `relativePrice` would be `500,000,000,000,000,000` (to represent 0.5 with 18 decimal places) +- `relativePrice` - A numeric value (u128) representing the fraction of the native token’s price that your asset’s price constitutes, scaled to 18 decimals. This value is used to calculate cross-chain fees by determining how many units of the non-native asset are required to cover XCM operation costs. For example, if the chosen asset is priced at exactly half the native token’s price (GLMR or MOVR), then `relativePrice` = `assetPrice` / `nativeTokenPrice` = `0.5`. Then, this figure must be multiplied by 10^18 to generate an 18-decimal integer of `500,000,000,000,000,000` You can use the following script (also available as part of [XCM-tools](https://github.com/Moonsong-Labs/xcm-tools){target=\_blank} ) to calculate the correct `relativePrice` value for your asset. @@ -81,7 +81,7 @@ You can use the following script (also available as part of [XCM-tools](https:// Using the above information, you can generate the encoded call data for the `addAsset` call either via the Polkadot API or on [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fwss.api.moonbeam.network#/extrinsics){target=\_blank}. -To create a batch transaction that combines both the `xcmWeightTrader.addAsset` and the `evmForeignAssets.createForeignAsset` calls together, you can use the [Polkadot API's Batch Method](/builders/substrate/libraries/polkadot-js-api/#batching-transactions){target=\_blank}. +To create a batch transaction that combines both the `xcmWeightTrader.addAsset` and the `evmForeignAssets.createForeignAsset` calls together, you can use the [Polkadot API's Batch Method](/builders/substrate/libraries/polkadot-js-api/#batching-transactions){target=\_blank}. The [XCM Asset Registrator](https://github.com/Moonsong-Labs/xcm-tools/blob/main/scripts/xcm-asset-registrator.ts){target=\_blank} script can help you build and submit the required calls. ### Submit the Preimage and Proposal for Asset Registration {: #submit-preimage-proposal } From e58fc111ed86d2b4f4a4d9a80dc9b5ee828b0205 Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Fri, 24 Jan 2025 09:45:27 -0800 Subject: [PATCH 18/64] rev --- builders/interoperability/xcm/xc-registration/assets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index 2484f16e2..45bbeab0c 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -81,7 +81,7 @@ You can use the following script (also available as part of [XCM-tools](https:// Using the above information, you can generate the encoded call data for the `addAsset` call either via the Polkadot API or on [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fwss.api.moonbeam.network#/extrinsics){target=\_blank}. -To create a batch transaction that combines both the `xcmWeightTrader.addAsset` and the `evmForeignAssets.createForeignAsset` calls together, you can use the [Polkadot API's Batch Method](/builders/substrate/libraries/polkadot-js-api/#batching-transactions){target=\_blank}. The [XCM Asset Registrator](https://github.com/Moonsong-Labs/xcm-tools/blob/main/scripts/xcm-asset-registrator.ts){target=\_blank} script can help you build and submit the required calls. +To create a batch transaction that combines both the `xcmWeightTrader.addAsset` and the `evmForeignAssets.createForeignAsset` calls together, you can use the [Polkadot API's Batch Method](/builders/substrate/libraries/polkadot-js-api/#batching-transactions){target=\_blank}. Additionally, the [XCM Asset Registrator](https://github.com/Moonsong-Labs/xcm-tools/blob/main/scripts/xcm-asset-registrator.ts){target=\_blank} script can help you build and submit the required calls. ### Submit the Preimage and Proposal for Asset Registration {: #submit-preimage-proposal } From ac805474118fb42b3b05b0fddd901b2f49f588b0 Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Fri, 24 Jan 2025 10:08:32 -0800 Subject: [PATCH 19/64] rev --- builders/interoperability/xcm/xc-registration/assets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index 45bbeab0c..df945d7d3 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -89,7 +89,7 @@ Your next task is to submit the preimage of your batched call containing both th For Moonbase Alpha, you do not need to go through governance, as Moonbase Alpha has `sudo` access. Instead, you can provide the output of the batch call data to the Moonbeam team, and the Moonbeam Team can submit the call with `sudo`. This will be a faster and easier process than going through governance. However, you may still wish to go through governance on Moonbase Alpha in order to prepare for the governance process on Moonbeam. -After submitting the preimage, you can submit the proposal by following the guidelines in the [Submitting a Proposal](/tokens/governance/proposals/#submitting-a-proposal-v2){target=\_blank} section +After submitting the preimage, you can submit the proposal by following the guidelines in the [Submitting a Proposal](/tokens/governance/proposals/#submitting-a-proposal-v2){target=\_blank} section. ### Test the Asset Registration on Moonbeam {: #test-asset-registration } From 41df3b755facc9e87722e145adb7d96a753ddc7b Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Wed, 29 Jan 2025 10:16:04 -0800 Subject: [PATCH 20/64] Update builders/interoperability/xcm/xc-registration/assets.md Co-authored-by: Lucas Malizia <131050418+0xlukem@users.noreply.github.com> --- builders/interoperability/xcm/xc-registration/assets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index df945d7d3..25f854e5d 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -43,7 +43,7 @@ To register an asset native to another chain on Moonbeam, you'll need to submit To get started, you'll need to collect some information about the asset: -- `assetId`: unique identifier of the asset. This can be any unique arbitrary integer, but it's recommended that you create this using the [`calculate-external-asset-info.ts`](https://github.com/Moonsong-Labs/xcm-tools/blob/main/scripts/calculate-external-asset-info.ts){target=\_blank} script. This provides a standardized way to generate a unique `assetId` +- `assetId` - unique identifier of the asset. This can be any unique arbitrary integer, but it's recommended that you create this using the [`calculate-external-asset-info.ts`](https://github.com/Moonsong-Labs/xcm-tools/blob/main/scripts/calculate-external-asset-info.ts){target=\_blank} script. This provides a standardized way to generate a unique `assetId` - `xcmLocation`: a scale encoded xcm v4 multilocation of asset reserve relative to Moonbeam - The asset name - The asset symbol. You'll need to prepend "xc" to the asset symbol to indicate that the asset is an XCM-enabled asset From 8086a121b5371d90d2beb9ad26b47ce02cece2b8 Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Wed, 29 Jan 2025 10:16:11 -0800 Subject: [PATCH 21/64] Update builders/interoperability/xcm/xc-registration/assets.md Co-authored-by: Lucas Malizia <131050418+0xlukem@users.noreply.github.com> --- builders/interoperability/xcm/xc-registration/assets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index 25f854e5d..87a130e51 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -44,7 +44,7 @@ To register an asset native to another chain on Moonbeam, you'll need to submit To get started, you'll need to collect some information about the asset: - `assetId` - unique identifier of the asset. This can be any unique arbitrary integer, but it's recommended that you create this using the [`calculate-external-asset-info.ts`](https://github.com/Moonsong-Labs/xcm-tools/blob/main/scripts/calculate-external-asset-info.ts){target=\_blank} script. This provides a standardized way to generate a unique `assetId` -- `xcmLocation`: a scale encoded xcm v4 multilocation of asset reserve relative to Moonbeam +- `xcmLocation` - a scale encoded xcm v4 multilocation of asset reserve relative to Moonbeam - The asset name - The asset symbol. You'll need to prepend "xc" to the asset symbol to indicate that the asset is an XCM-enabled asset - The number of decimals the asset has From cfdea7985464ac03d12b4fb963ce3c14fdfb990d Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Wed, 29 Jan 2025 14:11:13 -0800 Subject: [PATCH 22/64] update relative price script --- .../assets/calculate-relative-price.ts | 43 +++++++++++++------ 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/calculate-relative-price.ts b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/calculate-relative-price.ts index ad9c41d3e..b618f3a35 100644 --- a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/calculate-relative-price.ts +++ b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/calculate-relative-price.ts @@ -8,8 +8,9 @@ const NETWORK_IDS = { async function calculateRelativePrice( assetPrice: number, + assetDecimals: number, network: "GLMR" | "MOVR" -): Promise { +): Promise { try { // Fetch the native token price from CoinGecko const response = await axios.get( @@ -21,10 +22,12 @@ async function calculateRelativePrice( // Calculate relative price with 18 decimal places // Formula: (assetPrice / nativeTokenPrice) * 10^18 // This gives us how many units of the asset we need to equal 1 unit of native token - const relativePrice = ( assetPrice / nativeTokenPrice ) * Math.pow(10, 18); + const relativePrice = BigInt( + 0.175 * Math.pow(10, 18 - assetDecimals) * (assetPrice / nativeTokenPrice) * Math.pow(10, 18) + ); // Return as string to preserve precision - return relativePrice.toFixed(0); + return relativePrice; } catch (error) { if (error instanceof Error) { throw new Error(`Failed to calculate relative price: ${error.message}`); @@ -35,37 +38,45 @@ async function calculateRelativePrice( function validateInput( price: string, + decimals: string, network: string -): { assetPrice: number; network: "GLMR" | "MOVR" } { +): { assetPrice: number; assetDecimals: number; network: "GLMR" | "MOVR" } { // Validate price const assetPrice = parseFloat(price); if (isNaN(assetPrice) || assetPrice <= 0) { throw new Error("Price must be a positive number"); } + // Validate decimals + const assetDecimals = parseFloat(decimals); + if (isNaN(assetDecimals) || assetDecimals <= 0) { + throw new Error("Decimals must be a positive number"); + } + // Validate network const upperNetwork = network.toUpperCase() as "GLMR" | "MOVR"; if (!["GLMR", "MOVR"].includes(upperNetwork)) { throw new Error("Network must be either GLMR or MOVR"); } - return { assetPrice, network: upperNetwork }; + return { assetPrice, assetDecimals, network: upperNetwork }; } function printUsage() { console.log("\nUsage:"); - console.log("npx ts-node relative-price-calculator.ts "); + console.log("npx ts-node calculate-relative-price.ts "); console.log("\nExample:"); - console.log("npx ts-node relative-price-calculator.ts 0.25 GLMR"); + console.log("npx ts-node calculate-relative-price.ts 0.25 12 GLMR"); console.log("\nParameters:"); - console.log("price - The price of your asset in USD"); - console.log("network - Either GLMR or MOVR"); + console.log("price - The price of your asset in USD"); + console.log("decimals - The decimals of your asset"); + console.log("network - Either GLMR or MOVR"); } async function main() { try { // Get command line arguments - const [, , price, network] = process.argv; + const [, , price, decimals, network] = process.argv; // Check if help flag is passed if (price === "--help" || price === "-h") { @@ -74,19 +85,23 @@ async function main() { } // Check if required arguments are provided - if (!price || !network) { + if (!price || !decimals || !network) { console.error("Error: Missing required arguments"); printUsage(); process.exit(1); } // Validate inputs - const { assetPrice, network: validNetwork } = validateInput(price, network); + const { + assetPrice, + assetDecimals, + network: validNetwork, + } = validateInput(price, decimals, network); console.log( `\nCalculating relative price for asset worth $${assetPrice} against ${validNetwork}...` ); - const relativePrice = await calculateRelativePrice(assetPrice, validNetwork); + const relativePrice = await calculateRelativePrice(assetPrice, assetDecimals, validNetwork); const nativeTokenPrice = ( await axios.get( `https://api.coingecko.com/api/v3/simple/price?ids=${NETWORK_IDS[validNetwork]}&vs_currencies=usd` @@ -118,4 +133,4 @@ async function main() { } } -main(); +main(); \ No newline at end of file From b46357970ffa4686f2522583f6d3e043ccaf8d62 Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Wed, 29 Jan 2025 16:54:18 -0800 Subject: [PATCH 23/64] clarify relative price calculation with steps etc --- .../terminal/calculate-relative-price.md | 18 +++++ .../xcm/xc-registration/assets.md | 68 +++++++++++++++++-- 2 files changed, 80 insertions(+), 6 deletions(-) create mode 100644 .snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/calculate-relative-price.md diff --git a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/calculate-relative-price.md b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/calculate-relative-price.md new file mode 100644 index 000000000..c16f4480d --- /dev/null +++ b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/calculate-relative-price.md @@ -0,0 +1,18 @@ +
+ npx ts-node calculate-relative-price.ts 0.25 12 GLMR + + Calculating relative price for asset worth $0.25 against GLMR... + + Results: + Asset Price: $0.25 + Network: GLMR + Native Token Price (from CoinGecko): $0.1599 + + Relative Price Analysis: + 1 GLMR is equal to approximately 0.640 of your specified token. + With 18 decimals, 1 GLMR or in WEI, 1000000000000000000 is equal to a relative price of 273608505315822372126720 units of your token + + Relative Price: 273608505315822372126720 + + The relative price you should specify in asset registration steps is 273608505315822372126720 +
\ No newline at end of file diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index 87a130e51..71125be23 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -53,6 +53,68 @@ With this information in hand, you can prepare a governance proposal to register ![Overview of the proposal process](/images/builders/interoperability/xcm/xc-registration/assets/assets-3.webp) +### Calculate Relative Price {: #calculate-relative-price } + +An asset's `relativePrice` refers to a `u128` value that indicates how many units of said asset (in its smallest denomination) equate to one unit**—i.e., `1 × 10^18 wei`—of the native token (GLMR or MOVR). This helps determine how much of your asset to use for fees originally quoted in the native token, particularly in cross-chain messaging (XCM). + +You can use the following script (also available as part of [XCM-tools](https://github.com/Moonsong-Labs/xcm-tools){target=\_blank} ) to calculate the correct `relativePrice` value for your asset. + +??? code "Calculate Relative Price" + ```typescript + --8<-- 'code/builders/interoperability/xcm/xc-registration/assets/calculate-relative-price.ts' + ``` + +If you're in a hurry, you can input the required values and continue on your way. The next section will cover additional background information on relative price and how its calculated. + +Only three parameters are required to calculate the relative price of an asset: + +- Asset Price (USD): A positive number representing how much 1 unit (in human-readable form) of your asset costs in USD +- Asset Decimals: The number of decimal places your asset uses. For example, if your token has 12 decimals, specify 12 +- Network: Either GLMR (Moonbeam) or MOVR (Moonriver). This should correspond to the network that you're registering the asset on, and this determines which native token’s USD price the script will fetch from CoinGecko + +First, ensure that you've installed the required dependencies by running: + +```bash +npm install +``` + +Execute the script: + +```bash +npx ts-node calculate-relative-price.ts INSERT_ASSET_PRICE INSERT_DECIMALS GLMR +``` + +For example, if the asset you're registering has a USD price of $0.25 and 12 decimals and you're registering the asset on the Moonbeam network, you would run: + +```bash +npx ts-node calculate-relative-price.ts 0.25 12 GLMR +``` + +This instructs the script to calculate how many smallest units of an asset (priced at $0.25, with 12 decimals) correspond to 1 GLMR token. + +--8<-- 'code/builders/interoperability/xcm/xc-registration/assets/terminal/calculate-relative-price.md' + +Upon successful execution, the script prints the computed `relativePrice` as a `BigInt`. This value represents the scaled ratio between the asset’s USD price and the native token’s USD price, multiplied up to 18 decimals. You can then use this result in on-chain asset registration or fee calculation scenarios—especially where a `u128` 18-decimal format is required. + +For additional info, usage details, or to see an example in action, you can invoke the help command by running: + +```bash +npx ts-node calculate-relative-price.ts --help +``` + +### How Relative Price is Constructed + +If you're not interested in the mechanics of the relative price feel free to skip this section. The relative price calculation script performs the following steps: + +1. Fetch the native token price (GLMR or MOVR) from CoinGecko (in USD) +2. Calculate the ratio of `assetPrice` / `nativeTokenPrice` +3. Multiply that ratio by `0.175`. This factor intentionally overestimates the relative price by ~5–6× to provide a buffer against market fluctuations +4. Multiply by `10 ^ (18 - `assetDecimals`). For example, if the asset uses 12 decimals, you’d multiply by 10^(18 - 12) = 10^6. This accounts for any difference between your asset’s decimals and the 18 decimals used by the native token +5. Multiply by `10^18`. This final step scales everything up to 18 decimals (the common WEI format) +6. Convert to `BigInt` + +Why is there a `0.175` Factor? The main reason why we don't take the direct relative price of asset price / native token price is to provide a buffer for volatility. Market prices can shift rapidly. An exact 1:1 ratio might under-collect fees if prices move unexpectedly. The `0.175` provides for an approximate 5x overestimation. Generally speaking, the fees are expected to be extremely low so the `5x` multiplier, while a conservative overestimate, is not meant to be unduly burdensome. + ### Generate the Encoded Calldata for the Asset Registration {: #generate-encoded-calldata-for-asset-registration } Submitting a governance proposal on Moonbeam requires two steps: first, submit a preimage that defines the actions to be executed, then use that preimage to submit the proposal. For more details, see the [Governance on Moonbeam](/learn/features/governance/){target=\_blank} page. To submit a preimage for asset registration, you'll need the encoded calldata for both the `evmForeignAssets.createForeignAsset` and `xcmWeightTrader.addAsset` extrinsics. @@ -72,12 +134,6 @@ To get the encoded calldata for the `xcmWeightTrader.addAsset` extrinsic, you wi - `xcmLocation` - the multilocation of the asset relative to Moonbeam - `relativePrice` - A numeric value (u128) representing the fraction of the native token’s price that your asset’s price constitutes, scaled to 18 decimals. This value is used to calculate cross-chain fees by determining how many units of the non-native asset are required to cover XCM operation costs. For example, if the chosen asset is priced at exactly half the native token’s price (GLMR or MOVR), then `relativePrice` = `assetPrice` / `nativeTokenPrice` = `0.5`. Then, this figure must be multiplied by 10^18 to generate an 18-decimal integer of `500,000,000,000,000,000` -You can use the following script (also available as part of [XCM-tools](https://github.com/Moonsong-Labs/xcm-tools){target=\_blank} ) to calculate the correct `relativePrice` value for your asset. - -??? code "Calculate Relative Price" - ```typescript - --8<-- 'code/builders/interoperability/xcm/xc-registration/assets/calculate-relative-price.ts' - ``` Using the above information, you can generate the encoded call data for the `addAsset` call either via the Polkadot API or on [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fwss.api.moonbeam.network#/extrinsics){target=\_blank}. From 2eb4e22f01e6a2a174510f47d65b3006883e2aa0 Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Thu, 30 Jan 2025 14:18:24 -0800 Subject: [PATCH 24/64] progress --- .../assets/terminal/register-asset.md | 16 ++++++++++++++ .../xcm/xc-registration/assets.md | 21 ++++++++++++++++--- 2 files changed, 34 insertions(+), 3 deletions(-) create mode 100644 .snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/register-asset.md diff --git a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/register-asset.md b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/register-asset.md new file mode 100644 index 000000000..a3654810c --- /dev/null +++ b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/register-asset.md @@ -0,0 +1,16 @@ +
+ scripts % yarn register-asset --w wss://wss.api.moonbeam.network \ + --asset '{ "parents": 1, "interior": {"X1": [{ "Parachain": 3370}]}}' \ + --symbol "xcLAOS" \ + --decimals 18 \ + --name "LAOS" \ + --relative-price 59759806355511400 + yarn run v1.22.22 + warning ../../../package.json: No license field + $ ts-node 'scripts/xcm-asset-registrator.ts' --w wss://wss.api.moonbeam.network --asset '{ "parents": 1, "interior": {"X1": [{ "Parachain": 3370}]}}' --symbol xcLAOS --decimals 18 --name LAOS --relative-price 59759806355511400 + XCM Version is V4 + Encoded Call Data for registerAsset is 0x72008835e1b9f588de47ec5e4a828e4e70dd010100a934121878634c414f53104c414f53 + Encoded Call Data for Set Relative Price is 0x7300010100a9346898aa2d3a4fd4000000000000000000 + Encoded Call Data for batched is 0x1e000872008835e1b9f588de47ec5e4a828e4e70dd010100a934121878634c414f53104c414f537300010100a9346898aa2d3a4fd4000000000000000000 + ✨ Done in 5.20s. +
\ No newline at end of file diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index 71125be23..40885e43b 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -109,7 +109,7 @@ If you're not interested in the mechanics of the relative price feel free to ski 1. Fetch the native token price (GLMR or MOVR) from CoinGecko (in USD) 2. Calculate the ratio of `assetPrice` / `nativeTokenPrice` 3. Multiply that ratio by `0.175`. This factor intentionally overestimates the relative price by ~5–6× to provide a buffer against market fluctuations -4. Multiply by `10 ^ (18 - `assetDecimals`). For example, if the asset uses 12 decimals, you’d multiply by 10^(18 - 12) = 10^6. This accounts for any difference between your asset’s decimals and the 18 decimals used by the native token +4. Multiply by `10 ^ (18 - assetDecimals`). For example, if the asset uses 12 decimals, you’d multiply by 10^(18 - 12) = 10^6. This accounts for any difference between your asset’s decimals and the 18 decimals used by the native token 5. Multiply by `10^18`. This final step scales everything up to 18 decimals (the common WEI format) 6. Convert to `BigInt` @@ -129,11 +129,26 @@ Proposals must be submitted via the `GeneralAdmin` track. If you're opening a ch Using the above information, you can generate the encoded call data for the `createForeignAsset` call either via the Polkadot API or on [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fwss.api.moonbeam.network#/extrinsics){target=\_blank}. +You can generate this required calldata using the + +```bash +yarn register-asset --w wss://wss.api.moonbeam.network \ +--asset 'INSERT_MULTILOCATION' \ +--symbol "INSERT_ASSET_SYMBOL" \ +--decimals INSERT_DECIMALS \ +--name "INSERT_ASSET_NAME" \ +--relative-price INSERT_RELATIVE_PRICE +``` + +For example, + +--8<-- 'code/builders/interoperability/xcm/xc-registration/assets/terminal/calculate-relative-price.md' + + To get the encoded calldata for the `xcmWeightTrader.addAsset` extrinsic, you will need to provide the following arguments: - `xcmLocation` - the multilocation of the asset relative to Moonbeam -- `relativePrice` - A numeric value (u128) representing the fraction of the native token’s price that your asset’s price constitutes, scaled to 18 decimals. This value is used to calculate cross-chain fees by determining how many units of the non-native asset are required to cover XCM operation costs. For example, if the chosen asset is priced at exactly half the native token’s price (GLMR or MOVR), then `relativePrice` = `assetPrice` / `nativeTokenPrice` = `0.5`. Then, this figure must be multiplied by 10^18 to generate an 18-decimal integer of `500,000,000,000,000,000` - +- `relativePrice` - A numeric value (u128) representing the fraction of the native token’s price that your asset’s price constitutes, scaled to 18 decimals. This value is used to calculate cross-chain fees by determining how many units of the non-native asset are required to cover XCM operation costs. Using the above information, you can generate the encoded call data for the `addAsset` call either via the Polkadot API or on [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fwss.api.moonbeam.network#/extrinsics){target=\_blank}. From a747f91e7d40ebd22834f6db9578d5e631c0f08a Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Fri, 31 Jan 2025 15:36:47 -0800 Subject: [PATCH 25/64] add --- .../integration/terminal/accept.md | 16 ++++++++++++++ .../integration/terminal/propose.md | 17 +++++++++++++++ .../xcm/xc-registration/assets.md | 21 ++++++++++++++----- .../xcm/xc-registration/xc-integration.md | 8 +++++++ 4 files changed, 57 insertions(+), 5 deletions(-) create mode 100644 .snippets/code/builders/interoperability/xcm/xc-registration/integration/terminal/accept.md create mode 100644 .snippets/code/builders/interoperability/xcm/xc-registration/integration/terminal/propose.md diff --git a/.snippets/code/builders/interoperability/xcm/xc-registration/integration/terminal/accept.md b/.snippets/code/builders/interoperability/xcm/xc-registration/integration/terminal/accept.md new file mode 100644 index 000000000..728e9f573 --- /dev/null +++ b/.snippets/code/builders/interoperability/xcm/xc-registration/integration/terminal/accept.md @@ -0,0 +1,16 @@ +
+ yarn hrmp-manipulator --target-para-id 3370 \ + --parachain-ws-provider wss://moonbeam.public.blastapi.io \ + --relay-ws-provider wss://polkadot-rpc.publicnode.com \ + --hrmp-action accept + yarn run v1.22.22 + warning ../../../package.json: No license field + $ ts-node 'scripts/hrmp-channel-manipulator.ts' --target-para-id 3370 --parachain-ws-provider wss://moonbeam.public.blastapi.io --relay-ws-provider wss://polkadot-rpc.publicnode.com --hrmp-action accept + + Genesis hash is: 0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3 + Polkadot + FeeAmount is: 10000000000 + XCM Version is V4 + Encoded Call Data for Tx is 0x6b09012a0d0000010401000100e40b5402000000000000000000000002286bee020004000100 + ✨ Done in 4.39s. +
\ No newline at end of file diff --git a/.snippets/code/builders/interoperability/xcm/xc-registration/integration/terminal/propose.md b/.snippets/code/builders/interoperability/xcm/xc-registration/integration/terminal/propose.md new file mode 100644 index 000000000..5f42279fd --- /dev/null +++ b/.snippets/code/builders/interoperability/xcm/xc-registration/integration/terminal/propose.md @@ -0,0 +1,17 @@ +
+ yarn hrmp-manipulator --target-para-id 3370 \ + --parachain-ws-provider wss://moonbeam.public.blastapi.io \ + --relay-ws-provider wss://polkadot-rpc.publicnode.com \ + --max-capacity 1000 --max-message-size 102400 \ + --hrmp-action open + yarn run v1.22.22 + warning ../../../package.json: No license field + $ ts-node 'scripts/hrmp-channel-manipulator.ts' --target-para-id 3370 --parachain-ws-provider wss://moonbeam.public.blastapi.io --relay-ws-provider wss://polkadot-rpc.publicnode.com --max-capacity 1000 --max-message-size 102400 --hrmp-action open + + Genesis hash is: 0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3 + Polkadot + FeeAmount is: 10000000000 + XCM Version is V4 + Encoded Call Data for Tx is 0x6b09002a0d0000e803000000900100010401000100e40b5402000000000000000000000002286bee020004000100 + ✨ Done in 4.25s. +
\ No newline at end of file diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index 40885e43b..5edfb647d 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -129,7 +129,7 @@ Proposals must be submitted via the `GeneralAdmin` track. If you're opening a ch Using the above information, you can generate the encoded call data for the `createForeignAsset` call either via the Polkadot API or on [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fwss.api.moonbeam.network#/extrinsics){target=\_blank}. -You can generate this required calldata using the +You can generate this required calldata using the [xcm-asset-registrator script](https://github.com/Moonsong-Labs/xcm-tools/blob/main/scripts/xcm-asset-registrator.ts){target=\_blank} as follows: ```bash yarn register-asset --w wss://wss.api.moonbeam.network \ @@ -140,19 +140,28 @@ yarn register-asset --w wss://wss.api.moonbeam.network \ --relative-price INSERT_RELATIVE_PRICE ``` -For example, +Upon running the script with the relevant parameters, you'll see output like the following: ---8<-- 'code/builders/interoperability/xcm/xc-registration/assets/terminal/calculate-relative-price.md' +--8<-- 'code/builders/interoperability/xcm/xc-registration/assets/terminal/register-asset.md' + +The script will provide the encoded call data for each of the following calls: + +- The `registerAsset` call +- The `setRelativePrice` call +- The `batch` call that combines each all of the above +Typically, you can submit the `batch` call as part of a single governance proposal to register the asset and set the relative price in one go under the `FastGeneralAdmin` track. However, currently there is a limitation that requires the two calls to be submitted independently. The `registerAsset` call must be submitted under the `FastGeneralAdmin` track, and the `setRelativePrice` call must be submitted under the `GeneralAdmin track`. The latter is a temporary limitation, and in the future is expected to be able to submit both calls as a single `batch` call under the `FastGeneralAdmin` track. -To get the encoded calldata for the `xcmWeightTrader.addAsset` extrinsic, you will need to provide the following arguments: +### Construct the Add Asset Call + +If you've already used the [xcm-asset-registrator script](https://github.com/Moonsong-Labs/xcm-tools/blob/main/scripts/xcm-asset-registrator.ts){target=\_blank} shown above, you can skip this section. This section dives into more detail about how the `xcmWeightTrader.addAsset` call is constructued. To get the encoded calldata for the `xcmWeightTrader.addAsset` extrinsic, you will need to provide the following arguments: - `xcmLocation` - the multilocation of the asset relative to Moonbeam - `relativePrice` - A numeric value (u128) representing the fraction of the native token’s price that your asset’s price constitutes, scaled to 18 decimals. This value is used to calculate cross-chain fees by determining how many units of the non-native asset are required to cover XCM operation costs. Using the above information, you can generate the encoded call data for the `addAsset` call either via the Polkadot API or on [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fwss.api.moonbeam.network#/extrinsics){target=\_blank}. -To create a batch transaction that combines both the `xcmWeightTrader.addAsset` and the `evmForeignAssets.createForeignAsset` calls together, you can use the [Polkadot API's Batch Method](/builders/substrate/libraries/polkadot-js-api/#batching-transactions){target=\_blank}. Additionally, the [XCM Asset Registrator](https://github.com/Moonsong-Labs/xcm-tools/blob/main/scripts/xcm-asset-registrator.ts){target=\_blank} script can help you build and submit the required calls. +To create a batch transaction that combines both the `xcmWeightTrader.addAsset` and the `evmForeignAssets.createForeignAsset` calls together, you can use the [Polkadot API's Batch Method](/builders/substrate/libraries/polkadot-js-api/#batching-transactions){target=\_blank}. As mentioned previously, the [XCM Asset Registrator](https://github.com/Moonsong-Labs/xcm-tools/blob/main/scripts/xcm-asset-registrator.ts){target=\_blank} script can help you build and submit the required calls. ### Submit the Preimage and Proposal for Asset Registration {: #submit-preimage-proposal } @@ -162,6 +171,8 @@ For Moonbase Alpha, you do not need to go through governance, as Moonbase Alpha After submitting the preimage, you can submit the proposal by following the guidelines in the [Submitting a Proposal](/tokens/governance/proposals/#submitting-a-proposal-v2){target=\_blank} section. +If you prefer the script method and you're comfortable working with the scripts in the XCM tools repo, you can use the [Generic Call Proposer](https://github.com/Moonsong-Labs/xcm-tools/blob/main/scripts/generic-call-proposer.ts){target=\_blank} by passing in the requisite calls, including the acceptance and proposal of the XCM Channel, and the asset registration. + ### Test the Asset Registration on Moonbeam {: #test-asset-registration } After your asset is registered, the team will provide the asset ID and the [XC-20 precompile](/builders/interoperability/xcm/xc20/interact/#the-erc20-interface){target=\_blank} address. Your XC-20 precompile address is calculated by converting the asset ID decimal number to hex and prepending it with F's until you get a 40-hex character (plus the “0x”) address. For more information on how it is calculated, please refer to the [Calculate External XC-20 Precompile Addresses](/builders/interoperability/xcm/xc20/interact/#calculate-xc20-address){target=\_blank} section of the External XC-20 guide. After the asset is successfully registered, you can transfer tokens from your parachain to the Moonbeam-based network you are integrating with. diff --git a/builders/interoperability/xcm/xc-registration/xc-integration.md b/builders/interoperability/xcm/xc-registration/xc-integration.md index 9cb6dca0a..e11c31f2f 100644 --- a/builders/interoperability/xcm/xc-registration/xc-integration.md +++ b/builders/interoperability/xcm/xc-registration/xc-integration.md @@ -194,6 +194,10 @@ Running the following command will provide the encoded calldata to accept an ope !!! note You can adapt the script for your parachain by changing the `parachain-ws-provider`. +After running the script, you'll see output that looks like the following: + +--8<-- 'code/builders/interoperability/xcm/xc-registration/integration/terminal/accept.md' + Running the script as shown above will return the encoded calldata to accept an HRMP channel. You can also use the script to create and submit a preimage and proposal on chain for the given HRMP action. For Moonbeam and Moonriver, the proposal must be submitted via the General Admin Track. Please refer to the [README](https://github.com/Moonsong-Labs/xcm-tools/tree/main#hrmp-manipulator-script){target=\_blank} for a complete list of the arguments, including optional arguments, and examples on how to use the HRMP-manipulator script. @@ -243,6 +247,10 @@ Running the following command will provide the encoded calldata to create the HR !!! note You can readapt the script for your parachain by changing the `parachain-ws-provider`. +After running the script, you'll see output that looks like the following: + +--8<-- 'code/builders/interoperability/xcm/xc-registration/integration/terminal/propose.md' + Running the script as shown above will return the encoded calldata to open an HRMP channel. You can also use the script to create and submit a preimage and proposal on-chain for the given HRMP action. For Moonbeam and Moonriver, the proposal must be submitted via the General Admin Track. Please refer to the [README](https://github.com/Moonsong-Labs/xcm-tools/tree/main#hrmp-manipulator-script){target=\_blank} for a complete list of the arguments, including optional arguments, and examples on how to use the HRMP-manipulator script. From 020cb722516707a7db73be44527ca8e75476374e Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Fri, 31 Jan 2025 15:47:03 -0800 Subject: [PATCH 26/64] run grammarly --- .../xcm/xc-registration/assets.md | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index 5edfb647d..94c183167 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -7,7 +7,7 @@ description: This guide includes everything you need to know to register local a ## Introduction {: #introduction } -For an asset to be transferred across chains via XCM, there needs to be an open channel between the two chains, and the asset needs to be registered on the destination chain. If a channel doesn't exist between the two chains, one will need to be opened. Please check out the [XC Channel Registration](/builders/interoperability/xcm/xc-registration/xc-integration/){target=\_blank} guide for information on how to establish a channel between Moonbeam and another chain. +For an asset to be transferred across chains via XCM, there needs to be an open channel between the two chains, and the asset needs to be registered on the destination chain. If a channel does not exist between the two chains, one will need to be opened. Please check out the [XC Channel Registration](/builders/interoperability/xcm/xc-registration/xc-integration/){target=\_blank} guide for information on how to establish a channel between Moonbeam and another chain. This guide will show you how to register [external XC-20s](/builders/interoperability/xcm/xc20/overview/#external-xc20s){target=\_blank} on Moonbeam and provide the information you need to register Moonbeam assets, including Moonbeam native assets (GLMR, MOVR, and DEV) and [local XC-20s](/builders/interoperability/xcm/xc20/overview/#local-xc20s){target=\_blank} (XCM-enabled ERC-20s), on another chain. @@ -55,7 +55,7 @@ With this information in hand, you can prepare a governance proposal to register ### Calculate Relative Price {: #calculate-relative-price } -An asset's `relativePrice` refers to a `u128` value that indicates how many units of said asset (in its smallest denomination) equate to one unit**—i.e., `1 × 10^18 wei`—of the native token (GLMR or MOVR). This helps determine how much of your asset to use for fees originally quoted in the native token, particularly in cross-chain messaging (XCM). +An asset's `relativePrice` refers to a `u128` value that indicates how many units of said asset (in its smallest denomination) equate to one unit**—i.e., `1 × 10^18 wei`—of the native token (GLMR or MOVR). This helps determine how much of your asset to use for fees initially quoted in the native token, particularly in cross-chain messaging (XCM). You can use the following script (also available as part of [XCM-tools](https://github.com/Moonsong-Labs/xcm-tools){target=\_blank} ) to calculate the correct `relativePrice` value for your asset. @@ -64,7 +64,7 @@ You can use the following script (also available as part of [XCM-tools](https:// --8<-- 'code/builders/interoperability/xcm/xc-registration/assets/calculate-relative-price.ts' ``` -If you're in a hurry, you can input the required values and continue on your way. The next section will cover additional background information on relative price and how its calculated. +If you're in a hurry, you can input the required values and continue. The following section will cover additional background information on relative price and how it's calculated. Only three parameters are required to calculate the relative price of an asset: @@ -78,7 +78,7 @@ First, ensure that you've installed the required dependencies by running: npm install ``` -Execute the script: +Execute the script, making sure to provide the USD price of the asset you're registering, the number of decimals it has, and the network you're registering the asset on (either GLMR or MOVR): ```bash npx ts-node calculate-relative-price.ts INSERT_ASSET_PRICE INSERT_DECIMALS GLMR @@ -113,13 +113,13 @@ If you're not interested in the mechanics of the relative price feel free to ski 5. Multiply by `10^18`. This final step scales everything up to 18 decimals (the common WEI format) 6. Convert to `BigInt` -Why is there a `0.175` Factor? The main reason why we don't take the direct relative price of asset price / native token price is to provide a buffer for volatility. Market prices can shift rapidly. An exact 1:1 ratio might under-collect fees if prices move unexpectedly. The `0.175` provides for an approximate 5x overestimation. Generally speaking, the fees are expected to be extremely low so the `5x` multiplier, while a conservative overestimate, is not meant to be unduly burdensome. +Why is there a `0.175` Factor? The main reason why we don't take the direct relative price of asset price / native token price is to provide a buffer for volatility. Market prices can shift rapidly. An exact 1:1 ratio might under-collect fees if prices move unexpectedly. The `0.175` provides for an approximate `5x` overestimation. Generally speaking, fees are expected to be extremely low so the `5x` multiplier, while a conservative overestimate, is not meant to be unduly burdensome. ### Generate the Encoded Calldata for the Asset Registration {: #generate-encoded-calldata-for-asset-registration } Submitting a governance proposal on Moonbeam requires two steps: first, submit a preimage that defines the actions to be executed, then use that preimage to submit the proposal. For more details, see the [Governance on Moonbeam](/learn/features/governance/){target=\_blank} page. To submit a preimage for asset registration, you'll need the encoded calldata for both the `evmForeignAssets.createForeignAsset` and `xcmWeightTrader.addAsset` extrinsics. -Proposals must be submitted via the `GeneralAdmin` track. If you're opening a channel and registering an asset and you'll want to wait until the channel is established prior to attempting to register the asset. To get the encoded calldata for the `evmForeignAssets.createForeignAsset` extrinsic, you will need to provide the following arguments: +Proposals must be submitted via the `GeneralAdmin` track. A channel must be established before an asset can be registered. To get the encoded calldata for the `evmForeignAssets.createForeignAsset` extrinsic, you will need to provide the following arguments: - `assetId` - unique identifier of the asset, generated from the [`calculate-external-asset-info.ts`](https://github.com/Moonsong-Labs/xcm-tools/blob/main/scripts/calculate-external-asset-info.ts){target=\_blank} script - `xcmLocation` - the multilocation of the asset relative to Moonbeam @@ -150,14 +150,14 @@ The script will provide the encoded call data for each of the following calls: - The `setRelativePrice` call - The `batch` call that combines each all of the above -Typically, you can submit the `batch` call as part of a single governance proposal to register the asset and set the relative price in one go under the `FastGeneralAdmin` track. However, currently there is a limitation that requires the two calls to be submitted independently. The `registerAsset` call must be submitted under the `FastGeneralAdmin` track, and the `setRelativePrice` call must be submitted under the `GeneralAdmin track`. The latter is a temporary limitation, and in the future is expected to be able to submit both calls as a single `batch` call under the `FastGeneralAdmin` track. +Typically, you can submit the `batch` call as part of a single governance proposal to register the asset and set the relative price in one go under the `FastGeneralAdmin` track. However, a limitation currently requires the two calls to be submitted independently. The `registerAsset` call must be submitted under the `FastGeneralAdmin` track, and the `setRelativePrice` call must be submitted under the `GeneralAdmin track`. The latter is a temporary limitation, and in the future, it is expected to be able to submit both calls as a single `batch` call under the `FastGeneralAdmin` track. ### Construct the Add Asset Call If you've already used the [xcm-asset-registrator script](https://github.com/Moonsong-Labs/xcm-tools/blob/main/scripts/xcm-asset-registrator.ts){target=\_blank} shown above, you can skip this section. This section dives into more detail about how the `xcmWeightTrader.addAsset` call is constructued. To get the encoded calldata for the `xcmWeightTrader.addAsset` extrinsic, you will need to provide the following arguments: - `xcmLocation` - the multilocation of the asset relative to Moonbeam -- `relativePrice` - A numeric value (u128) representing the fraction of the native token’s price that your asset’s price constitutes, scaled to 18 decimals. This value is used to calculate cross-chain fees by determining how many units of the non-native asset are required to cover XCM operation costs. +- `relativePrice` - A numeric value (u128) representing the fraction of the native token’s price that your asset’s price constitutes, scaled to 18 decimals. This value calculates cross-chain fees by determining how many units of the non-native asset are required to cover XCM operation costs. Using the above information, you can generate the encoded call data for the `addAsset` call either via the Polkadot API or on [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fwss.api.moonbeam.network#/extrinsics){target=\_blank}. @@ -167,7 +167,7 @@ To create a batch transaction that combines both the `xcmWeightTrader.addAsset` Your next task is to submit the preimage of your batched call containing both the `xcmWeightTrader.addAsset` and the `evmForeignAssets.createForeignAsset` by following the guidelines in the [Submit a Democracy Proposal Guide](/tokens/governance/proposals/#submitting-a-preimage-of-the-proposal){target=\_blank}. -For Moonbase Alpha, you do not need to go through governance, as Moonbase Alpha has `sudo` access. Instead, you can provide the output of the batch call data to the Moonbeam team, and the Moonbeam Team can submit the call with `sudo`. This will be a faster and easier process than going through governance. However, you may still wish to go through governance on Moonbase Alpha in order to prepare for the governance process on Moonbeam. +For Moonbase Alpha, you do not need to go through governance, as Moonbase Alpha has `sudo` access. Instead, you can provide the output of the batch call data to the Moonbeam team, and the Moonbeam Team can submit the call with `sudo`. This will be a faster and easier process than going through governance. However, you may still wish to go through governance on Moonbase Alpha to prepare for Moonbeam's governance process. After submitting the preimage, you can submit the proposal by following the guidelines in the [Submitting a Proposal](/tokens/governance/proposals/#submitting-a-proposal-v2){target=\_blank} section. @@ -428,7 +428,7 @@ You can use the following multilocation to register a local XC-20: } ``` -Since local XC-20s are ERC-20s on Moonbeam, there are no deposits required to create an ERC-20 on Moonbeam. There may, however, be deposits required to register the asset on another parachain. Please consult with the parachain team you wish to register the asset with for more information. +Since local XC-20s are ERC-20s on Moonbeam, there are no deposits required to create an ERC-20 on Moonbeam. However, deposits may be required to register the asset on another parachain. Please consult with the parachain team you wish to register the asset with for more information. ## Managing XC Assets @@ -436,7 +436,7 @@ After completing the [registration process](#introduction) for an XC asset, you ### Updating Foreign Asset XCM Location {: #updating-foreign-asset-xcm-location } -You can update the multilocation of an asset with the `evmForeignAssets.changeXcmLocation` call, which takes as parameters, the `assetId` and the new multilocation. You'll need to raise a [governance proposal](/tokens/governance/proposals/) and submit the update under the `GeneralAdmin` track. If you're testing in Moonbase Alpha, you can ask the Moonbeam Team to submit the extrinsic using Sudo to speed up the process. You can also submit the requisite governance proposal on Moonbase Alpha. +You can update the multilocation of an asset with the `evmForeignAssets.changeXcmLocation` call, which takes as parameters the `assetId` and the new multilocation. You'll need to raise a [governance proposal](/tokens/governance/proposals/) and submit the update under the `GeneralAdmin` track. If you're testing in Moonbase Alpha, you can ask the Moonbeam Team to submit the extrinsic using Sudo to speed up the process. You can also submit the requisite governance proposal on Moonbase Alpha. ### Freezing a Foreign Asset {: #freezing-a--foreign-asset } @@ -444,4 +444,4 @@ You can freeze a foreign asset by calling `evmForeignAssets.freezeForeignAsset`, ### Paying XCM Fees with Foreign Assets {: #paying-xcm-fees-with-foreign-assets } -After you've registered the foreign asset via the `evmForeignAssets` and the `xcmWeightTrader` pallet, your asset will now be among the supported assets for paying XCM fees. To verify, you can query the `xcmWeightTrader` pallet and the `supportedAssets` chain state query. Toggle the **Include Option** slider off to see the complete list, or, you can filter the list by the multilocation of your asset. \ No newline at end of file +After you've registered the foreign asset via the `evmForeignAssets` and the `xcmWeightTrader` pallet, your asset will now be among the supported assets for paying XCM fees. To verify, you can query the `xcmWeightTrader` pallet and the `supportedAssets` chain state query. Toggle the **Include Option** slider off to see the complete list, or you can filter the list by the multilocation of your asset. \ No newline at end of file From 2eabe59d1a7e51427a52f0df7970d202ad2a4d30 Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Fri, 31 Jan 2025 15:52:02 -0800 Subject: [PATCH 27/64] additional grammar etc --- builders/interoperability/xcm/xc-registration/assets.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index 94c183167..54ac7d7d0 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -104,7 +104,7 @@ npx ts-node calculate-relative-price.ts --help ### How Relative Price is Constructed -If you're not interested in the mechanics of the relative price feel free to skip this section. The relative price calculation script performs the following steps: +If you're not interested in the mechanics of the relative price, feel free to skip this section. The relative price calculation script performs the following steps: 1. Fetch the native token price (GLMR or MOVR) from CoinGecko (in USD) 2. Calculate the ratio of `assetPrice` / `nativeTokenPrice` @@ -150,11 +150,11 @@ The script will provide the encoded call data for each of the following calls: - The `setRelativePrice` call - The `batch` call that combines each all of the above -Typically, you can submit the `batch` call as part of a single governance proposal to register the asset and set the relative price in one go under the `FastGeneralAdmin` track. However, a limitation currently requires the two calls to be submitted independently. The `registerAsset` call must be submitted under the `FastGeneralAdmin` track, and the `setRelativePrice` call must be submitted under the `GeneralAdmin track`. The latter is a temporary limitation, and in the future, it is expected to be able to submit both calls as a single `batch` call under the `FastGeneralAdmin` track. +Typically, you can submit the `batch` call as part of a single governance proposal to register the asset and set the relative price in one go under the `FastGeneralAdmin` track. However, a limitation currently requires the two calls to be submitted independently. The `registerAsset` call must be submitted under the `FastGeneralAdmin` track, and the `setRelativePrice` call must be submitted under the `GeneralAdmin` track. The latter is a temporary limitation, and in the future, it is expected to be able to submit both calls as a single `batch` call under the `FastGeneralAdmin` track. ### Construct the Add Asset Call -If you've already used the [xcm-asset-registrator script](https://github.com/Moonsong-Labs/xcm-tools/blob/main/scripts/xcm-asset-registrator.ts){target=\_blank} shown above, you can skip this section. This section dives into more detail about how the `xcmWeightTrader.addAsset` call is constructued. To get the encoded calldata for the `xcmWeightTrader.addAsset` extrinsic, you will need to provide the following arguments: +If you've already used the [xcm-asset-registrator script](https://github.com/Moonsong-Labs/xcm-tools/blob/main/scripts/xcm-asset-registrator.ts){target=\_blank} shown above, you can skip this section. This section dives into more detail about how the `xcmWeightTrader.addAsset` call is constructed. To get the encoded calldata for the `xcmWeightTrader.addAsset` extrinsic, you will need to provide the following arguments: - `xcmLocation` - the multilocation of the asset relative to Moonbeam - `relativePrice` - A numeric value (u128) representing the fraction of the native token’s price that your asset’s price constitutes, scaled to 18 decimals. This value calculates cross-chain fees by determining how many units of the non-native asset are required to cover XCM operation costs. From 4af094d2f8f132e58680917fac31db48f0ea8d41 Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Fri, 7 Feb 2025 09:22:27 -0800 Subject: [PATCH 28/64] Update .snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/calculate-relative-price.md Co-authored-by: albertov19 <64150856+albertov19@users.noreply.github.com> --- .../xc-registration/assets/terminal/calculate-relative-price.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/calculate-relative-price.md b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/calculate-relative-price.md index c16f4480d..376af1e4b 100644 --- a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/calculate-relative-price.md +++ b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/calculate-relative-price.md @@ -1,5 +1,5 @@
- npx ts-node calculate-relative-price.ts 0.25 12 GLMR + yarn calculate-relative-price 0.25 12 GLMR Calculating relative price for asset worth $0.25 against GLMR... From da2a5f3d40d197f506f604dab2e29bd1360e077a Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Fri, 7 Feb 2025 09:23:14 -0800 Subject: [PATCH 29/64] Update builders/interoperability/xcm/xc-registration/assets.md Co-authored-by: albertov19 <64150856+albertov19@users.noreply.github.com> --- builders/interoperability/xcm/xc-registration/assets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index 54ac7d7d0..7b35df300 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -44,7 +44,7 @@ To register an asset native to another chain on Moonbeam, you'll need to submit To get started, you'll need to collect some information about the asset: - `assetId` - unique identifier of the asset. This can be any unique arbitrary integer, but it's recommended that you create this using the [`calculate-external-asset-info.ts`](https://github.com/Moonsong-Labs/xcm-tools/blob/main/scripts/calculate-external-asset-info.ts){target=\_blank} script. This provides a standardized way to generate a unique `assetId` -- `xcmLocation` - a scale encoded xcm v4 multilocation of asset reserve relative to Moonbeam +- `xcmLocation` - an [XCM multilocation](/builders/interoperability/xcm/core-concepts/multilocations/){target=\_blank} of asset in its reserve chain relative to Moonbeam - The asset name - The asset symbol. You'll need to prepend "xc" to the asset symbol to indicate that the asset is an XCM-enabled asset - The number of decimals the asset has From 234d455d8614adea64e1a89e0c35392cf8154cd7 Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Fri, 7 Feb 2025 09:23:28 -0800 Subject: [PATCH 30/64] Update builders/interoperability/xcm/xc-registration/assets.md Co-authored-by: albertov19 <64150856+albertov19@users.noreply.github.com> --- builders/interoperability/xcm/xc-registration/assets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index 7b35df300..10ccd60f1 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -49,7 +49,7 @@ To get started, you'll need to collect some information about the asset: - The asset symbol. You'll need to prepend "xc" to the asset symbol to indicate that the asset is an XCM-enabled asset - The number of decimals the asset has -With this information in hand, you can prepare a governance proposal to register a foreign asset. Foreign asset registration proposals should be submitted through the `GeneralAdmin` track. +With this information in hand, you can prepare a governance proposal to register a foreign asset. Foreign asset registration proposals should be submitted through the `FastGeneralAdmin` track. ![Overview of the proposal process](/images/builders/interoperability/xcm/xc-registration/assets/assets-3.webp) From be3d0613710e10b8f9695d8767e5fb841f08dc3c Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Fri, 7 Feb 2025 09:30:26 -0800 Subject: [PATCH 31/64] Update builders/interoperability/xcm/xc-registration/assets.md Co-authored-by: albertov19 <64150856+albertov19@users.noreply.github.com> --- builders/interoperability/xcm/xc-registration/assets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index 10ccd60f1..ccf50fd20 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -81,7 +81,7 @@ npm install Execute the script, making sure to provide the USD price of the asset you're registering, the number of decimals it has, and the network you're registering the asset on (either GLMR or MOVR): ```bash -npx ts-node calculate-relative-price.ts INSERT_ASSET_PRICE INSERT_DECIMALS GLMR +yarn calculate-relative-price.ts GLMR ``` For example, if the asset you're registering has a USD price of $0.25 and 12 decimals and you're registering the asset on the Moonbeam network, you would run: From 5a396d68c1f88111348453eea00842cdb9822102 Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Fri, 7 Feb 2025 09:30:38 -0800 Subject: [PATCH 32/64] Update builders/interoperability/xcm/xc-registration/assets.md Co-authored-by: albertov19 <64150856+albertov19@users.noreply.github.com> --- builders/interoperability/xcm/xc-registration/assets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index ccf50fd20..17366b640 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -75,7 +75,7 @@ Only three parameters are required to calculate the relative price of an asset: First, ensure that you've installed the required dependencies by running: ```bash -npm install +yarn ``` Execute the script, making sure to provide the USD price of the asset you're registering, the number of decimals it has, and the network you're registering the asset on (either GLMR or MOVR): From 68e2c6b34ac2c468d8578fdbaf0386507d377dd4 Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Fri, 7 Feb 2025 09:36:14 -0800 Subject: [PATCH 33/64] Update builders/interoperability/xcm/xc-registration/assets.md Co-authored-by: albertov19 <64150856+albertov19@users.noreply.github.com> --- builders/interoperability/xcm/xc-registration/assets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index 17366b640..12d111f92 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -87,7 +87,7 @@ yarn calculate-relative-price.ts GLMR For example, if the asset you're registering has a USD price of $0.25 and 12 decimals and you're registering the asset on the Moonbeam network, you would run: ```bash -npx ts-node calculate-relative-price.ts 0.25 12 GLMR +yarn calculate-relative-price.ts 0.25 12 GLMR ``` This instructs the script to calculate how many smallest units of an asset (priced at $0.25, with 12 decimals) correspond to 1 GLMR token. From 4b54698f7844b993250a8cae2e57d29121555a81 Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Fri, 7 Feb 2025 09:36:39 -0800 Subject: [PATCH 34/64] Update builders/interoperability/xcm/xc-registration/assets.md Co-authored-by: albertov19 <64150856+albertov19@users.noreply.github.com> --- builders/interoperability/xcm/xc-registration/assets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index 12d111f92..e7428dcca 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -99,7 +99,7 @@ Upon successful execution, the script prints the computed `relativePrice` as a ` For additional info, usage details, or to see an example in action, you can invoke the help command by running: ```bash -npx ts-node calculate-relative-price.ts --help +yarn calculate-relative-price.ts --help ``` ### How Relative Price is Constructed From 4966320f54c931b3b5bb3f52d80e35d1be1bdcba Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Fri, 7 Feb 2025 09:37:29 -0800 Subject: [PATCH 35/64] remove how relative price is calculated --- .../interoperability/xcm/xc-registration/assets.md | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index e7428dcca..384628b49 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -102,19 +102,6 @@ For additional info, usage details, or to see an example in action, you can invo yarn calculate-relative-price.ts --help ``` -### How Relative Price is Constructed - -If you're not interested in the mechanics of the relative price, feel free to skip this section. The relative price calculation script performs the following steps: - -1. Fetch the native token price (GLMR or MOVR) from CoinGecko (in USD) -2. Calculate the ratio of `assetPrice` / `nativeTokenPrice` -3. Multiply that ratio by `0.175`. This factor intentionally overestimates the relative price by ~5–6× to provide a buffer against market fluctuations -4. Multiply by `10 ^ (18 - assetDecimals`). For example, if the asset uses 12 decimals, you’d multiply by 10^(18 - 12) = 10^6. This accounts for any difference between your asset’s decimals and the 18 decimals used by the native token -5. Multiply by `10^18`. This final step scales everything up to 18 decimals (the common WEI format) -6. Convert to `BigInt` - -Why is there a `0.175` Factor? The main reason why we don't take the direct relative price of asset price / native token price is to provide a buffer for volatility. Market prices can shift rapidly. An exact 1:1 ratio might under-collect fees if prices move unexpectedly. The `0.175` provides for an approximate `5x` overestimation. Generally speaking, fees are expected to be extremely low so the `5x` multiplier, while a conservative overestimate, is not meant to be unduly burdensome. - ### Generate the Encoded Calldata for the Asset Registration {: #generate-encoded-calldata-for-asset-registration } Submitting a governance proposal on Moonbeam requires two steps: first, submit a preimage that defines the actions to be executed, then use that preimage to submit the proposal. For more details, see the [Governance on Moonbeam](/learn/features/governance/){target=\_blank} page. To submit a preimage for asset registration, you'll need the encoded calldata for both the `evmForeignAssets.createForeignAsset` and `xcmWeightTrader.addAsset` extrinsics. From ae66ffc194d173170340879b507be745a754332a Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Fri, 7 Feb 2025 09:37:53 -0800 Subject: [PATCH 36/64] Update builders/interoperability/xcm/xc-registration/assets.md Co-authored-by: albertov19 <64150856+albertov19@users.noreply.github.com> --- builders/interoperability/xcm/xc-registration/assets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index 384628b49..a66e7cd6c 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -106,7 +106,7 @@ yarn calculate-relative-price.ts --help Submitting a governance proposal on Moonbeam requires two steps: first, submit a preimage that defines the actions to be executed, then use that preimage to submit the proposal. For more details, see the [Governance on Moonbeam](/learn/features/governance/){target=\_blank} page. To submit a preimage for asset registration, you'll need the encoded calldata for both the `evmForeignAssets.createForeignAsset` and `xcmWeightTrader.addAsset` extrinsics. -Proposals must be submitted via the `GeneralAdmin` track. A channel must be established before an asset can be registered. To get the encoded calldata for the `evmForeignAssets.createForeignAsset` extrinsic, you will need to provide the following arguments: +Proposals must be submitted via the `FastGeneralAdmin` track. A channel must be established before an asset can be registered. To get the encoded calldata for the `evmForeignAssets.createForeignAsset` extrinsic, you will need to provide the following arguments: - `assetId` - unique identifier of the asset, generated from the [`calculate-external-asset-info.ts`](https://github.com/Moonsong-Labs/xcm-tools/blob/main/scripts/calculate-external-asset-info.ts){target=\_blank} script - `xcmLocation` - the multilocation of the asset relative to Moonbeam From b07a1caf5bae950c8a6d10ec08c8903dd2d93b23 Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Fri, 7 Feb 2025 09:38:36 -0800 Subject: [PATCH 37/64] Update builders/interoperability/xcm/xc-registration/assets.md Co-authored-by: albertov19 <64150856+albertov19@users.noreply.github.com> --- builders/interoperability/xcm/xc-registration/assets.md | 1 - 1 file changed, 1 deletion(-) diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index a66e7cd6c..f2955309c 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -137,7 +137,6 @@ The script will provide the encoded call data for each of the following calls: - The `setRelativePrice` call - The `batch` call that combines each all of the above -Typically, you can submit the `batch` call as part of a single governance proposal to register the asset and set the relative price in one go under the `FastGeneralAdmin` track. However, a limitation currently requires the two calls to be submitted independently. The `registerAsset` call must be submitted under the `FastGeneralAdmin` track, and the `setRelativePrice` call must be submitted under the `GeneralAdmin` track. The latter is a temporary limitation, and in the future, it is expected to be able to submit both calls as a single `batch` call under the `FastGeneralAdmin` track. ### Construct the Add Asset Call From 231dd3962ab7d88ad5dec05f1ae9bf49a51ca81a Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Fri, 7 Feb 2025 09:39:12 -0800 Subject: [PATCH 38/64] Update builders/interoperability/xcm/xc-registration/assets.md Co-authored-by: albertov19 <64150856+albertov19@users.noreply.github.com> --- builders/interoperability/xcm/xc-registration/assets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index f2955309c..f58ba30f2 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -39,7 +39,7 @@ To create a forum post on the [Moonbeam Community Forum](https://forum.moonbeam. ### Create a Proposal to Register an Asset {: #create-a-proposal } -To register an asset native to another chain on Moonbeam, you'll need to submit a governance proposal that will call the `evmForeignAssets.createForeignAsset` extrinsic. Additionally, you'll need to register the asset's price (formerly known as units per second) through the `xcmWeightTrader.addAsset` extrinsic so that XCM fees can be properly calculated. An existing asset's price can be updated with `xcmWeightTrader.editAsset`. +To register an asset native to another chain on Moonbeam, you must submit a governance proposal that will call the `evmForeignAssets.createForeignAsset` extrinsic via the `FastGeneralAdmin` track. Additionally, in the same proposal, you'll need to register the asset's price through the `xcmWeightTrader.addAsset` extrinsic so that XCM fees can be properly calculated. An existing asset's price can be updated with `xcmWeightTrader.editAsset`. To get started, you'll need to collect some information about the asset: From aacef73b0f2d69866cbd0c8200efb686b523f179 Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Fri, 7 Feb 2025 09:41:13 -0800 Subject: [PATCH 39/64] clarify commands --- builders/interoperability/xcm/xc-registration/assets.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index f58ba30f2..65ec45ffc 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -81,13 +81,13 @@ yarn Execute the script, making sure to provide the USD price of the asset you're registering, the number of decimals it has, and the network you're registering the asset on (either GLMR or MOVR): ```bash -yarn calculate-relative-price.ts GLMR +yarn calculate-relative-price GLMR ``` For example, if the asset you're registering has a USD price of $0.25 and 12 decimals and you're registering the asset on the Moonbeam network, you would run: ```bash -yarn calculate-relative-price.ts 0.25 12 GLMR +yarn calculate-relative-price 0.25 12 GLMR ``` This instructs the script to calculate how many smallest units of an asset (priced at $0.25, with 12 decimals) correspond to 1 GLMR token. @@ -99,7 +99,7 @@ Upon successful execution, the script prints the computed `relativePrice` as a ` For additional info, usage details, or to see an example in action, you can invoke the help command by running: ```bash -yarn calculate-relative-price.ts --help +yarn calculate-relative-price --help ``` ### Generate the Encoded Calldata for the Asset Registration {: #generate-encoded-calldata-for-asset-registration } From 53591ef978c91e1f44806634cc24f5c6a5dad45d Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Fri, 7 Feb 2025 10:31:36 -0800 Subject: [PATCH 40/64] add generic call propose info --- .../interoperability/xcm/xc-registration/assets.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index 65ec45ffc..2858e3fd5 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -157,7 +157,15 @@ For Moonbase Alpha, you do not need to go through governance, as Moonbase Alpha After submitting the preimage, you can submit the proposal by following the guidelines in the [Submitting a Proposal](/tokens/governance/proposals/#submitting-a-proposal-v2){target=\_blank} section. -If you prefer the script method and you're comfortable working with the scripts in the XCM tools repo, you can use the [Generic Call Proposer](https://github.com/Moonsong-Labs/xcm-tools/blob/main/scripts/generic-call-proposer.ts){target=\_blank} by passing in the requisite calls, including the acceptance and proposal of the XCM Channel, and the asset registration. +If you prefer the script method and you're comfortable working with the scripts in the XCM tools repo, you can use the [Generic Call Proposer](https://github.com/Moonsong-Labs/xcm-tools/blob/main/scripts/generic-call-proposer.ts){target=\_blank} by passing in the requisite calls, including the acceptance and proposal of the XCM Channel, and the asset registration. The [Generic Call Proposer](https://github.com/Moonsong-Labs/xcm-tools/blob/main/scripts/generic-call-proposer.ts){target=\_blank} can help you assemble the multiple requisite calls as follows: + +```bash +yarn generic-call-propose \ + --call INSERT_CALLDATA_INCOMING_XCM_CHANNEL \ + --call INSERT_CALLDATA_OUTGOING_XCM_CHANNEL \ + --call INSERT_CALLDATA_BATCH_ASSET_REGISTRATION \ + --ws-provider INSERT_WSS_PROVIDER +``` ### Test the Asset Registration on Moonbeam {: #test-asset-registration } From 16a1be41647803219762178b25b5ab5a488414ba Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Fri, 7 Feb 2025 10:39:21 -0800 Subject: [PATCH 41/64] revise relative price examples --- .../terminal/calculate-relative-price.md | 18 +++++++++--------- .../assets/terminal/register-asset.md | 8 ++++---- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/calculate-relative-price.md b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/calculate-relative-price.md index 376af1e4b..ab5ed259e 100644 --- a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/calculate-relative-price.md +++ b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/calculate-relative-price.md @@ -1,18 +1,18 @@
- yarn calculate-relative-price 0.25 12 GLMR + yarn calculate-relative-price 0.04901 12 GLMR - Calculating relative price for asset worth $0.25 against GLMR... + Calculating relative price for asset worth $0.04901 against GLMR... Results: - Asset Price: $0.25 + Asset Price: $0.04901 Network: GLMR - Native Token Price (from CoinGecko): $0.1599 + Native Token Price (from CoinGecko): $0.126009 Relative Price Analysis: - 1 GLMR is equal to approximately 0.640 of your specified token. - With 18 decimals, 1 GLMR or in WEI, 1000000000000000000 is equal to a relative price of 273608505315822372126720 units of your token + 1 GLMR is equal to approximately 2.571 of your specified token. + With 18 decimals, 1 GLMR (in WEI: 1000000000000000000) is equal to 68064582688538114392064 units of your token. - Relative Price: 273608505315822372126720 + Relative Price: 68064582688538114392064 - The relative price you should specify in asset registration steps is 273608505315822372126720 -
\ No newline at end of file + The relative price you should specify in asset registration steps is 68064582688538114392064 +
diff --git a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/register-asset.md b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/register-asset.md index a3654810c..056b3e4d2 100644 --- a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/register-asset.md +++ b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/register-asset.md @@ -4,13 +4,13 @@ --symbol "xcLAOS" \ --decimals 18 \ --name "LAOS" \ - --relative-price 59759806355511400 + --relative-price 68064582688538114392064 yarn run v1.22.22 warning ../../../package.json: No license field - $ ts-node 'scripts/xcm-asset-registrator.ts' --w wss://wss.api.moonbeam.network --asset '{ "parents": 1, "interior": {"X1": [{ "Parachain": 3370}]}}' --symbol xcLAOS --decimals 18 --name LAOS --relative-price 59759806355511400 + $ ts-node 'scripts/xcm-asset-registrator.ts' --w wss://wss.api.moonbeam.network --asset '{ "parents": 1, "interior": {"X1": [{ "Parachain": 3370}]}}' --symbol xcLAOS --decimals 18 --name LAOS --relative-price 68064582688538114392064 XCM Version is V4 Encoded Call Data for registerAsset is 0x72008835e1b9f588de47ec5e4a828e4e70dd010100a934121878634c414f53104c414f53 - Encoded Call Data for Set Relative Price is 0x7300010100a9346898aa2d3a4fd4000000000000000000 - Encoded Call Data for batched is 0x1e000872008835e1b9f588de47ec5e4a828e4e70dd010100a934121878634c414f53104c414f537300010100a9346898aa2d3a4fd4000000000000000000 + Encoded Call Data for Set Relative Price is 0x7300010100a9340000805c9cf5d5c9690e000000000000 + Encoded Call Data for batched is 0x1e000872008835e1b9f588de47ec5e4a828e4e70dd010100a934121878634c414f53104c414f537300010100a9340000805c9cf5d5c9690e000000000000 ✨ Done in 5.20s. \ No newline at end of file From f877a220e509a0690cb6244920994668363fa7e8 Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Fri, 7 Feb 2025 11:15:54 -0800 Subject: [PATCH 42/64] revise image diagram --- .../xcm/xc-registration/assets.md | 19 ++---------------- .../xcm/xc-registration/assets/assets-3.webp | Bin 90548 -> 103716 bytes 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index 2858e3fd5..62733a00b 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -37,22 +37,6 @@ If a channel between the chains already exists, you'll need to create a forum po To create a forum post on the [Moonbeam Community Forum](https://forum.moonbeam.network){target=\_blank}, you'll need to make sure that you're adding the post to the correct category and adding relevant content. For general guidelines and a template to follow, please refer to the [Moonbeam Community Forum Templates for XCM Integrations](/builders/interoperability/xcm/xc-registration/forum-templates/#){target=\_blank} page. -### Create a Proposal to Register an Asset {: #create-a-proposal } - -To register an asset native to another chain on Moonbeam, you must submit a governance proposal that will call the `evmForeignAssets.createForeignAsset` extrinsic via the `FastGeneralAdmin` track. Additionally, in the same proposal, you'll need to register the asset's price through the `xcmWeightTrader.addAsset` extrinsic so that XCM fees can be properly calculated. An existing asset's price can be updated with `xcmWeightTrader.editAsset`. - -To get started, you'll need to collect some information about the asset: - -- `assetId` - unique identifier of the asset. This can be any unique arbitrary integer, but it's recommended that you create this using the [`calculate-external-asset-info.ts`](https://github.com/Moonsong-Labs/xcm-tools/blob/main/scripts/calculate-external-asset-info.ts){target=\_blank} script. This provides a standardized way to generate a unique `assetId` -- `xcmLocation` - an [XCM multilocation](/builders/interoperability/xcm/core-concepts/multilocations/){target=\_blank} of asset in its reserve chain relative to Moonbeam -- The asset name -- The asset symbol. You'll need to prepend "xc" to the asset symbol to indicate that the asset is an XCM-enabled asset -- The number of decimals the asset has - -With this information in hand, you can prepare a governance proposal to register a foreign asset. Foreign asset registration proposals should be submitted through the `FastGeneralAdmin` track. - -![Overview of the proposal process](/images/builders/interoperability/xcm/xc-registration/assets/assets-3.webp) - ### Calculate Relative Price {: #calculate-relative-price } An asset's `relativePrice` refers to a `u128` value that indicates how many units of said asset (in its smallest denomination) equate to one unit**—i.e., `1 × 10^18 wei`—of the native token (GLMR or MOVR). This helps determine how much of your asset to use for fees initially quoted in the native token, particularly in cross-chain messaging (XCM). @@ -104,7 +88,7 @@ yarn calculate-relative-price --help ### Generate the Encoded Calldata for the Asset Registration {: #generate-encoded-calldata-for-asset-registration } -Submitting a governance proposal on Moonbeam requires two steps: first, submit a preimage that defines the actions to be executed, then use that preimage to submit the proposal. For more details, see the [Governance on Moonbeam](/learn/features/governance/){target=\_blank} page. To submit a preimage for asset registration, you'll need the encoded calldata for both the `evmForeignAssets.createForeignAsset` and `xcmWeightTrader.addAsset` extrinsics. +Submitting a governance proposal on Moonbeam requires two steps: first, submit a preimage that defines the actions to be executed, then use that preimage to submit the proposal. For more details, see the [Governance on Moonbeam](/learn/features/governance/){target=\_blank} page. To submit a preimage for asset registration, you'll need the encoded calldata for both the `evmForeignAssets.createForeignAsset` and `xcmWeightTrader.addAsset` extrinsics. An existing asset's price can be updated with `xcmWeightTrader.editAsset`. Proposals must be submitted via the `FastGeneralAdmin` track. A channel must be established before an asset can be registered. To get the encoded calldata for the `evmForeignAssets.createForeignAsset` extrinsic, you will need to provide the following arguments: @@ -137,6 +121,7 @@ The script will provide the encoded call data for each of the following calls: - The `setRelativePrice` call - The `batch` call that combines each all of the above +![Overview of the proposal process](/images/builders/interoperability/xcm/xc-registration/assets/assets-3.webp) ### Construct the Add Asset Call diff --git a/images/builders/interoperability/xcm/xc-registration/assets/assets-3.webp b/images/builders/interoperability/xcm/xc-registration/assets/assets-3.webp index d56cae5c0ed5461c3c6dbeb447680a6711ffbe12..b534d83e14fa732869f702e523e8529162317c05 100644 GIT binary patch literal 103716 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 y*> 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

18rg_l>zxhp0w~`y>y_Y!Jl!i} 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 From 25b908e51b1af514783675746011cf0a7596a086 Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Fri, 7 Feb 2025 11:16:49 -0800 Subject: [PATCH 43/64] rev --- builders/interoperability/xcm/xc-registration/assets.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index 62733a00b..6cf8847ba 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -48,8 +48,6 @@ You can use the following script (also available as part of [XCM-tools](https:// --8<-- 'code/builders/interoperability/xcm/xc-registration/assets/calculate-relative-price.ts' ``` -If you're in a hurry, you can input the required values and continue. The following section will cover additional background information on relative price and how it's calculated. - Only three parameters are required to calculate the relative price of an asset: - Asset Price (USD): A positive number representing how much 1 unit (in human-readable form) of your asset costs in USD From 234587673af2d5f5302cc6f71a8b7178949ce36c Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Tue, 11 Feb 2025 10:49:17 -0800 Subject: [PATCH 44/64] Update .snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/calculate-relative-price.md Co-authored-by: Erin Shaben --- .../xc-registration/assets/terminal/calculate-relative-price.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/calculate-relative-price.md b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/calculate-relative-price.md index ab5ed259e..50a54058e 100644 --- a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/calculate-relative-price.md +++ b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/calculate-relative-price.md @@ -1,5 +1,5 @@

- yarn calculate-relative-price 0.04901 12 GLMR + yarn calculate-relative-price 0.04901 12 GLMR Calculating relative price for asset worth $0.04901 against GLMR... From 5f4137e435333154c1ee062c03dcf9a1e0fd3658 Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Tue, 11 Feb 2025 10:49:42 -0800 Subject: [PATCH 45/64] Update .snippets/code/builders/interoperability/xcm/xc-registration/assets/weight-trader.js Co-authored-by: Erin Shaben --- .../xcm/xc-registration/assets/weight-trader.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/weight-trader.js b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/weight-trader.js index 142f3c0e4..5a1064d38 100644 --- a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/weight-trader.js +++ b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/weight-trader.js @@ -16,7 +16,7 @@ async function getEncodedCallData() { }; // Relative price as u128 - const relativePrice = 'INSERT-RELATIVE-PRICE'; // Insert value generated + const relativePrice = 'INSERT_RELATIVE_PRICE'; // Insert value generated // from the relative price script e.g. 1299476000000000000 try { From 35737adaa389c24a6cdb1d77f7e25f7c1a9207cb Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Tue, 11 Feb 2025 10:49:53 -0800 Subject: [PATCH 46/64] Update .snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/register-asset.md Co-authored-by: Erin Shaben --- .../xcm/xc-registration/assets/terminal/register-asset.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/register-asset.md b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/register-asset.md index 056b3e4d2..8f391f0a8 100644 --- a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/register-asset.md +++ b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/terminal/register-asset.md @@ -1,5 +1,5 @@
- scripts % yarn register-asset --w wss://wss.api.moonbeam.network \ + yarn register-asset --w wss://wss.api.moonbeam.network \ --asset '{ "parents": 1, "interior": {"X1": [{ "Parachain": 3370}]}}' \ --symbol "xcLAOS" \ --decimals 18 \ From 69b0fa1e6327f67d46a9404cb74def39f1567acd Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Tue, 11 Feb 2025 10:50:03 -0800 Subject: [PATCH 47/64] Update .snippets/code/builders/interoperability/xcm/xc-registration/integration/terminal/accept.md Co-authored-by: Erin Shaben --- .../xcm/xc-registration/integration/terminal/accept.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.snippets/code/builders/interoperability/xcm/xc-registration/integration/terminal/accept.md b/.snippets/code/builders/interoperability/xcm/xc-registration/integration/terminal/accept.md index 728e9f573..a57c30730 100644 --- a/.snippets/code/builders/interoperability/xcm/xc-registration/integration/terminal/accept.md +++ b/.snippets/code/builders/interoperability/xcm/xc-registration/integration/terminal/accept.md @@ -1,5 +1,5 @@
- yarn hrmp-manipulator --target-para-id 3370 \ + yarn hrmp-manipulator --target-para-id 3370 \ --parachain-ws-provider wss://moonbeam.public.blastapi.io \ --relay-ws-provider wss://polkadot-rpc.publicnode.com \ --hrmp-action accept From 9c87ad7c3c19dc7d6a3e8ae837279070d9b05119 Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Tue, 11 Feb 2025 10:50:25 -0800 Subject: [PATCH 48/64] Update .snippets/code/builders/interoperability/xcm/xc-registration/integration/terminal/propose.md Co-authored-by: Erin Shaben --- .../xcm/xc-registration/integration/terminal/propose.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.snippets/code/builders/interoperability/xcm/xc-registration/integration/terminal/propose.md b/.snippets/code/builders/interoperability/xcm/xc-registration/integration/terminal/propose.md index 5f42279fd..09d9d5e4a 100644 --- a/.snippets/code/builders/interoperability/xcm/xc-registration/integration/terminal/propose.md +++ b/.snippets/code/builders/interoperability/xcm/xc-registration/integration/terminal/propose.md @@ -1,5 +1,5 @@
- yarn hrmp-manipulator --target-para-id 3370 \ + yarn hrmp-manipulator --target-para-id 3370 \ --parachain-ws-provider wss://moonbeam.public.blastapi.io \ --relay-ws-provider wss://polkadot-rpc.publicnode.com \ --max-capacity 1000 --max-message-size 102400 \ From ea67718d02ab5616e72730ae2251be2de6c23a66 Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Tue, 11 Feb 2025 10:50:46 -0800 Subject: [PATCH 49/64] Update builders/interoperability/xcm/xc-registration/assets.md Co-authored-by: Erin Shaben --- builders/interoperability/xcm/xc-registration/assets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index 6cf8847ba..2ddb3d33e 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -39,7 +39,7 @@ To create a forum post on the [Moonbeam Community Forum](https://forum.moonbeam. ### Calculate Relative Price {: #calculate-relative-price } -An asset's `relativePrice` refers to a `u128` value that indicates how many units of said asset (in its smallest denomination) equate to one unit**—i.e., `1 × 10^18 wei`—of the native token (GLMR or MOVR). This helps determine how much of your asset to use for fees initially quoted in the native token, particularly in cross-chain messaging (XCM). +An asset's `relativePrice` refers to a `u128` value that indicates how many units of said asset (in its smallest denomination) equate to one unit**—i.e., `1 × 10^18 Wei`—of the native token (GLMR or MOVR). This helps determine how much of your asset to use for fees initially quoted in the native token, particularly in cross-chain messaging (XCM). You can use the following script (also available as part of [XCM-tools](https://github.com/Moonsong-Labs/xcm-tools){target=\_blank} ) to calculate the correct `relativePrice` value for your asset. From d61d61165b46029974748ebea0e5c15b3684f588 Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Tue, 11 Feb 2025 10:51:00 -0800 Subject: [PATCH 50/64] Update builders/interoperability/xcm/xc-registration/assets.md Co-authored-by: Erin Shaben --- builders/interoperability/xcm/xc-registration/assets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index 2ddb3d33e..be8fe62cb 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -41,7 +41,7 @@ To create a forum post on the [Moonbeam Community Forum](https://forum.moonbeam. An asset's `relativePrice` refers to a `u128` value that indicates how many units of said asset (in its smallest denomination) equate to one unit**—i.e., `1 × 10^18 Wei`—of the native token (GLMR or MOVR). This helps determine how much of your asset to use for fees initially quoted in the native token, particularly in cross-chain messaging (XCM). -You can use the following script (also available as part of [XCM-tools](https://github.com/Moonsong-Labs/xcm-tools){target=\_blank} ) to calculate the correct `relativePrice` value for your asset. +You can use the following script (also available as part of [xcm-tools](https://github.com/Moonsong-Labs/xcm-tools){target=\_blank} ) to calculate the correct `relativePrice` value for your asset. ??? code "Calculate Relative Price" ```typescript From ae902449dd8b983d5f70ad0a471822d5608f9e60 Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Tue, 11 Feb 2025 10:51:16 -0800 Subject: [PATCH 51/64] Update builders/interoperability/xcm/xc-registration/assets.md Co-authored-by: Erin Shaben --- builders/interoperability/xcm/xc-registration/assets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index be8fe62cb..09c885cdb 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -130,7 +130,7 @@ If you've already used the [xcm-asset-registrator script](https://github.com/Moo Using the above information, you can generate the encoded call data for the `addAsset` call either via the Polkadot API or on [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fwss.api.moonbeam.network#/extrinsics){target=\_blank}. -To create a batch transaction that combines both the `xcmWeightTrader.addAsset` and the `evmForeignAssets.createForeignAsset` calls together, you can use the [Polkadot API's Batch Method](/builders/substrate/libraries/polkadot-js-api/#batching-transactions){target=\_blank}. As mentioned previously, the [XCM Asset Registrator](https://github.com/Moonsong-Labs/xcm-tools/blob/main/scripts/xcm-asset-registrator.ts){target=\_blank} script can help you build and submit the required calls. +To create a batch transaction that combines both the `xcmWeightTrader.addAsset` and the `evmForeignAssets.createForeignAsset` calls together, you can use the [Polkadot API's `batch` method](/builders/substrate/libraries/polkadot-js-api/#batching-transactions){target=\_blank}. As mentioned previously, the [XCM asset registrator script](https://github.com/Moonsong-Labs/xcm-tools/blob/main/scripts/xcm-asset-registrator.ts){target=\_blank} can help you build and submit the required calls. ### Submit the Preimage and Proposal for Asset Registration {: #submit-preimage-proposal } From 27cba57816ead630b73152b3ac177e23eafb69d9 Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Tue, 11 Feb 2025 10:52:32 -0800 Subject: [PATCH 52/64] Update builders/interoperability/xcm/xc-registration/assets.md Co-authored-by: Erin Shaben --- builders/interoperability/xcm/xc-registration/assets.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index 09c885cdb..cde6693df 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -50,9 +50,9 @@ You can use the following script (also available as part of [xcm-tools](https:// Only three parameters are required to calculate the relative price of an asset: -- Asset Price (USD): A positive number representing how much 1 unit (in human-readable form) of your asset costs in USD -- Asset Decimals: The number of decimal places your asset uses. For example, if your token has 12 decimals, specify 12 -- Network: Either GLMR (Moonbeam) or MOVR (Moonriver). This should correspond to the network that you're registering the asset on, and this determines which native token’s USD price the script will fetch from CoinGecko +- **Asset Price (USD)** - a positive number representing how much 1 unit (in human-readable form) of your asset costs in USD +- **Asset Decimals** - the number of decimal places your asset uses. For example, if your token has 12 decimals, specify 12 +- **Network** - either GLMR (Moonbeam) or MOVR (Moonriver). This should correspond to the network that you're registering the asset on, and this determines which native token’s USD price the script will fetch from CoinGecko First, ensure that you've installed the required dependencies by running: From 39d8b3af261709dc1e90fd9c9a62999c86af4a10 Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Tue, 11 Feb 2025 10:52:51 -0800 Subject: [PATCH 53/64] Update builders/interoperability/xcm/xc-registration/assets.md Co-authored-by: Erin Shaben --- builders/interoperability/xcm/xc-registration/assets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index cde6693df..e87c74cdd 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -94,7 +94,7 @@ Proposals must be submitted via the `FastGeneralAdmin` track. A channel must be - `xcmLocation` - the multilocation of the asset relative to Moonbeam - `decimals` - the number of decimals of the asset - `symbol` - the symbol of the asset. Remember that "xc" should be prepended to the symbol to indicate the asset is an XCM-enabled asset -- `name` - The asset name +- `name` - the asset name Using the above information, you can generate the encoded call data for the `createForeignAsset` call either via the Polkadot API or on [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fwss.api.moonbeam.network#/extrinsics){target=\_blank}. From 07dbbc4a7dc2eb9c6779b94120dfb8f3b8667d6b Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Tue, 11 Feb 2025 10:53:18 -0800 Subject: [PATCH 54/64] Update builders/interoperability/xcm/xc-registration/assets.md Co-authored-by: Erin Shaben --- builders/interoperability/xcm/xc-registration/assets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index e87c74cdd..9f86ea293 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -63,7 +63,7 @@ yarn Execute the script, making sure to provide the USD price of the asset you're registering, the number of decimals it has, and the network you're registering the asset on (either GLMR or MOVR): ```bash -yarn calculate-relative-price GLMR +yarn calculate-relative-price INSERT_ASSET_PRICE INSERT_DECIMALS GLMR ``` For example, if the asset you're registering has a USD price of $0.25 and 12 decimals and you're registering the asset on the Moonbeam network, you would run: From 64a4bd2ab3a75ee5f87a5b0b90903654678f3b83 Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Tue, 11 Feb 2025 10:53:31 -0800 Subject: [PATCH 55/64] Update builders/interoperability/xcm/xc-registration/assets.md Co-authored-by: Erin Shaben --- builders/interoperability/xcm/xc-registration/assets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index 9f86ea293..d3bfdec77 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -136,7 +136,7 @@ To create a batch transaction that combines both the `xcmWeightTrader.addAsset` Your next task is to submit the preimage of your batched call containing both the `xcmWeightTrader.addAsset` and the `evmForeignAssets.createForeignAsset` by following the guidelines in the [Submit a Democracy Proposal Guide](/tokens/governance/proposals/#submitting-a-preimage-of-the-proposal){target=\_blank}. -For Moonbase Alpha, you do not need to go through governance, as Moonbase Alpha has `sudo` access. Instead, you can provide the output of the batch call data to the Moonbeam team, and the Moonbeam Team can submit the call with `sudo`. This will be a faster and easier process than going through governance. However, you may still wish to go through governance on Moonbase Alpha to prepare for Moonbeam's governance process. +You do not need to go through governance for Moonbase Alpha, as Moonbase Alpha has sudo access. Instead, you can provide the output of the batch call data to the Moonbeam team, and they can submit the call with sudo. This will be a faster and easier process than going through governance. However, you may still wish to go through governance on Moonbase Alpha to prepare for Moonbeam's governance process. After submitting the preimage, you can submit the proposal by following the guidelines in the [Submitting a Proposal](/tokens/governance/proposals/#submitting-a-proposal-v2){target=\_blank} section. From 07bbaf301230d84ca3394e13ceb61fab8b9ee048 Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Tue, 11 Feb 2025 11:01:22 -0800 Subject: [PATCH 56/64] Update builders/interoperability/xcm/xc-registration/assets.md Co-authored-by: Erin Shaben --- builders/interoperability/xcm/xc-registration/assets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index d3bfdec77..de45acad7 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -90,7 +90,7 @@ Submitting a governance proposal on Moonbeam requires two steps: first, submit a Proposals must be submitted via the `FastGeneralAdmin` track. A channel must be established before an asset can be registered. To get the encoded calldata for the `evmForeignAssets.createForeignAsset` extrinsic, you will need to provide the following arguments: -- `assetId` - unique identifier of the asset, generated from the [`calculate-external-asset-info.ts`](https://github.com/Moonsong-Labs/xcm-tools/blob/main/scripts/calculate-external-asset-info.ts){target=\_blank} script +- **`assetId`** - unique identifier of the asset, generated from the [`calculate-external-asset-info.ts`](https://github.com/Moonsong-Labs/xcm-tools/blob/main/scripts/calculate-external-asset-info.ts){target=\_blank} script - `xcmLocation` - the multilocation of the asset relative to Moonbeam - `decimals` - the number of decimals of the asset - `symbol` - the symbol of the asset. Remember that "xc" should be prepended to the symbol to indicate the asset is an XCM-enabled asset From bdaa52b69e4c8c0191a64a4167d6de7837ac752c Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Tue, 11 Feb 2025 11:04:29 -0800 Subject: [PATCH 57/64] Update builders/interoperability/xcm/xc-registration/assets.md Co-authored-by: Erin Shaben --- builders/interoperability/xcm/xc-registration/assets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index de45acad7..f1d7ca7b0 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -102,7 +102,7 @@ You can generate this required calldata using the [xcm-asset-registrator script] ```bash yarn register-asset --w wss://wss.api.moonbeam.network \ ---asset 'INSERT_MULTILOCATION' \ +--asset "INSERT_MULTILOCATION" \ --symbol "INSERT_ASSET_SYMBOL" \ --decimals INSERT_DECIMALS \ --name "INSERT_ASSET_NAME" \ From a451f9f16dec05230e44c8b19b5fe4b1641322bb Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Tue, 11 Feb 2025 11:04:52 -0800 Subject: [PATCH 58/64] Update builders/interoperability/xcm/xc-registration/assets.md Co-authored-by: Erin Shaben --- builders/interoperability/xcm/xc-registration/assets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index f1d7ca7b0..c49b7b9f6 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -140,7 +140,7 @@ You do not need to go through governance for Moonbase Alpha, as Moonbase Alpha h After submitting the preimage, you can submit the proposal by following the guidelines in the [Submitting a Proposal](/tokens/governance/proposals/#submitting-a-proposal-v2){target=\_blank} section. -If you prefer the script method and you're comfortable working with the scripts in the XCM tools repo, you can use the [Generic Call Proposer](https://github.com/Moonsong-Labs/xcm-tools/blob/main/scripts/generic-call-proposer.ts){target=\_blank} by passing in the requisite calls, including the acceptance and proposal of the XCM Channel, and the asset registration. The [Generic Call Proposer](https://github.com/Moonsong-Labs/xcm-tools/blob/main/scripts/generic-call-proposer.ts){target=\_blank} can help you assemble the multiple requisite calls as follows: +If you prefer the script method and you're comfortable working with the scripts in the XCM tools repo, you can use the [generic call proposer](https://github.com/Moonsong-Labs/xcm-tools/blob/main/scripts/generic-call-proposer.ts){target=\_blank} by passing in the requisite calls, including the acceptance and proposal of the XCM Channel, and the asset registration. The [generic call proposer](https://github.com/Moonsong-Labs/xcm-tools/blob/main/scripts/generic-call-proposer.ts){target=\_blank} can help you assemble the multiple requisite calls as follows: ```bash yarn generic-call-propose \ From 26115038bbf36f0aa6f8f2f5a208fce633637f02 Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Tue, 11 Feb 2025 11:05:11 -0800 Subject: [PATCH 59/64] Update builders/interoperability/xcm/xc-registration/assets.md Co-authored-by: Erin Shaben --- builders/interoperability/xcm/xc-registration/assets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index c49b7b9f6..f6eacf8de 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -88,7 +88,7 @@ yarn calculate-relative-price --help Submitting a governance proposal on Moonbeam requires two steps: first, submit a preimage that defines the actions to be executed, then use that preimage to submit the proposal. For more details, see the [Governance on Moonbeam](/learn/features/governance/){target=\_blank} page. To submit a preimage for asset registration, you'll need the encoded calldata for both the `evmForeignAssets.createForeignAsset` and `xcmWeightTrader.addAsset` extrinsics. An existing asset's price can be updated with `xcmWeightTrader.editAsset`. -Proposals must be submitted via the `FastGeneralAdmin` track. A channel must be established before an asset can be registered. To get the encoded calldata for the `evmForeignAssets.createForeignAsset` extrinsic, you will need to provide the following arguments: +Proposals must be submitted via the Fast General Admin track. A channel must be established before an asset can be registered. To get the encoded calldata for the `evmForeignAssets.createForeignAsset` extrinsic, you will need to provide the following arguments: - **`assetId`** - unique identifier of the asset, generated from the [`calculate-external-asset-info.ts`](https://github.com/Moonsong-Labs/xcm-tools/blob/main/scripts/calculate-external-asset-info.ts){target=\_blank} script - `xcmLocation` - the multilocation of the asset relative to Moonbeam From 7a620de0a7ceca63e409e267b56b6f12807a781f Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Tue, 11 Feb 2025 11:05:22 -0800 Subject: [PATCH 60/64] Update builders/interoperability/xcm/xc-registration/assets.md Co-authored-by: Erin Shaben --- builders/interoperability/xcm/xc-registration/assets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index f6eacf8de..95ba73131 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -413,7 +413,7 @@ After completing the [registration process](#introduction) for an XC asset, you ### Updating Foreign Asset XCM Location {: #updating-foreign-asset-xcm-location } -You can update the multilocation of an asset with the `evmForeignAssets.changeXcmLocation` call, which takes as parameters the `assetId` and the new multilocation. You'll need to raise a [governance proposal](/tokens/governance/proposals/) and submit the update under the `GeneralAdmin` track. If you're testing in Moonbase Alpha, you can ask the Moonbeam Team to submit the extrinsic using Sudo to speed up the process. You can also submit the requisite governance proposal on Moonbase Alpha. +You can update the multilocation of an asset with the `evmForeignAssets.changeXcmLocation` call, which takes as parameters the `assetId` and the new multilocation. You'll need to raise a [governance proposal](/tokens/governance/proposals/) and submit the update under the General Admin track. If you're testing in Moonbase Alpha, you can ask the Moonbeam Team to submit the extrinsic using Sudo to speed up the process. You can also submit the requisite governance proposal on Moonbase Alpha. ### Freezing a Foreign Asset {: #freezing-a--foreign-asset } From 654c3c1388af302e24cb9b23ae45833e2f7a7b7a Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Tue, 11 Feb 2025 11:07:20 -0800 Subject: [PATCH 61/64] make bold lists --- .../interoperability/xcm/xc-registration/assets.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index 95ba73131..9dfd503c3 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -91,10 +91,10 @@ Submitting a governance proposal on Moonbeam requires two steps: first, submit a Proposals must be submitted via the Fast General Admin track. A channel must be established before an asset can be registered. To get the encoded calldata for the `evmForeignAssets.createForeignAsset` extrinsic, you will need to provide the following arguments: - **`assetId`** - unique identifier of the asset, generated from the [`calculate-external-asset-info.ts`](https://github.com/Moonsong-Labs/xcm-tools/blob/main/scripts/calculate-external-asset-info.ts){target=\_blank} script -- `xcmLocation` - the multilocation of the asset relative to Moonbeam -- `decimals` - the number of decimals of the asset -- `symbol` - the symbol of the asset. Remember that "xc" should be prepended to the symbol to indicate the asset is an XCM-enabled asset -- `name` - the asset name +- **`xcmLocation`** - the multilocation of the asset relative to Moonbeam +- **`decimals`** - the number of decimals of the asset +- **`symbol`** - the symbol of the asset. Remember that "xc" should be prepended to the symbol to indicate the asset is an XCM-enabled asset +- **`name`** - the asset name Using the above information, you can generate the encoded call data for the `createForeignAsset` call either via the Polkadot API or on [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fwss.api.moonbeam.network#/extrinsics){target=\_blank}. @@ -125,8 +125,8 @@ The script will provide the encoded call data for each of the following calls: If you've already used the [xcm-asset-registrator script](https://github.com/Moonsong-Labs/xcm-tools/blob/main/scripts/xcm-asset-registrator.ts){target=\_blank} shown above, you can skip this section. This section dives into more detail about how the `xcmWeightTrader.addAsset` call is constructed. To get the encoded calldata for the `xcmWeightTrader.addAsset` extrinsic, you will need to provide the following arguments: -- `xcmLocation` - the multilocation of the asset relative to Moonbeam -- `relativePrice` - A numeric value (u128) representing the fraction of the native token’s price that your asset’s price constitutes, scaled to 18 decimals. This value calculates cross-chain fees by determining how many units of the non-native asset are required to cover XCM operation costs. +- **`xcmLocation`** - the multilocation of the asset relative to Moonbeam +- **`relativePrice`** - A numeric value (u128) representing the fraction of the native token’s price that your asset’s price constitutes, scaled to 18 decimals. This value calculates cross-chain fees by determining how many units of the non-native asset are required to cover XCM operation costs. Using the above information, you can generate the encoded call data for the `addAsset` call either via the Polkadot API or on [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fwss.api.moonbeam.network#/extrinsics){target=\_blank}. From 5cba02d96a78b61b0d247c448628633311fde5ab Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Tue, 11 Feb 2025 11:08:00 -0800 Subject: [PATCH 62/64] rev --- builders/interoperability/xcm/xc-registration/assets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index 9dfd503c3..f5706c969 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -39,7 +39,7 @@ To create a forum post on the [Moonbeam Community Forum](https://forum.moonbeam. ### Calculate Relative Price {: #calculate-relative-price } -An asset's `relativePrice` refers to a `u128` value that indicates how many units of said asset (in its smallest denomination) equate to one unit**—i.e., `1 × 10^18 Wei`—of the native token (GLMR or MOVR). This helps determine how much of your asset to use for fees initially quoted in the native token, particularly in cross-chain messaging (XCM). +An asset's `relativePrice` refers to a `u128` value that indicates how many units of said asset (in its smallest denomination) equate to one unit—i.e., `1 × 10^18 Wei`—of the native token (GLMR or MOVR). This helps determine how much of your asset to use for fees initially quoted in the native token, particularly in cross-chain messaging (XCM). You can use the following script (also available as part of [xcm-tools](https://github.com/Moonsong-Labs/xcm-tools){target=\_blank} ) to calculate the correct `relativePrice` value for your asset. From 868c61f454b59505419e40bcc48d233820b746d6 Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Tue, 11 Feb 2025 11:12:27 -0800 Subject: [PATCH 63/64] prettier --- .../assets/calculate-relative-price.ts | 57 +++++++++++-------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/calculate-relative-price.ts b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/calculate-relative-price.ts index b618f3a35..db860659b 100644 --- a/.snippets/code/builders/interoperability/xcm/xc-registration/assets/calculate-relative-price.ts +++ b/.snippets/code/builders/interoperability/xcm/xc-registration/assets/calculate-relative-price.ts @@ -1,15 +1,15 @@ -import axios from "axios"; +import axios from 'axios'; // CoinGecko IDs for the networks const NETWORK_IDS = { - GLMR: "moonbeam", - MOVR: "moonriver", + GLMR: 'moonbeam', + MOVR: 'moonriver', }; async function calculateRelativePrice( assetPrice: number, assetDecimals: number, - network: "GLMR" | "MOVR" + network: 'GLMR' | 'MOVR' ): Promise { try { // Fetch the native token price from CoinGecko @@ -23,7 +23,10 @@ async function calculateRelativePrice( // Formula: (assetPrice / nativeTokenPrice) * 10^18 // This gives us how many units of the asset we need to equal 1 unit of native token const relativePrice = BigInt( - 0.175 * Math.pow(10, 18 - assetDecimals) * (assetPrice / nativeTokenPrice) * Math.pow(10, 18) + 0.175 * + Math.pow(10, 18 - assetDecimals) * + (assetPrice / nativeTokenPrice) * + Math.pow(10, 18) ); // Return as string to preserve precision @@ -40,37 +43,39 @@ function validateInput( price: string, decimals: string, network: string -): { assetPrice: number; assetDecimals: number; network: "GLMR" | "MOVR" } { +): { assetPrice: number; assetDecimals: number; network: 'GLMR' | 'MOVR' } { // Validate price const assetPrice = parseFloat(price); if (isNaN(assetPrice) || assetPrice <= 0) { - throw new Error("Price must be a positive number"); + throw new Error('Price must be a positive number'); } // Validate decimals const assetDecimals = parseFloat(decimals); if (isNaN(assetDecimals) || assetDecimals <= 0) { - throw new Error("Decimals must be a positive number"); + throw new Error('Decimals must be a positive number'); } // Validate network - const upperNetwork = network.toUpperCase() as "GLMR" | "MOVR"; - if (!["GLMR", "MOVR"].includes(upperNetwork)) { - throw new Error("Network must be either GLMR or MOVR"); + const upperNetwork = network.toUpperCase() as 'GLMR' | 'MOVR'; + if (!['GLMR', 'MOVR'].includes(upperNetwork)) { + throw new Error('Network must be either GLMR or MOVR'); } return { assetPrice, assetDecimals, network: upperNetwork }; } function printUsage() { - console.log("\nUsage:"); - console.log("npx ts-node calculate-relative-price.ts "); - console.log("\nExample:"); - console.log("npx ts-node calculate-relative-price.ts 0.25 12 GLMR"); - console.log("\nParameters:"); - console.log("price - The price of your asset in USD"); - console.log("decimals - The decimals of your asset"); - console.log("network - Either GLMR or MOVR"); + console.log('\nUsage:'); + console.log( + 'npx ts-node calculate-relative-price.ts ' + ); + console.log('\nExample:'); + console.log('npx ts-node calculate-relative-price.ts 0.25 12 GLMR'); + console.log('\nParameters:'); + console.log('price - The price of your asset in USD'); + console.log('decimals - The decimals of your asset'); + console.log('network - Either GLMR or MOVR'); } async function main() { @@ -79,14 +84,14 @@ async function main() { const [, , price, decimals, network] = process.argv; // Check if help flag is passed - if (price === "--help" || price === "-h") { + if (price === '--help' || price === '-h') { printUsage(); return; } // Check if required arguments are provided if (!price || !decimals || !network) { - console.error("Error: Missing required arguments"); + console.error('Error: Missing required arguments'); printUsage(); process.exit(1); } @@ -101,7 +106,11 @@ async function main() { console.log( `\nCalculating relative price for asset worth $${assetPrice} against ${validNetwork}...` ); - const relativePrice = await calculateRelativePrice(assetPrice, assetDecimals, validNetwork); + const relativePrice = await calculateRelativePrice( + assetPrice, + assetDecimals, + validNetwork + ); const nativeTokenPrice = ( await axios.get( `https://api.coingecko.com/api/v3/simple/price?ids=${NETWORK_IDS[validNetwork]}&vs_currencies=usd` @@ -128,9 +137,9 @@ async function main() { `\nThe relative price you should specify in asset registration steps is ${relativePrice}\n` ); } catch (error) { - console.error("\nError:", error instanceof Error ? error.message : error); + console.error('\nError:', error instanceof Error ? error.message : error); process.exit(1); } } -main(); \ No newline at end of file +main(); From 1a29184035aca04fcf0de1782520cca653f61c56 Mon Sep 17 00:00:00 2001 From: Kevin Neilson Date: Tue, 11 Feb 2025 11:13:22 -0800 Subject: [PATCH 64/64] rev --- builders/interoperability/xcm/xc-registration/assets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builders/interoperability/xcm/xc-registration/assets.md b/builders/interoperability/xcm/xc-registration/assets.md index f5706c969..73e57cdc0 100644 --- a/builders/interoperability/xcm/xc-registration/assets.md +++ b/builders/interoperability/xcm/xc-registration/assets.md @@ -126,7 +126,7 @@ The script will provide the encoded call data for each of the following calls: If you've already used the [xcm-asset-registrator script](https://github.com/Moonsong-Labs/xcm-tools/blob/main/scripts/xcm-asset-registrator.ts){target=\_blank} shown above, you can skip this section. This section dives into more detail about how the `xcmWeightTrader.addAsset` call is constructed. To get the encoded calldata for the `xcmWeightTrader.addAsset` extrinsic, you will need to provide the following arguments: - **`xcmLocation`** - the multilocation of the asset relative to Moonbeam -- **`relativePrice`** - A numeric value (u128) representing the fraction of the native token’s price that your asset’s price constitutes, scaled to 18 decimals. This value calculates cross-chain fees by determining how many units of the non-native asset are required to cover XCM operation costs. +- **`relativePrice`** - A numeric value (u128) representing the fraction of the native token’s price that your asset’s price constitutes, scaled to 18 decimals. This value calculates cross-chain fees by determining how many units of the non-native asset are required to cover XCM operation costs Using the above information, you can generate the encoded call data for the `addAsset` call either via the Polkadot API or on [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fwss.api.moonbeam.network#/extrinsics){target=\_blank}.