通过XCM执行远程批量EVM调用¶
作者:Kevin Neilson
概览¶
在本教程中,我们将使用波卡的通用消息传递协议XCM从中继链(对于Moonbeam来说为Polkadot)发起一系列远程批量EVM调用。为此,我们将使用独特的XCM指令组合,允许您通过XCM消息调用Moonbeam EVM。本教程的独特之处在于,我们将使用Moonbeam的Batch Precompile来将多个EVM调用组合成单个交易进行处理,而不是依次执行单个远程EVM合约调用。
要遵循本教程操纵之前,您需要先熟悉通过XCM执行远程EVM调用和Moonbeam的Batch Precompile。
本教程的内容仅用于教育目的!
在本示例中,我们将在Moonbase Alpha(Moonbeam TestNet)上进行操作,其拥有自己的中继链,称为Moonbase relay(类似于波卡中继链)。中继链Token为UNIT,而Moonbase Alpha的Token为DEV。请注意,发送错误的XCM消息可能导致资金丢失。因此,XCM功能需要先在测试网上进行测试后再将其移到生产环境。
本教程的目的展示批量预编译如何与波卡的XCM允许您在Moonbeam上触发远程批量EVM调用。为了简化本教程的复杂性,我们实际操作的批量EVM调用将非常简单。我们将在Moonbase Alpha上发行多个planet ERC-20测试token。尽管我们选择了简单的合约调用来进行演示,但您可能希望模拟更多现实生活中的DeFi示例,例如Token批准和兑换、从多个池中领取奖励,或者兑换并存入LP池。
在本教程中,我们将通过XCM执行批量EVM调用的账户称为Alice。接下来,让我们来解析一下本教程的流程:
- Alice在中继链上有一个账户,她想要使用Moonbase Minter mint Mars (MARS)和Neptune (NEPT) Token(即Moonbase Alpha上的ERC-20)。Alice需要从她的中继链账户发送XCM消息至Moonbase Alpha
- Moonbase Alpha将接收XCM消息并执行其指令。这些指令说明Alice想要在Moonbase Alph中购买一些块执行时间,并执行对Moonbase批量预编译的调用,该调用由两个不同的mint调用组成。批量EVM调用通过Alice在Moonbase Alpha上通过XCM消息控制的特殊账户进行调度。 此账户称为multilocation衍生账户。即使这是一个无密钥账户(私钥未知),公共地址也可以以确定性方式计算
- 成功的XCM执行将导致EVM执行mint命令,Alice将在她的特殊账户中收到她的MARS和NEPT Token
- 通过XCM的远程EVM执行将产生一些EVM日志,这些日志由浏览器收集。任何人都可以验证EVM交易和收据
通过XCM调度的远程批量EVM调用的“满意路径”如下所示:
查看先决条件¶
根据概览中总结的所有步骤,需要考虑以下先决条件:
- 您需要在中继链上拥有UNIT,在发送XCM时用于支付交易费用。如果您有一个拥有DEV Token的Moonbase Alpha账户,您可以在Moonbeam Swap将一些DEV Token兑换成xcUNIT。然后使用apps.moonbeam.network从Moonbase Alpha提取一些xcUNIT至Moonbase中继链上的账户 您可以每24小时一次从Moonbase Alpha水龙头上获取DEV代币以在Moonbase Alpha上进行测试
- 您的multilocation衍生账户必须持有DEV Token以调用Batch Precompile,并支付XCM执行费用(虽然此费用将以xcUNIT形式的UNIT Token进行支付)。我们将在下一个部分计算multilocation衍生账户地址
计算您的Multilocation衍生账户¶
复制您在Moonbase中继链的现有或新创建的账户。您将需要它来计算相应的多地点衍生账户,这是一种特殊类型的无密钥账户(其私钥未知)。来自多地点衍生账户的交易只能通过来自中继链上相应账户的有效XCM指令启动。换句话说,您是唯一可以在您的多地点衍生账户上发起交易的人——如果您无法访问您的Moonbase中继链账户,您也将无法访问您的多地点衍生账户。
如要产生多地点衍生账户,首先请复制xcm-tools代码库,运行yarn
指令以安装所有必要代码包并运行以下指令:
yarn calculate-multilocation-derivative-account \
--ws-provider wss://wss.api.moonbase.moonbeam.network \
--address INSERT_MOONBASE_RELAY_ACCOUNT \
--para-id INSERT_ORIGIN_PARACHAIN_ID_IF_APPLIES \
--parents INSERT_PARENTS_VALUE_IF_APPLIES
接着,让我们检查以上指令中输入的相关参数:
--ws-provider
或-w
标志对应我们用于获得此信息的端点--address
或-a
标志对应您的Moonbase中继链账户地址--para-id
或-p
标志对应原链(如有)的平行链ID。如果您从中继链传送XCM则无需提供此参数-parents
标签与目标链在源链上的父值相关。如果您正从中继链源头在平行链目标链生成multi-location衍生账户,此数值将会是1
。如果不是,父值预设为0
在本示例中,我们将通过XCM从Alice的账户(即5Fe4nNwxJ9ai9hVkUubiy4e6BVs1tzJGDLXAdhUKuePq9CLp
)发送远程EVM调用。由于我们将从中继链发送XCM指令,因此命令中省略了平行链ID。父值1
表示中继链为目标平行链父链。命令和响应如下图所示:
下方表格涵盖了所有值:
名称 | 值 |
---|---|
源链编码地址 | 5Fe4nNwxJ9ai9hVkUubiy4e6BVs1tzJGDLXAdhUKuePq9CLp |
源链解码地址 | 0x9e263df66ff98212347e9a6b51d56f7a982bc25bb1300cd20e5a68d726789043 |
Multilocation衍生账户(32字节) | 0xf0615483cbe76f5b2aa80a8ce2b2e9a8206deb65b8a1323270e25802f600f95c |
Multilocation衍生账户(20字节) | 0xf0615483cbe76f5b2aa80a8ce2b2e9a8206deb65 |
此脚本将返回32字节和20字节的地址。我们将使用以太坊格式的地址,也就是20字节的地址:0xf0615483cbe76f5b2aa80a8ce2b2e9a8206deb65
。您可以根据需求在Moonscan上查看您的multilocation衍生账户。接下来,您可以为此账户充值DEV Token。
您可以每24小时一次从Moonbase Alpha水龙头上获取DEV代币以在Moonbase Alpha上进行测试。
准备Mint EVM Calldata¶
首先,我们将生成mint MARS和NEPT Token所需的calldata。然后,我们将引用批量预编译来将调用批处理为单个调用。
此处将要使用的函数为Moonbase Minter的mint
函数。此函数没有参数,其calldata与其他planet一致。但是,每个planet有不同的合约地址。
获取calldata最简便的方式是通过Moonbase Minter页面获取。进入页面后,执行以下步骤:
- 点击Connect MetaMask并解锁钱包
- 点击任一Mint按钮,因其均拥有同样的calldata
- 然后,MetaMask将跳出弹窗,但请勿签署交易。在MetaMask中,点击hex标签,随后将会出现编码的calldata
- 点击Copy raw transaction data按钮。这将复制编码的calldata至剪贴板:
0x2004ffd9
注意事项
其他钱包也提供相同的功能,可以在签署交易之前检查编码的calldata。
准备批量Calldata¶
现在我们有了用于mint操作的calldata,我们可以使用批量预编译将多个调用合并为一个调用。批量预编译提供了几种不同的方法,根据您对子调用失败的承受程度对交易进行批处理。在本示例中,我们将使用batchAll
函数,如果单个子调用失败,该函数将恢复所有子调用。关于批量预编译每个函数的运作方式,请查看完整的批量预编译教程。
用于本教程目的,我们将使用Remix可视化和构造我们的calldata。如需要,批量预编译页面提供了分步教程,引导您如何在Remix中使用批量预编译开始操作。
首先,复制Batch.sol
并编译它。从Remix的Deploy标签下,将Remix的环境指定为Injected Web3,并确保您的钱包已切换至Moonbase Alpha网络。由于这是一个预编译,因此我们无需部署任何东西,而是在其各自的地址访问批量预编译:
0x0000000000000000000000000000000000000808
0x0000000000000000000000000000000000000808
0x0000000000000000000000000000000000000808
输入地址并点击At Address,然后执行以下步骤准备批处理调用:
- 展开batchAll或批量预编译的其他所需方法
- 在To字段中,将MARS和NEPT合约的地址放在引号中并用逗号分隔。整行应该用括号括起来,具体如下所示:
["0x1FC56B105c4F0A1a8038c2b429932B122f6B631f","0xed13B028697febd70f34cf9a9E280a8f1E98FD29"]
- 在值字段中提供一个空白数组 (
[]
)。我们不想向合约发送任何Token,因为它们不是支付合约 - 在
callData
字段中,提供["0x2004ffd9","0x2004ffd9"]
。请注意您需要为每个调用提供calldata,即使在calldata是一致的情况下,例如两者均为mint
调用 - (可选)您可以指定gas限制,但这非必要,因此只需提供一个空白数组(
[]
) - 要验证您是否已正确配置调用,您可以按Transact,但请勿在钱包中确认交易。如果出现错误,请仔细检查每个参数的格式是否正确
- MetaMask将跳出弹窗,但请勿签署交易。在MetaMask中,点击hex标签,随后将出现编码后的calldata
- 点击Copy raw transaction data按钮。这将批量调用的编码calldata复制到剪贴板
现在,我们已经完成了批量调用EVM calldata的准备工作。接下来,我们需要准备XCM指令,用于执行远程批量调用。
生成Moonbeam编码的Callcata¶
现在我们有了包含两个mint命令的批量EVM calldata,我们需要生成XCM消息中的Transact
XCM指令将执行的字节。请注意,这些字节表示将在远程链中执行的操作。在此示例中,我们希望XCM消息执行进入EVM并发出两个mint命令,从中我们获得编码后的calldata。
要获取交易参数的SCALE(编码类型)编码的calldata,我们可以利用以下Polkadot.js API脚本 ( 请注意,这需要用到@polkadot/api
)。
import { ApiPromise, WsProvider } from '@polkadot/api'; // Version 9.13.6
// 1. Input Data
const providerWsURL = 'wss://wss.api.moonbase.moonbeam.network';
const batchPrecompile = '0x0000000000000000000000000000000000000808';
const contractCall =
'0x96e292b8000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000001fc56b105c4f0a1a8038c2b429932b122f6b631f000000000000000000000000ed13b028697febd70f34cf9a9e280a8f1e98fd29000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000042004ffd90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000042004ffd9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000';
const generateCallData = async () => {
// 2. Create Substrate API Provider
const substrateProvider = new WsProvider(providerWsURL);
const api = await ApiPromise.create({ provider: substrateProvider });
// 3. Estimate Gas for EVM Call
const gasLimit = 140000n;
// 4. Call Parameters
const callParams = {
V2: {
gasLimit: gasLimit + 10000n, // Estimated plus some extra gas
action: { Call: batchPrecompile }, // Address of the Batch Precompile
value: 0, // Not a payable contract
input: contractCall, // Batch of the 2 mint calls
},
};
// 5. Create the Extrinsic
const tx = api.tx.ethereumXcm.transact(callParams);
// 6. Get SCALE Encoded Calldata
const encodedCall = tx.method.toHex();
console.log(`Encoded Calldata: ${encodedCall}`);
api.disconnect();
};
generateCallData();
注意事项
您也可以通过在Polkadot.js Apps中手动构建extrinsic来获取SCALE编码的calldata。
接下来,让我们看一下上面显示的代码片段的每个主要组件:
-
提供请求的输入数据。这包括:
- 创建提供商的Moonbase Alpha端点URL
- 批量预编译的地址
- 包含两个mint命令的批量调用的编码calldata
-
创建所需的提供商。其中一个为Polkadot.js API提供商,通过此提供商我们可以直接调用Moonbeam pallets
- 为了简单起见,我们对gas限制进行了硬编码,并避免批量预编译导致的gas预估问题
- 构建包含批量调用的远程EVM调用
- 创建对
transact
函数的Ethereum XCM pallet调用,提供上方指定的调用参数 - 获取特定交易参数的SCALE calldata,稍后我们需要将其提供给
Transact
XCM指令。请注意,在这个特定场景中,因为我们只需要交易参数的calldata,所以我们必须使用tx.method.toHex()
代码设置完毕后,您可以使用node
执行它。并且您将获取Moonbase Alpha远程EVM calldata:
本示例的编码calldata如下所示:
0x260001f0490200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008080000000000000000000000000000000000000000000000000000000000000000110896e292b8000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000001fc56b105c4f0a1a8038c2b429932b122f6b631f000000000000000000000000ed13b028697febd70f34cf9a9e280a8f1e98fd29000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000042004ffd90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000042004ffd900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
这样就可以了!您已拥有开始制作XCM消息所需要的一切!
从中继链构建XCM消息¶
我们即将进入本教程的最后一个部分!在此部分中,我们将使用Polkadot.js API制作XCM消息。我们将根据指令分解消息指令,深入了解每个部分的具体情况。
我们即将构建的XCM消息由以下指令组成:
WithdrawAsset
— 从目标链中调度XCM的账户中提取资金,并将其存放在可用于后续操作的地方BuyExecution
— 购买一定数量的区块执行时间Transact
— 使用前一条指令购买的部分区块执行时间来执行一些任意字节DepositAsset
— 从持有的资产中提取资产并将其存入指定账户
要构建XCM消息(该消息将通过XCM发起远程EVM调用)并获取其SCALE编码的calldata,您可以使用以下代码片段:
import { ApiPromise, WsProvider } from '@polkadot/api'; // Version 9.13.6
// 1. Input Data
const providerWsURL =
'wss://frag-moonbase-relay-rpc-ws.g.moonbase.moonbeam.network';
const amountToWithdraw = BigInt(1 * 10 ** 16); // 0.01 DEV
const devMultiLocation = {
parents: 0,
interior: { X1: { PalletInstance: 3 } },
};
const weightTransact = 43500000000n; // 25000 * Gas limit of EVM call
const multiLocAccount = '0xf0615483cbe76f5b2aa80a8ce2b2e9a8206deb65'; // REPLACE with your multilocation-derivative account
const transactBytes =
'0x260001f0490200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008080000000000000000000000000000000000000000000000000000000000000000110896e292b8000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000001fc56b105c4f0a1a8038c2b429932b122f6b631f000000000000000000000000ed13b028697febd70f34cf9a9e280a8f1e98fd29000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000042004ffd90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000042004ffd900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000';
// 2. XCM Destination (Moonbase Alpha Parachain ID 1000)
const dest = { V3: { parents: 0, interior: { X1: { Parachain: 1000 } } } };
// 3. XCM Instruction 1
const instr1 = {
WithdrawAsset: [
{
id: { Concrete: devMultiLocation },
fun: { Fungible: amountToWithdraw },
},
],
};
// 4. XCM Instruction 2
const instr2 = {
BuyExecution: {
fees: {
id: { Concrete: devMultiLocation },
fun: { Fungible: amountToWithdraw },
},
weightLimit: { Unlimited: null },
},
};
// 5. XCM Instruction 3
const instr3 = {
Transact: {
originKind: 'SovereignAccount',
requireWeightAtMost: { refTime: weightTransact, proofSize: 200000n },
call: {
encoded: transactBytes,
},
},
};
// 6. XCM Instruction 4
const instr4 = {
DepositAsset: {
assets: { Wild: 'All' },
beneficiary: {
parents: 0,
interior: { X1: { AccountKey20: { key: multiLocAccount } } },
},
},
};
// 7. Build XCM Message
const message = { V3: [instr1, instr2, instr3, instr4] };
const generateCallData = async () => {
// 8. Create Substrate API Provider
const substrateProvider = new WsProvider(providerWsURL);
const api = await ApiPromise.create({ provider: substrateProvider });
// 9. Create the Extrinsic
const tx = api.tx.xcmPallet.send(dest, message);
// 10. Get SCALE Encoded Calldata
const encodedCall = tx.toHex();
console.log(`Encoded Calldata: ${encodedCall}`);
api.disconnect();
};
generateCallData();
注意事项
您也可以通过在Polkadot.js Apps中手动构建extrinsic来获取SCALE编码的calldata。
接下来,让我们看一下上面显示的代码片段的每个主要组件:
-
提供请求的输入数据。这包括:
- 创建提供商的Moonbase中继链端点URL
- 从multilocation衍生账户提取的Token数量(以Wei为单位)。在本示例中,
0.01
Token已经足够了。想要了解如何获取此值,请参考XCM费用页面 - DEV token的multilocation,如Moonbase Alpha所见
transact
XCM指令的权重。这可以通过将25000
乘以之前获得的gas限制来获得。建议在预估值的基础上增加10%左右。您可以在通过XCM远程EVM调用的页面获取关于此值的更多信息- multilocation衍生账户,这将用于后续XCM指令
- 我们上一部分计算的
transact
XCM指令的字节
-
定义XCM消息的目标multilocation。在本示例中为Moonbase Alpha平行链
- 第一个XCM指令
WithdrawAsset
。您需要提供资产multilocation以及您想要提取的金额。这两个变量已在之前描述过 - 第二个XCM指令
BuyExecution
。在这里,我们通过提供其multilocation和我们用上一个指令提取的金额,以DEV Token支付Moonbase Alpha区块的执行时间。接下来,我们将使用0.01 DEV
token购买我们可以购买的所有执行(Unlimited
权重),这应该约为200亿个权重单位,对于本示例来说足够了 - 第三个XCM指令
Transact
。该指令将使用购买的一部分权重(定义为requireWeightAtMost
)并执行提供的任意字节(transactBytes
) - 第四个XCM指令
DepositAsset
。执行之前的操作后剩下的部分(在本例中,应该只是DEV Token)都会存入multilocation衍生账户,设置为beneficiary
- 通过连接
V3
数组内的指令来构建XCM消息 - 创建Polkadot.js API提供商
- 使用目的地和XCM消息制作
xcmPallet.send
extrinsic。此方法会将DescendOrigin
XCM指令附加到我们的XCM消息中,该指令将提供计算multilocation衍生账户所需的信息 - 获取SCALE编码的calldata。请注意在此特殊场景中,由于我们需要完整的SCALE编码calldata,我们必须使用
tx.toHex()
。因此意味着我们将使用calldata提交此交易。
代码设置完毕后,您可以使用node
执行它。并且您将获取中继链XCM calldata:
本示例的编码calldata如下所示:
0xcd0a04630003000100a10f031000040000010403000f0000c16ff28623130000010403000f0000c16ff28623000601070053cd200a02350c007d09260001f0490200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008080000000000000000000000000000000000000000000000000000000000000000110896e292b8000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000001fc56b105c4f0a1a8038c2b429932b122f6b631f000000000000000000000000ed13b028697febd70f34cf9a9e280a8f1e98fd29000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000042004ffd90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000042004ffd9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d010000010300f0615483cbe76f5b2aa80a8ce2b2e9a8206deb65
注意事项
您的编码calldata应该略有不同,因为您需要将脚本中的multilocation衍生账户替换为您在计算Multilocation衍生帐户部分中创建的帐户。
现在我们已经有了SCALE编码的calldata,最后一步是提交交易,这会将我们的XCM消息发送到Moonbase Alpha,并执行远程批量EVM调用!
从中继链发送XCM消息¶
恭喜您已经进入最后一个部分。让我们先回顾一下目前所完成的内容:
- 我们已经创建了一个中继链账户,并为此账户充值了UNIT Token(中继链原生Token)
- 我们在Moonbase Alpha上确定了其multilocation衍生账户,并为此账户充值了DEV Token
- 我们获取了批量预编译calldata,其中结合了MARS和NEPT ERC-20 Token的两个mint调用
- 我们在Moonbase Alpha中构建了SCALE编码的calldata,以通过XCM访问其EVM
- 我们创建了交易,向Moonbase Alpha发送一条XCM消息,在该消息中我们将要求它执行之前构建的SCALE编码的calldata。 反过来,这将执行对批量预编译的调用,其中包括对MARS和 NEPT ERC-20 Token的mint调用!
要发送我们在上一节中构建的XCM消息,您可以使用以下代码片段:
import { ApiPromise, WsProvider } from '@polkadot/api'; // Version 9.13.6
import Keyring from '@polkadot/keyring'; // Version 10.3.1
// 1. Input Data
const providerWsURL =
'wss://frag-moonbase-relay-rpc-ws.g.moonbase.moonbeam.network';
const MNEMONIC = 'INSERT_MNEMONIC'; // Not safe, only for testing
const txCall =
'0xcd0a04630003000100a10f031000040000010403000f0000c16ff28623130000010403000f0000c16ff28623000601070053cd200a02350c007d09260001f0490200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008080000000000000000000000000000000000000000000000000000000000000000110896e292b8000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000001fc56b105c4f0a1a8038c2b429932b122f6b631f000000000000000000000000ed13b028697febd70f34cf9a9e280a8f1e98fd29000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000042004ffd90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000042004ffd9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d010000010300f0615483cbe76f5b2aa80a8ce2b2e9a8206deb65';
// 2. Create Keyring Instance
const keyring = new Keyring({ type: 'sr25519' });
const sendXCM = async () => {
// 3. Create Substrate API Provider
const substrateProvider = new WsProvider(providerWsURL);
const api = await ApiPromise.create({ provider: substrateProvider });
// 4. Create Account from Mnemonic
const alice = keyring.addFromUri(MNEMONIC);
// 5. Create the Extrinsic
const tx = await api.tx(txCall).signAndSend(alice, (result) => {
// 6. Check Transaction Status
console.log(`Transaction sent`);
if (result.status.isInBlock) {
console.log(
`Transaction included in blockHash ${result.status.asInBlock}`
);
}
});
api.disconnect();
};
sendXCM();
代码设置完毕后,您可以使用node
执行它,这将发送XCM消息以发起对Moonbase Alpha中的MARS和NEPT ERC-20 Token的批量预编译的调用。如果您看到Abnormal Closure
错误提示,请不要担心。您可以通过在Moonbase Moonscan上查找您的multilocation衍生账户来验证远程批量调用是否成功。
这样就可以了!您已成功发送一条XCM消息,这将通过XCM对批量预编译执行远程EVM调用并铸造 MARS和NEPT ERC-20 Token。接下来,让我们详细了解发生了什么。
此操作将发出不同的事件。第一个仅与中继链相关,其名称为 xcmPallet.Sent
,来自于xcmPallet.send
extrinsic。在Moonbase Alpha中,以下事件将由parachainSystem.setValidationData
extrinsic发出,此外部函数将处理所有的入站XCM消息:
parachainSystem.DownwardMessagesReceived
— 表明收到了XCM消息evm.Log
— 不同合约调用发出的内部事件。结构相同,为:合约地址、主题、相关数据ethereum.Executed
— 包含有关from
地址、to
地址以及EVM调用完成的交易哈希的信息polkadotXcm.AssetsTrapped
— 标记某些资产已被持有且未存入给定地址。如果Transact
XCM指令没有用完分配给它的Token,它将在处理XCM之后执行RefundSurplus
。该指令将从购买的执行中取出所有剩余的Token并将其持有。我们可以通过调整提供给Transact
指令的费用或在Transact
之后添加指令来防止这种情况发生dmpQueue.ExecutedDownward
— 表示执行从中继链接收到的消息(DMP消息)的结果。在此情况下,outcome
被标记为Complete
XCM已成功被执行!如果您访问Moonbase Alpha Moonscan并搜索交易哈希,您将找到通过XCM消息执行的批量预编译调用。请注意,每个planet每小时只能调用一次mint
命令。如果您想进一步操作并执行其他mint调用,只需在配置批量调用时将目标合约地址更改为不同的planet即可。
挑战
通过XCM使用批量预编译和远程EVM调用,将MARS批准和Uniswap V2兑换结合到您想要的任何其他Token。作为一个想法实验,请仔细考虑哪种批量预编译方法最适合结合批准和交换交易。通过XCM从波卡进行Uniswap V2兑换教程和批量预编译教程将能帮助您快速操作。
本教程仅用于教育目的。 因此,不应在生产环境中使用本教程中创建的任何合约或代码。
| Created: August 3, 2023