Skip to content

使用X-Tokens Pallet发送XC-20s

X-Tokens Precompile Contracts Banner

概览

为同质化资产转移构建XCM信息通道并非一件易事。因此,开发者可以通过利用wrapper函数/pallet在Polkadot/Kusama上使用XCM功能。

此类包装器的一个示例是X-Tokens pallet,用于提供通过XCM转移同质化资产的不同方法。

本教程将向您展示如何利用X-Tokens pallet在生态系统(中继链/平行链)中从基于Moonbeam的网络发送XC-20至其他链。此外,您还将学习到如何使用X-Tokens预编译通过以太坊API执行同样的操作。

开发者须知若发送不正确的XCM信息可能会导致资金丢失。因此,XCM功能需先在测试网上进行测试后才可移至生产环境。

相关XCM定义

  • XCM — 代表跨共识信息,是共识系统相互通信的信息格式
  • VMP — 代表垂直消息传递,它允许平行链与中继链交换消息。UMP(向上消息传递)允许平行链将消息发送到它们的中继链,而 DMP(向下消息传递)允许中继链将消息向下传递到它们的平行链之一
  • XCMP — 代表跨共识消息传递,它允许平行链与同一中继链上的其他平行链交换消息
  • HRMP — 代表平行中继路由消息传递,是启动完整XCMP实现前的过度实现方式。与XCMP具有相同的接口,但消息存储在中继链上
  • 主权账户 — 每条平行链在其他平行链上的预设账户。该帐户归root所支配,只能通过SUDO(如果有)或民主(技术委员会或公民投票)使用。主权账户通常在其它链上签署 XCM 消息
  • Multilocation — 一种指定整个中继链或平行链生态系统中来源点(相对或绝对来源)的方式;例如,它可用于指定特定的平行链、资产、账户,甚至是一个Pallet。一般而言,multilocation定义包含为parentsinteriorparents是指需要从来源点“跳跃”多少次可以进入parent区块链。interior,是指定义目标点需要多少个字段。例如,要从另一个平行链中定位ID为1000的平行链,multilocation将是 { "parents": 1, "interior": { "X1": [{ "Parachain": 1000 }]}}

X-Tokens Pallet接口

X-Tokens pallet提供以下extrinsics(函数):

  • transfer(currencyId, amount, dest, destWeight) —— 转移一个币种,根据原生Token(自身储备)或是资产ID定义
  • transferMultiasset(asset, dest, destWeight) —— 转移一种可替代资产,根据其multilocation定义
  • transferMultiassetWithFee(asset, fee, dest, destWeight) —— 转移一种可替代资产,但其能够让资产的发送者使用另外一种资产支付转移费用。两者皆根据其multilocation定义
  • transferMultiassets(assets, feeItem, dest, destWeight) —— 转移多种可替代资产,并定义其中哪种资产将会被用于支付转移费用。所有资产皆由其multilocation定义
  • transferMulticurrencies(currencies, feeItem, dest, destWeight) —— 转移多个币种,并定义其中哪种币种将会被用于支付转移费用。所有币种都将通过原生Token(自身储备)或是资产ID定义
  • transferWithFee(currencyId, amount, fee, dest, destWeight) —— 转移一个币种,但允许资产发送者使用不同的资产支付转移费用。两者皆由其multilocation定义

其中需要提供信息输入的函数定义如下:

  • currencyId/currencies —— 将通过XCM转移的币种ID。不同runtime有不同的方法定义ID。以基于Moonbeam的网络为例子,SelfReserve代表原生Token,ForeignAsset代表其XC-20资产ID(而不是其XC-20地址)
  • amount —— 将通过XCM转移的Token数量
  • dest —— 一个multilocation,用于定义将通过XCM转移Token的目标地址。其支持不同地址格式,如20或32字节的地址(以太坊或是Substrate格式)
  • destWeight —— 您提供给目标链希望其执行XCM信息的最大执行时间。如果您提供的信息不足,XCM将会执行失败,且资金将会被锁定在主权账户或是特定的pallet中。设置目标权重非常重要,这将避免XCM失败
  • asset/assets —— 一个用于定义将通过XCM转移资产的multilocation。每条平行链将会有不同定义资产的方式。举例而言,基于Moonbeam的网络将会经由其原生Token的pallet余额索引定义
  • fee —— 一个用于定义支付XCM在目标链上执行的multilocation
  • feeItem —— 一个用于定义多样资产发送地点的索引,将用于支付XCM在目标链上的执行。举例而言,如果仅有一种资产被发送,feeItem将会是0

唯一由pallet提供的只读函数为palletVersion,其提供使用的X-Tokens pallet的版本。

使用X-Tokens Pallet构建XCM信息

