使用X-Tokens Pallet发送XC-20s¶
概览¶
为同质化资产转移构建XCM消息通道并非一件易事。因此,开发者可以通过利用wrapper函数/pallet在Polkadot/Kusama上使用XCM功能。
此类包装器的一个示例是X-Tokens Pallet,用于提供通过XCM转移同质化资产的不同方法。
本教程将向您展示如何利用X-Tokens Pallet在生态系统(中继链/平行链)中从基于Moonbeam的网络发送XC-20s至其他链。此外,您还将学习如何使用X-Tokens预编译通过以太坊API执行同样的操作。
开发者须知若发送不正确的XCM消息可能会导致资金丢失。因此,XCM功能需先在测试网上进行测试后才可移至生产环境。
XCM相关定义¶
本教程假设您已经拥有基础的XCM知识。如果没有,请阅读XCM概览页面。
对于本指南,您需要了解以下定义:
- 主权账户 — 生态系统中每条链预设的账户,用于中继链和其他平行链。它的地址为特定单词和平行链ID连接的
blake2
哈希(中继链中的主权账户为blake2(para+ParachainID)
,其他中的主权账户为blake2(sibl+ParachainID)
平行链),将哈希截断为正确的长度。该帐户归root所支配,只能通过SUDO(如果有)或民主(公投)使用。主权账户通常在其它链上签署 XCM 消息 -
Multilocation — 一种指定整个中继链或平行链生态系统中来源点(相对或绝对来源)的方式;例如,它可用于指定特定的平行链、资产、账户,甚至是一个Pallet。一般而言,multilocation定义包含为
parents
和interior
:parents
- 是指需要从来源点“跳跃”多少次可以进入parent
区块链interior
,是指定义目标点需要多少个字段
例如,要从另一个平行链中定位ID为
1000
的平行链,multilocation将是{ "parents": 1, "interior": { "X1": [{ "Parachain": 1000 }]}}
X-Tokens Pallet接口¶
Extrinsics¶
X-Tokens Pallet提供以下extrinsics(函数):
- transfer(currencyId, amount, dest, destWeightLimit) — 转移一个币种,根据原生Token(自身储备)或是资产ID定义
- transferMultiasset(asset, dest, destWeightLimit) — 转移一种同质化资产,根据其multilocation定义
- transferMultiassetWithFee(asset, fee, dest, destWeightLimit) — 转移一种同质化资产,但其能够让资产的发送者使用另外一种资产支付转移费用。两者皆根据其multilocation定义
- transferMultiassets(assets, feeItem, dest, destWeightLimit) — 转移多种同质化资产,并定义其中哪种资产将会被用于支付转移费用。所有资产皆由其multilocation定义
- transferMulticurrencies(currencies, feeItem, dest, destWeightLimit) — 转移多个币种,并定义其中哪种币种将会被用于支付转移费用。所有币种都将通过原生Token(自身储备)或是资产ID定义
- transferWithFee(currencyId, amount, fee, dest, destWeightLimit) — 转移一个币种,但允许资产发送者使用不同的资产支付转移费用。两者皆由其multilocation定义
其中需要提供消息输入的函数定义如下:
-
currencyId/currencies — 将通过XCM转移的币种ID。不同runtime有不同的方法定义ID。以基于Moonbeam的网络为例子,币种可以被定义为:
SelfReserve
- 代表原生TokenForeignAsset
- 代表外部XC-20(请不要与XC-20地址混淆)的资产IDLocalAssetReserve
- 弃用 通过使用Erc20
货币类型来使用 local XC-20sErc20
- 代表本地XC-20(ERC-20)的合约地址
-
amount — 将通过XCM转移的Token数量
- dest — 一个multilocation,用于定义将通过XCM转移Token的目标地址。其支持不同地址格式,如20或32字节的地址(以太坊或是Substrate格式)
-
destWeightLimit — 一个枚举,表示您提供给目标链希望其执行XCM消息的最大执行时间。该枚举包含以下选项:
Unlimited
- 允许使用全部gas来支付权重Limited
- 将gas的使用量限制为特定值
如果您提供的权重不足,XCM将会执行失败,且资金将会被锁定在主权账户或是特定的pallet中。正确设置目标权重非常重要,这将避免XCM失败
-
asset/assets — 个用于定义通过XCM转移资产的multilocation。每条平行链将会有不同定义资产的方式。举例而言,基于Moonbeam的网络将会由其原生Token的Balances Pallet索引定义
- fee — 一个用于定义支付XCM在目标链上执行的multilocation
- feeItem — 一个用于定义发送多样资产位置的索引,将用于支付XCM在目标链上的执行。举例而言,如果仅发送一种资产,
feeItem
将会是0
存储函数¶
X-Tokens Pallet包含以下只读存储函数:
- palletVersion() - 提供正在使用的X-Tokens Pallet的版本
Pallet常量¶
X-Tokens Pallet包含以下只读函数以获取pallet常量:
- baseXcmWeight() - 返回执行所需的基础XCM权重
- selfLocation() - 返回链的multilocation
使用X-Tokens Pallet构建XCM消息¶
此教程将会包含使用X-Tokens Pallet构建XCM消息的过程,更详细来说为使用transfer
和transferMultiasset
函数。然而,这两种情况仍然可以外推至其他函数,特别是当您熟悉了multilocation的使用之后。
注意事项
每条平行链皆能够通过pallet允许/禁止特定函数。因此,开发者需要确认使用的函数是被平行链允许的。相反来说,如果使用了被禁止的函数,交易将会如同system.CallFiltered
显示一般失败。
本教程将以转移xcUNIT Token为例。xcUNIT是Alphanet中继链Token的XC-20形式。本教程也同样适用于其他XC-20 Token。
查看先决条件¶
要跟随本教程操作,您需要准备以下内容:
- 一个拥有资金的账户。 您可以每24小时一次从Moonbase Alpha水龙头上获取DEV代币以在Moonbase Alpha上进行测试
-
一些xcUNIT Token。您可以在Moonbeam-Swap上将DEV Token(Moonbase Alpha的原生Token)兑换成xcUNIT。Moonbeam-Swap是Moonbase Alpha上的Uniswap-V2版本的示范协议。
要查看您的xcUNIT余额,您可以使用以下地址将XC-20添加至MetaMask:
0xFfFFfFff1FcaCBd218EDc0EbA20Fc2308C778080
注意事项
想要了解如何计算预编译地址,您可以查看计算外部XC-20预编译地址教程。
本教程也同样适用于其他的外部XC-20或本地XC-20。如果您要针对另一个外部XC-20调整本教程,您需要拥有要转移资产的资产ID以及该资产的小数位数,您可以根据外部XC-20s的检索列表获取这些信息。如果您要针对本地XC-20调整本教程,则需要拥有XC-20的合约地址。
如果您要转移本地XC-20,请注意每个网络的转移仅限于以下gas单位:
200,000
200,000
200,000
X-Tokens转移函数¶
在本示例中,您将会构建一个XCM消息,通过X-Tokens Pallet的transfer
函数将xcUNIT从Moonbase Alpha转移回其中继链上。为此,您需要使用Polkadot.js API。
由于您将使用X-Tokens Pallet的transfer
函数进行交互,您可以执行以下步骤来获取currencyId
、amount
、dest
和destWeightLimit
的参数:
-
定义
currencyId
。对于外部XC-20,您将使用ForeignAsset
货币类型和资产ID,在本示例中为42259045809535163221576417993425387648
。对于本地XC-20,您将需要Token地址。在JavaScript中,将翻译为:const currencyId = { ForeignAsset: { ForeignAsset: 42259045809535163221576417993425387648n } };
const currencyId = { Erc20: { contractAddress: 'INSERT_ERC_20_ADDRESS' } };
-
指定要转移的
amount
。在本示例中,您将发送1个xcUNIT,即有12位小数位:const amount = 1000000000000n;
-
定义目的地的multilocation,这将定位来自Moonbase Alpha的中继链上的账户。请注意,中继链可以接收的唯一资产是它自己的:
const dest = { V3: { parents: 1, interior: { X1: { AccountId32: { id: relayAccount } } } } };
注意事项
对于
AccountId32
、AccountIndex64
或AccountKey20
,您可以选择指定network
参数。如果不指定,则默认为None
。 -
将
destWeightLimit
设置为Unlimited
。在JavaScript中,您需要将Unlimited
设置为null
(如XcmV3WeightLimit
的TypeScript接口中所述):const destWeightLimit = { Unlimited: null };
注意事项
如果您想限制目标权重,可以使用
Limited
来实现,这需要您输入refTime
和proofSize
的值。其中refTime
是可用于执行的计算时间量,proofSize
是可使用的存储量(以字节为单位)。在JavaScript中,这会转换为:
{ Limited: { refTime: 'INSERT_ALLOWED_AMOUNT', proofSize: 'INSERT_ALLOWED_AMOUNT' } };
现在您已经有了每个参数的值,您可以编写传送脚本了。 为此,您需要执行以下步骤:
- 提供调用的输入数据,这包含:
- 用于创建提供商的Moonbase Alpha端点URL
transfer
函数的每个参数值
- 创建Keyring实例,这将用于传送交易
- 创建Polkadot.js API提供商
- 使用
currencyId
、amount
、dest
和destWeightLimit
构建xTokens.transfer
extrinsic - 使用
signAndSend
extrinsic(函数)和第二步创建的Keyring实例发送交易
请记住
本教程仅用于演示目的,请勿将您的私钥存储在JavaScript文件中。
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api'; // Version 9.13.6
// 1. Provide input data
const providerWsURL = 'wss://wss.api.moonbase.moonbeam.network';
const privateKey = 'INSERT_PRIVATE_KEY';
const relayAccount =
'0xc4db7bcb733e117c0b34ac96354b10d47e84a006b9e7e66a229d174e8ff2a063'; // Alice's relay account address
const currencyId = {
ForeignAsset: {
ForeignAsset: 42259045809535163221576417993425387648n
}
};
const amount = 1000000000000n;
const dest = {
V3: {
parents: 1,
interior: { X1: { AccountId32: { id: relayAccount } } },
},
};
const destWeightLimit = { Unlimited: null };
// 2. Create Keyring instance
const keyring = new Keyring({ type: 'ethereum' });
const alice = keyring.addFromUri(privateKey);
const sendXc20 = async () => {
// 3. Create Substrate API provider
const substrateProvider = new WsProvider(providerWsURL);
const api = await ApiPromise.create({ provider: substrateProvider });
// 4. Craft the extrinsic
const tx = api.tx.xTokens.transfer(currencyId, amount, dest, destWeightLimit);
// 5. Send the transaction
const txHash = await tx.signAndSend(alice);
console.log(`Submitted with hash ${txHash}`);
api.disconnect();
};
sendXc20();
注意事项
您可以使用以下编码的调用数据在Polkadot.js Apps上查看上述脚本的示例,该脚本将1个xcUNIT发送到中继链上Alice的账户:0x1e00018080778c30c20fa2ebc0ed18d2cbca1f0010a5d4e8000000000000000000 00000301010100c4db7bcb733e117c0b34ac96354b10d47e84a006b9e7e66a229d174e8ff2a06300
。
交易被处理后,中继链上的目标账户应该收到转账金额减去在目标链上执行XCM时扣除的一小笔费用。
X-Tokens转移MultiAsset(多种资产)函数¶
在本示例中,您将会构建一个XCM消息,通过X-Tokens Pallet的transferMultiasset
函数将xcUNIT从Moonbase Alpha转移回其中继链上。
由于您将使用X-Tokens Pallet的transferMultiasset
函数进行交互,您可以执行以下步骤来获取asset
、dest
和destWeightLimit
的参数:
-
定义
asset
的XCM资产multilocation,这将以Moonbase Alpha为起点的中继链中的UNIT Token为目标。每个链对自己的资产都有不同的看法。因此,您必须为每个目的地设置不同的资产multilocation// Multilocation for UNIT in the relay chain const asset = { V3: { id: { Concrete: { parents: 1, interior: null, }, }, fun: { Fungible: { Fungible: 1000000000000n }, // 1 token }, }, };
// Multilocation for a local XC-20 on Moonbeam const asset = { V3: { id: { Concrete: { parents: 0, interior: { X2: [{ PalletInstance: 48 }, { AccountKey20: { key: 'INSERT_ERC_20_ADDRESS' } }], }, }, }, fun: { Fungible: { Fungible: 1000000000000000000n }, // 1 token }, }, };
-
定义
dest
的XCM目的地multilocation,这将以Moonbase Alpha的中继链中的一个账户为起点:const dest = { V3: { parents: 1, interior: { X1: { AccountId32: { id: relayAccount } } }, }, };
注意事项
对于
AccountId32
、AccountIndex64
或AccountKey20
,您可以选择指定network
参数。如果不指定,则默认为None
。 -
将目的地权重限制设置为
Unlimited
。在JavaScript中,您需要将Unlimited
设置为null
(如XcmV3WeightLimit
的TypeScript接口中所述:const destWeightLimit = { Unlimited: null };
注意事项
如果您想限制目的地权重,可以使用
Limited
来实现,这需要您输入refTime
和proofSize
的值。其中refTime
是可用于执行的计算时间量,proofSize
是可使用的存储量(以字节为单位)。在JavaScript中,这会转换为:
{ Limited: { refTime: 'INSERT_ALLOWED_AMOUNT', proofSize: 'INSERT_ALLOWED_AMOUNT' } };
现在您已经有了每个参数的值,您可以编写转移脚本了。为此,您将执行以下步骤:
- 提供调用的输入数据,这包含:
- 用于创建提供商的Moonbase Alpha端点URL
transferMultiasset
函数的每个参数值
- 创建Keyring实例,这将用于传送交易
- 创建Polkadot.js API提供商
- 使用
asset
、dest
和destWeightLimit
创建xTokens.transferMultiasset
extrinsic - 使用
signAndSend
extrinsic和第二步创建的Keyring实例发送交易
请记住
本教程仅用于演示目的,请勿将您的私钥存储在JavaScript文件中。
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api'; // Version 9.13.6
// 1. Provide input data
const providerWsURL = 'wss://wss.api.moonbase.moonbeam.network';
const privateKey = 'INSERT_PRIVATE_KEY';
const relayAccount =
'0xc4db7bcb733e117c0b34ac96354b10d47e84a006b9e7e66a229d174e8ff2a063'; // Alice's relay account address
const asset = {
V3: {
id: {
Concrete: {
parents: 1,
interior: null,
},
},
fun: {
Fungible: { Fungible: 1000000000000n },
},
},
};
const dest = {
V3: {
parents: 1,
interior: { X1: { AccountId32: { id: relayAccount } } },
},
};
const destWeightLimit = { Unlimited: null };
// 2. Create Keyring instance
const keyring = new Keyring({ type: 'ethereum' });
const alice = keyring.addFromUri(privateKey);
const sendXc20 = async () => {
// 3. Create Substrate API provider
const substrateProvider = new WsProvider(providerWsURL);
const api = await ApiPromise.create({ provider: substrateProvider });
// 4. Craft the extrinsic
const tx = api.tx.xTokens.transferMultiasset(asset, dest, destWeightLimit);
// 5. Send the transaction
const txHash = await tx.signAndSend(alice);
console.log(`Submitted with hash ${txHash}`);
api.disconnect();
};
sendXc20();
注意事项
您可以使用以下编码的调用数据在Polkadot.js Apps上查看上述脚本的示例,该脚本将1个xcUNIT发送到中继链上Alice的账户:0x1e010300010000070010a5d4e80301010100c4db7bcb733e117c0b34ac96354b10d47e84a006b9e7e66a229d174e8ff2a06300
。
交易被处理后,中继链上的目标账户应该收到转账金额减去在目标链上执行XCM时扣除的一小笔费用。
XC-Tokens预编译¶
X-Tokens预编译合约将会允许开发者通过基于Moonbeam网络的以太坊API访问XCM Token转移功能。如同其他预编译合约,X-Tokens预编译位于以下地址:
0x0000000000000000000000000000000000000804
0x0000000000000000000000000000000000000804
0x0000000000000000000000000000000000000804
注意事项
在Moonbeam使用预编译合约时,可能会出现一些意想不到的后果。 请参阅安全注意事项 页面了解更多信息。
X-Tokens Solidity接口¶
Xtokens.sol是一个开发者能够使用以太坊API与X-Tokens Pallet交互的接口。
此接口包含以下函数:
-
transfer(address currencyAddress, uint256 amount, Multilocation memory destination, uint64 weight) — 用于表示上述示例中提及的
transfer
函数。然而,在使用币种ID之外,您需要为currencyAddress
提供资产地址:- 对于外部XC-20s,您可以提供XC-20预编译地址
- 对于原生Token(如GLMR、MOVR和DEV),您可以提供ERC-20预编译地址,即
0x0000000000000000000000000000000000000802
- 对于本地XC-20s,您可以提供Token的地址
destination
multilocation将会以一种特殊形式构建(我们将在下一部分提及) -
transferMultiasset(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示例中出现的AccountId32
,AccountIndex64
和AccountKey20
,network
将会在最后添加。如下所示:
Selector | Data Value | Represents |
---|---|---|
Parachain | "0x00+000007E7" | Parachain ID 2023 |
AccountId32 | "0x01+AccountId32+00" | AccountId32, Network(Option) Null |
AccountId32 | "0x01+AccountId32+02" | AccountId32, Network Polkadot |
AccountKey20 | "0x03+AccountKey20+00" | AccountKey20, Network(Option) Null |
PalletInstance | "0x04+03" | Pallet Instance 3 |
注意事项
interior
数据通常需要使用引号包含。如果您未遵循此规则,您将会获得invalid tuple value
错误。
以下代码片段介绍了Multilocation
结构的一些示例,因为它们需要输入到X-Tokens预编译函数中:
// 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 = 1
// Size of array is 1, meaning is an X1 interior
[
'0x01c4db7bcb733e117c0b34ac96354b10d47e84a006b9e7e66a229d174e8ff2a06300'
// AccountKey32 Selector + Address in hex + Network(Option) Null
]
}
使用库与X-Tokens交互¶
使用库与以太坊API交互时,Multilocation结构可以像任何其他结构一样进行格式化。以下代码片段包括上述提及的X-Tokens转移函数、X-Tokens多资产转移函数和Multilocation结构示例。您可以在Github上找到X-Tokens ABI。
import ABI from './xtokensABI.js'; // Import the X-Tokens ABI
import { ethers } from 'ethers'; // Import Ethers library
const privateKey = 'INSERT_PRIVATE_KEY';
// Create Ethers wallet & contract instance
const provider = new ethers.providers.JsonRpcProvider(
'https://rpc.api.moonbase.moonbeam.network'
);
const signer = new ethers.Wallet(privateKey, provider);
const xTokens = new ethers.Contract(
'0x0000000000000000000000000000000000000804',
ABI,
signer
);
// xcUNIT address in Moonbase Alpha
const xcUnitAddress = '0xFfFFfFff1FcaCBd218EDc0EbA20Fc2308C778080';
// Multilocation targeting Alice's account on the relay chain from Moonbase Alpha
const aliceRelayAccount = [
1,
['0x01c4db7bcb733e117c0b34ac96354b10d47e84a006b9e7e66a229d174e8ff2a06300'],
];
// Sends 1 xcUNIT to the relay chain using the transfer function
async function transferToAlice() {
// Creates, signs, and sends the transfer transaction
const transaction = await xTokens.transfer(
xcUnitAddress, // Asset
'1000000000000', // Amount
aliceRelayAccount, // Destination
'1000000000' // Weight
);
// Waits for the transaction to be included in a block
await transaction.wait();
console.log(transaction);
}
// Multilocation targeting the relay chain or its asset from a parachain
const relayChainAsset = [1, []];
// Sends 1 xcUNIT to the relay chain using the transferMultiasset function
async function transferMultiassetToAlice() {
const transaction = await xTokens.transferMultiasset(
relayChainAsset, // Asset
'1000000000000', // Amount
aliceRelayAccount, // Destination
'1000000000' // Weight
);
await transaction.wait();
console.log(transaction);
}
transferToAlice();
transferMultiassetToAlice();
// Here are some additional multilocations for the Asset multilocation:
const localAsset = [0, ['0x0424', '0x05FD9D0BF45A2947A519A741C4B9E99EB6']]; // Note that 0x0424 indicates the x-tokens pallet
const devFromOtherParachain = [1, ['0x00000003E8', '0x0403']]; // Use if you were targeting DEV from a non-Moonbeam network
// Here are some additional multilocations for the Destination multilocation:
const address32OfParachain = [
1,
[
'0x00000007EF',
'0x01c4db7bcb733e117c0b34ac96354b10d47e84a006b9e7e66a229d174e8ff2a06300',
],
];
const address20FromParachainToMoonbase = [
1,
['0x00000003E8', '0x03f24FF3a9CF04c71Dbc94D0b566f7A27B94566cac00'],
];
import ABI from './xtokensABI.js'; // Import the X-Tokens ABI
import { Web3 } from 'web3'; // Import Web3 library
const privateKey = 'INSERT_PRIVATE_KEY';
const accountFrom = web3.eth.accounts.privateKeyToAccount(privateKey).address;
// Create Web3 wallet & contract instance
const web3 = new Web3('https://rpc.api.moonbase.moonbeam.network'); // Change to network of choice
const xTokens = new web3.eth.Contract(
ABI,
'0x0000000000000000000000000000000000000804',
{ from: accountFrom } // 'from' is necessary for gas estimation
);
// xcUNIT address in Moonbase Alpha
const xcUnitAddress = '0xFfFFfFff1FcaCBd218EDc0EbA20Fc2308C778080';
// Multilocation targeting Alice's account on the relay chain from Moonbase Alpha
const aliceRelayAccount = [
1,
['0x01c4db7bcb733e117c0b34ac96354b10d47e84a006b9e7e66a229d174e8ff2a06300'],
];
// Sends 1 xcUNIT to the relay chain using the transfer function
async function transferToAlice() {
// Create transaction
const transferTx = xTokens.methods.transfer(
xcUnitAddress, // Asset
'1000000000000', // Amount
aliceRelayAccount, // Destination
'1000000000' // Weight
);
// Sign transaction
const signedTx = await web3.eth.accounts.signTransaction(
{
to: '0x0000000000000000000000000000000000000804',
data: transferTx.encodeABI(),
gas: await transferTx.estimateGas(),
gasPrice: await web3.eth.getGasPrice(),
nonce: await web3.eth.getTransactionCount(accountFrom),
},
privateKey
);
// Send signed transaction
const sendTx = await web3.eth.sendSignedTransaction(signedTx.rawTransaction);
console.log(sendTx);
}
// Multilocation targeting the relay chain or its asset from a parachain
const relay_chain_asset = [1, []];
// Sends 1 xcUNIT to the relay chain using the transferMultiasset function
async function transferMultiassetToAlice() {
const transferTx = xTokens.methods.transferMultiasset(
relay_chain_asset, // Asset
'1000000000000', // Amount
aliceRelayAccount, // Destination
'1000000000' // Weight
);
const signedTx = await web3.eth.accounts.signTransaction(
{
to: '0x0000000000000000000000000000000000000804',
data: transferTx.encodeABI(),
gas: await transferTx.estimateGas(),
gasPrice: await web3.eth.getGasPrice(),
nonce: await web3.eth.getTransactionCount(accountFrom),
},
privateKey
);
const sendTx = await web3.eth.sendSignedTransaction(signedTx.rawTransaction);
console.log(sendTx);
}
transferToAlice();
transferMultiassetToAlice();
// Here are some additional multilocations for the Asset multilocation:
const localAsset = [0, ['0x0424', '0x05FD9D0BF45A2947A519A741C4B9E99EB6']]; // Note that 0x0424 indicates the x-tokens pallet
const devFromOtherParachain = [1, ['0x00000003E8', '0x0403']]; // Use if you were targeting DEV from a non-Moonbeam network
// Here are some additional multilocations for the Destination multilocation:
const address32OfParachain = [
1,
[
'0x00000007EF',
'0x01c4db7bcb733e117c0b34ac96354b10d47e84a006b9e7e66a229d174e8ff2a06300',
],
];
const address20FromParachainToMoonbase = [
1,
['0x00000003E8', '0x03f24FF3a9CF04c71Dbc94D0b566f7A27B94566cac00'],
];
from web3 import Web3
abi = "INSERT_XTOKENS_ABI" # Paste or import the x-tokens ABI
private_key = "INSERT_PRIVATE_KEY" # This is for demo purposes, never store your private key in plain text
address = "INSERT_ADDRESS" # The wallet address that corresponds to your private key
# Create Web3 wallet & contract instance
web3 = Web3(Web3.HTTPProvider("https://rpc.api.moonbase.moonbeam.network"))
x_tokens = web3.eth.contract(
address="0x0000000000000000000000000000000000000804", abi=abi
)
# xcUNIT address in Moonbase Alpha
xcUnit_address = "0xFfFFfFff1FcaCBd218EDc0EbA20Fc2308C778080"
# Multilocation targeting Alice's account on the relay chain from Moonbase Alpha
alice_relay_account = [
1,
["0x01c4db7bcb733e117c0b34ac96354b10d47e84a006b9e7e66a229d174e8ff2a06300"],
]
# Sends 1 xcUNIT to the relay chain using the transfer function
def transfer_to_alice():
# Create transaction
transferTx = x_tokens.functions.transfer(
xcUnit_address, # Asset
1000000000000, # Amount
alice_relay_account, # Destination
1000000000, # Weight
).build_transaction(
{
"from": address,
"nonce": web3.eth.get_transaction_count(address),
}
)
# Sign transaction
signedTx = web3.eth.account.sign_transaction(transferTx, private_key)
# Send tx and wait for receipt
hash = web3.eth.send_raw_transaction(signedTx.rawTransaction)
receipt = web3.eth.wait_for_transaction_receipt(hash)
print(f"Tx successful with hash: { receipt.transactionHash.hex() }")
# Multilocation targeting the relay chain or its asset from a parachain
relay_chain_asset = [1, []]
# Sends 1 xcUNIT to the relay chain using the transferMultiasset function
def transfer_multiasset_to_alice():
transferTx = x_tokens.functions.transferMultiasset(
relay_chain_asset, # Asset
1000000000000, # Amount
alice_relay_account, # Destination
1000000000, # Weight
).build_transaction(
{
"from": address,
"nonce": web3.eth.get_transaction_count(address),
}
)
signedTx = web3.eth.account.sign_transaction(transferTx, private_key)
hash = web3.eth.send_raw_transaction(signedTx.rawTransaction)
receipt = web3.eth.wait_for_transaction_receipt(hash)
print(f"Tx successful with hash: { receipt.transactionHash.hex() }")
transfer_to_alice()
transfer_multiasset_to_alice()
# Here are some additional multilocations for the Asset multilocation:
local_asset = [
0,
["0x0424", "0x05FD9D0BF45A2947A519A741C4B9E99EB6"],
] # Note that 0x0424 indicates the x-tokens pallet
dev_from_other_parachain = [
1,
["0x00000003E8", "0x0403"],
] # Use if you were targeting DEV from a non-Moonbeam network
# Here are some additional multilocations for the Destination multilocation:
address32_of_parachain = [
1,
[
"0x00000007EF",
"0x01c4db7bcb733e117c0b34ac96354b10d47e84a006b9e7e66a229d174e8ff2a06300",
],
]
address20_from_parachain_to_moonbase = [
1,
["0x00000003E8", "0x03f24FF3a9CF04c71Dbc94D0b566f7A27B94566cac00"],
]
注意事项
要在Moonbeam或Moonriver上测试上述示例,您可以将RPC URL替换为您自己的端点和API密钥,您可以从支持的端点提供商中获取该密钥。
| Created: April 29, 2022