此教程将会包含使用X-Tokens pallet构建XCM信息的过程,更详细来说为使用transfertransferMultiasset函数。然而,这两种情况仍然可以外推至其他函数,特别是当您熟悉了多重地点的使用之后。

注意事项

每条平行链皆能够通过pallet允许/禁止特定函数。因此,开发者需要确认使用的函数是被平行链允许的。相反来说,如果使用了被禁止的函数,交易将会如同system.CallFiltered显示一般失败。

本教程将以转移xcUNIT token为例。xcUNIT是Alphanet中继链Token UNITXC-20形式,也是外部XC-20。本教程也同样适用于其他外部XC-20或可铸造XC-20

查看先决条件

要在Polikadot.js Apps上发送extrinsics,您需要准备以下内容:

Moonbeam Swap xcUNITs

要查看您的xcUNIT余额,您可以使用以下地址将XC-20添加至MetaMask:

0xFfFFfFff1FcaCBd218EDc0EbA20Fc2308C778080

您可以通过以下教程查看如何计算预编译地址:

X-Tokens转移函数

在本示例中,您将会构建一个XCM信息,通过X-Tokens pallet的transfer函数将xcUNIT从Moonbase Alpha转移回其中继链上。

导航至Polkadot.js Apps的extrinsic页面,并设定以下选项(也可以适用于可铸造XC-20s):

  1. 选取您希望转移XCM的账户
  2. 选择xTokens pallet
  3. 选择transfer extrinsic
  4. 将外部XC-20的币种ID设置为ForeignAsset或将可铸造XC-20的币种ID设置为LocalAssetReserve。因为xcUNIT是外部XC-20,所以您需要选择ForeignAsset
  5. 输入资产ID。在本示例中,xcUNIT的资产ID为42259045809535163221576417993425387648
  6. 设置需要转移的Token数量。在本示例中,您将转移1个xcUNIT,但您需要注意xcUNIT后有12位小数位
  7. 定义XCM目标multilocation,您需要将Moonbase Alpha的中继链中的一个账户作为初始点。因此,您需要设置以下参数:

    参数 数值
    Version V1
    Parents 1
    Interior X1
    X1 AccountId32
    Network Any
    Id Target Account
  8. 将目标权重设置为1000000000。请注意,在Moonbase Alpha上,每个XCM操作需要大概100000000权重单位。一个transfer包含4个XCM操作,因此目标权重应当设置为400000000左右

  9. 点击Submit Transaction按钮并签署交易

注意事项

以上extrinsict配置的编码调用数据为0x1e00018080778c30c20fa2ebc0ed18d2cbca1f0010a5d4e800000000000000000000000101010100c4db7bcb733e117c0b34ac96354b10d47e84a006b9e7e66a229d174e8ff2a06300ca9a3b00000000,这同样包含一个您需要改变的接收者函数。

XCM X-Tokens Transfer Extrinsic

当交易正在处理中,TargetAccount将会获取设定的转移数量并扣除用于在目标链上执行XCM的小额费用。在Polkadot.js Apps,您可以查看Moonbase Alpha以及中继链的相关extrinsics和事件。

X-Tokens转移多种资产函数

在本示例中,您将会构建一个XCM信息,通过X-Tokens pallet的transferMultiasset函数将xcUNIT从Moonbase Alpha转移回其中继链上。

导航至Polkadot JS Apps的extrinsic页面,并设定以下选项:

  1. 选取您希望转移XCM的账户

  2. 选择xTokens pallet

  3. 选择transferMultiasset extrinsic

  4. 定义XCM资产multilocation,您需要将Moonbase Alpha的中继链中的UNIT作为初始点。每条链皆有不同的定义方法。因此,您需要为各个目标设置不同的资产multilocation。在此例而言,中继链Token将会通过以下函数定义:

    参数 数值
    Version V1
    Parents 1
    Interior Here

    如果您要将本教程修改成适应可铸造XC-20资产,您需要指定创建资产和资产ID的pallet。因此,您需要设置以下参数:

    参数 数值
    Version V1
    Parents 1
    Interior X2
    PalletInstance 36
    GeneralIndex Asset ID
  5. 将资产类别设置为Fungible

  6. 设置需要转移的Token数量。在本示例中,您将转移1个xcUNIT,但您需要注意xcUNIT后有12位小数位

  7. 定义XCM目标multilocation,您需要将Moonbase Alpha的中继链中的一个账户作为初始点。因此,您需要设置以下参数:

    参数 数值
    Version V1
    Parents 1
    Interior X1
    X1 AccountId32
    Network Any
    Id Target Account
  8. 将目标权重设置为1000000000。请注意,在Moonbase Alpha上,每个XCM操作需要大概100000000权重单位。一个transferMultiasset包含4个XCM操作,因此目标权重应当设置为400000000左右

  9. 点击Submit Transaction按钮并签署交易

注意事项

以上extrinsict配置的编码调用数据为0x1e010100010000070010a5d4e80101010100c4db7bcb733e117c0b34ac96354b10d47e84a006b9e7e66a229d174e8ff2a06300ca9a3b00000000,这同样包含一个您需要改变的接收者函数。

XCM X-Tokens Transfer Extrinsic

当交易正在处理中,TargetAccount将会获取设定的转移数量并扣取用于在目标链上执行XCM的小额费用。在Polkadot.js Apps,您可以查看Moonbase Alpha以及中继链的相关extrinsics和事件。

XC-Tokens预编译

X-Tokens预编译合约将会允许开发者通过基于Moonbeam网络的以太坊API访问XCM Token转移功能。如同其他预编译合约,X-Tokens预编译位于以下地址:

0x0000000000000000000000000000000000000804
0x0000000000000000000000000000000000000804
0x0000000000000000000000000000000000000804

X-Tokens Solidity接口

Xtokens.sol是一个开发者能够使用以太坊API与X-Tokens pallet交互的接口。

此接口包含以下函数:

  • transfer(address currency_address, uint256 amount, Multilocation memory destination, uint64 weight) —— 用于表示先前示例中提及的transfer函数。然而,在使用币种ID之外,您需要为currency_address提供资产预编译地址:

    destination multilocation将会以一种特殊形式构建(我们将在下一部分提及)

  • transfer_multiasset(Multilocation memory asset, uint256 amount, Multilocation memory destination, uint64 weight) —— 用于表示先前示例中提及的transferMultiasset函数。两种multilocation将会以一种特殊形式构建(我们将在下一部分提及)

构建预编译Multilocation

在X-Tokens预编译接口中,Multilocation架构根据下列函数定义:

 struct Multilocation {
    uint8 parents;
    bytes [] interior;
}

请注意每个multilocation皆有parents元素,请使用uint8和一组字节定义。Parents代表有多少“hops”在通过中继链中您需要执行的传递向上方向。作为uint8,您将会看到以下数值:

Origin Destination Parents Value
Parachain A Parachain A 0
Parachain A Relay Chain 1
Parachain A Parachain B 1

字节阵列(bytes[])定义了内部参数以及其在multilocation的内容。阵列的大小则根据以下定义interior数值:

Array Size Interior Value
[] 0 Here
[XYZ] 1 X1
[XYZ, ABC] 2 X2
[XYZ, ... N] N XN

注意事项

内部值Here通常用于中继链(作为目标链或以中继链资产为目标)。

假设所有字节阵列包含数据。所有元素的首个字节(2个十六进制数值)与XN部分的选择器相关,举例来说:

Byte Value Selector Data Type
0x00 Parachain bytes4
0x01 AccountId32 bytes32
0x02 AccountIndex64 u64
0x03 AccountKey20 bytes20
0x04 PalletInstance byte
0x05 GeneralIndex u128
0x06 GeneralKey bytes[]

接着,根据选择器及其数据类型,以下字节对应于提供的实际数据。请注意在Polkadot.js Apps示例中出现的AccountId32AccountIndex64AccountKey20network将会在最后添加。如下所示:

Selector Data Value Represents
Parachain "0x00+000007E7" Parachain ID 2023
AccountId32 "0x01+AccountId32+00" AccountId32, Network Any
AccountKey20 "0x03+AccountKey20+00" AccountKey20, Network Any
PalletInstance "0x04+03" Pallet Instance 3

注意事项

interior数据通常需要使用引号包含。如果您未遵循此规则,您将会获得invalid tuple value错误。

以下代码片段包含Multilocation架构的部分示例,因为其将会在X-Token预编译函数中使用:

// Multilocation targeting the relay chain or its asset from a parachain
{
    1, // parents = 1
    [] // interior = here
}

// Multilocation targeting Moonbase Alpha DEV token from another parachain
{
    1, // parents = 1
    // Size of array is 2, meaning is an X2 interior
    [
        "0x00000003E8", // Selector Parachain, ID = 1000 (Moonbase Alpha)
        "0x0403" // Pallet Instance = 3
    ]
}

// Multilocation targeting Alice's account on the Relay Chain from Moonbase Alpha
{
    1, // parents = 0
    // Size of array is 1, meaning is an X1 interior
    [
        "0x01c4db7bcb733e117c0b34ac96354b10d47e84a006b9e7e66a229d174e8ff2a06300" 
        // AccountKey32 Selector + Address in hex + Network = Any
    ]
}