Moonbeam上的XCM费用¶
概览¶
XCM旨在成为共识系统之间沟通的语言。传送XCM消息包含一系列在原链和目标链上执行的指令。XCM指令的集合将执行如Token转账等不同的动作。要处理和执行每个XCM指令,基本上皆需支付一定数量的相关费用。
然而,XCM技术被设计为通用、可扩展且高效,因此才能够在发展的生态当中保持可用和潜力。正因如此,其通用性适用于包含XCM执行费用支付的概念。在以太坊中,费用包含在交易协议之中,而在波卡生态当中,每条平行链皆有能够定义XCM支付该如何处理的能力。
本教程将会包含费用支付,如谁该负责支付XCM执行费用、该如何支付以及如何在Moonbeam上计算费用。
注意事项
以下信息仅供参考。权重(weight)和extrinsic基础成本自撰写本文时可能已发生变化。请确保检查实际值,切勿将以下信息用于生产环境应用程序。
费用支付¶
一般来说,费用支付的过程如下:
- 提供所需资产
- 必须协商资产交换计算时间(或权重)
- 在提供的权重限制或资金足够执行的情况下,XCM将会如指令描述运行
每条链皆能够配置XCM费用的组成,以及使用哪些Token支付(不论是原生或是外部资产)。举例来说,波卡和Kusama上的费用可分别由DOT和KSM支付给区块的验证人。在Moonbeam和Moonriver,XCM执行费用能够使用原生储备资产(分别为GLMR和MOVR)支付,但用户也能够使用源自其他链的资产支付,其费用将会被传送至财政库中。
您可以想像以下情景:Alice在波卡上拥有一定数量的DOT,她想要传送至Moonbeam给Alith。Alice因此传送了一个包含一系列XCM指令的XCM消息,将从Alice波卡上的账户拿取一定量的DOT并将铸造相同数量的xcDOT至Alith的账户。部分指令将会在波卡上执行,而其他部分指令将会在Moonbeam上执行。
那究竟Alice是如何在Moonbeam完成支付,执行她的指令完成其请求?她的请求将会通过一系列包含在XCM消息中的XCM指令完成,允许其在扣除相关XCM执行费用后购买执行时间。此处的执行时间将会用于发行和转移xcDOT,xcDOT为DOT在Moonbeam上的表现形式。这代表当Alice传送一些DOT至Alith在Moonbeam上的账户时,她将会在扣除XCM执行费用后获得与原先DOT数量比例为1:1的xcDOT。请注意在此情境中,XCM的执行费用以xcDOT支付。
Alice请求的资产转移过程如下:
- 资产将会传送Moonbeam在波卡上的账户(主权账户),并在收到资产后传送XCM消息至Moonbeam
- 传送至Moonbeam的XCM消息将会:
- 铸造相关资产在Moonbeam的表现形式
- 购买相应执行时间
- 使用执行时间在扣除执行费用后将资产在Moonbeam上的表现形式存入目标账户
XCM指令¶
一个XCM消息由一系列的XCM指令组成,而不同的XCM指令组合将会导向不同的执行动作。举例而言,要将DOT传送至Moonbeam,将会使用以下XCM指令:
TransferReserveAsset
- 在波卡上执行。此指令会将资产从原账户存入目标账户。在此例子中,目标账户为Moonbeam在波卡上的主权账户。接着,这将会传送一条XCM消息至目标链,也就是Moonbeam。XCM指令将会在Moonbeam上被执行ReserveAssetDeposited
- 在Moonbeam上执行。此指令将会把主权账户获得资产在Moonbeam上的表现形式传送至注册持有者中,一个在跨共识虚拟机(XCVM)中的暂时储存地ClearOrigin
- 在Moonbeam上执行。此指令会确保最新的XCM指令不会覆盖XCM作者的授权BuyExecution
- 在Moonbeam上执行。此指令会使用暂存的资产支付执行费用,费用的数量依据目标链决定,在本示例中为MoonbeamDepositAsset
- 在Moonbeam上执行。此指令会移除暂存区域的资产并将其传送至Moonbeam上的目标账户
要检查XCM消息中的指令是如何构建,以传送自有资产至目标链,例如传送DOT至Moonbeam,您可以查看X-Tokens Open Runtime Module Library(作为范例)。查看 transfer_self_reserve_asset
函数,您将会看到其调用TransferReserveAsset
并输入assets
、dest
和xcm
作为参数。详细来说,xcm
参数包含BuyExecution
和DepositAsset
指令。如果您导向至Polkadot GitHub库,您可以找到TransferReserveAsset
指令。此XCM消息由使用xcm
参数的ReserveAssetDeposited
和ClearOrigin
指令组成,如上所示其中包含BuyExecution
和DepositAsset
指令。
要将xcDOT从Moonbeam转移回波卡,您可以使用以下指令:
WithdrawAsset
- 在Moonbeam上执行。此指令将会移除资产并将它们存放在暂存处InitiateReserveWithdraw
- 在Moonbeam上执行。此指令会将资产从暂存处移除(本质上是销毁它们)并使用WithdrawAsset
为开头的指令传送一条XCM消息至目标链WithdrawAsset
- 在波卡上执行。此指令会移除资产并将它们存放在暂存处ClearOrigin
- 在波卡上执行。此指令会确保最新的XCM指令不会覆盖XCM作者的授权BuyExecution
- 在波卡上执行。此指令会使用暂存的资产支付执行费用,费用的数量依据目标链决定,在本示例中为波卡网络DepositAsset
- 在波卡上执行。此指令会移除暂存区域的资产并将其传送至波卡上的目标账户
要检查XCM消息中的指令是如何构建,以传送自有资产至目标链,例如传送xcDOT至波卡,您可以查看X-Tokens Open Runtime Module Library(作为范例)。查看 transfer_to_reserve
函数,您将会看到其调用WithdrawAsset
和InitiateReserveWithdraw
,并输入assets
、dest
和xcm
作为参数。详细来说,xcm
参数包含BuyExecution
和DepositAsset
指令。如果您导向至Polkadot GitHub库,您可以找到InitiateReserveWithdraw
指令。此XCM消息由使用xcm
参数的WithdrawAsset
和ClearOrigin
指令组成,如上所述其中包含BuyExecution
和DepositAsset
指令。
中继链XCM费用计算¶
Substrate已推出一个权重系统,决定一个函数的权重,也就是从计算成本的角度决定一个extrinsic的昂贵程度。一个权重单位被定义为一皮秒的执行时间。当在支付费用时,除了如网络拥塞的情况外,用户将会根据所调用函数的权重支付交易费用。
以下部分将会解释如何在波卡和Kusama计算XCM费用。请注意,Kusama特别使用基准化的数据决定XCM指令的总权重花费,因部分XCM指令可能包含数据库的读写,这将增加调用的权重。
目前在波卡和Kusama中有两个可用数据库,RocksDB(预设)和ParityDB,两者皆在每个网络具有不同的相关权重花费。
Polkadot¶
如同先前提到的,波卡目前对所有XCM指令采取固定权重数量的计算方式,也就是每条指令1,000,000,000
权重单位。
虽然波卡目前并未使用数据库的权重单位计算花费,但以下仍记载了数据库运行包含的权重单位作为参考。
数据库 | 读 | 写 |
---|---|---|
RocksDB (default) | 20,499,000 | 83,471,000 |
ParityDB | 11,826,000 | 38,052,000 |
在指令权重花费的计算架构完成后,您能够以DOT为单位计算指令的花费。
在波卡中,ExtrinsicBaseWeight
被设置为107,648,000
,也就是一分的十分之一。一分为10^10 / 100
。
因此您可以使用以下公式计算一个XCM指令的执行费用:
XCM-DOT-Cost = XCMInstrWeight * DOTWeightToFeeCoefficient
DOTWeightToFeeCoefficient
为常量(为一分),并可以通过以下计算获得:
DOTWeightToFeeCoefficient = 10^10 / ( 10 * 100 * DOTExtrinsicBaseWeight )
使用实际数值:
DOTWeightToFeeCoefficient = 10^10 / ( 10 * 100 * 107648000 )
最后DOTWeightToFeeCoefficient
将会等于0.092895362 Planck-DOT
。现在,您可以开始以DOT为单位计算最终费用,并使用DOTWeightToFeeCoefficient
常量和TotalWeight
变量:
XCM-Planck-DOT-Cost = TotalWeight * DOTWeightToFeeCoefficient
XCM-DOT-Cost = XCM-Planck-DOT-Cost / DOTDecimalConversion
因此,一个XCM指令的实际计算方式如下:
XCM-Planck-DOT-Cost = 1000000000 * 0.092895362
XCM-DOT-Cost = 92895362 / 10^10
总花费为0.0092895362 DOT
。
作为范例,您可以使用以下权重和指令花费计算传送一条XCM消息以转移xcDOT至DOT到波卡网络上所需的总花费:
指令 | 重量 | 成本 |
---|---|---|
WithdrawAsset |
1,000,000,000 | 0.0092895362 DOT |
ClearOrigin |
1,000,000,000 | 0.0092895362 DOT |
BuyExecution |
1,000,000,000 | 0.0092895362 DOT |
DepositAsset |
1,000,000,000 | 0.0092895362 DOT |
总量 | 4,000,000,000 | 0.0371581448 DOT |
Kusama¶
Kusama上的总权重花费包括:给定指令本身花费和数据库读写的费用。尚未对数据库读写操作进行基准测试,而对指令权重进行了基准测试。以下为数据库执行权重花费的细节:
数据库 | 读 | 写 |
---|---|---|
RocksDB (default) | 25,000,000 | 100,000,000 |
ParityDB | 8,000,000 | 50,000,000 |
现在您了解Kusama上数据库读写的权重花费,您可以使用指令的基础权重花费计算总花费。
例如,WithdrawAsset
指令具有20,385,000
基础权重,且执行一个数据库读取和一个数据库写入。因此,WithdrawAsset
指令的总权重花费将用以下方式计算:
20385000 + 25000000 + 100000000 = 145385000
BuyExecution
指令具有3,697,000
基础权重,且不包含任何数据库读写。因此,BuyExecution
指令的总权重花费为3,697,000
。
在Kusama上,基准化的基础权重分为两类:可替代的和通用的。可替代的权重为用于转移资产的XCM指令,而通用的基础权重用于其他类型指令。您可以在Kusama Runtime代码中查看可替代资产和通用资产的权重。
在了解指令的权重花费架构后,您可以以KSM为单位计算指令花费。
在Kusama中,ExtrinsicBaseWeight
被设置为108,512,000
,为一分的十分之一。一分为10^12 / 30,000
。
因此您可以使用以下公式计算一个XCM指令的执行费用:
XCM-KSM-Cost = XCMInstrWeight * KSMWeightToFeeCoefficient
KSMWeightToFeeCoefficient
为常量(为一分),并可以通过以下计算获得:
KSMWeightToFeeCoefficient = 10^12 / ( 10 * 3000 * KSMExtrinsicBaseWeight )
使用实际数值:
KSMWeightToFeeCoefficient = 10^12 / ( 10 * 3000 * 108512000 )
所以,KSMWeightToFeeCoefficient
与0.307185687604 Planck-KSM
相同,现在您可以开始以KSM为单位计算最终费用,使用KSMWeightToFeeCoefficient
作为常量和TotalWeight
(145,385,000)作为变量:
XCM-Planck-KSM-Cost = TotalWeight * KSMWeightToFeeCoefficient
XCM-KSM-Cost = XCM-Planck-KSM-Cost / KSMDecimalConversion
因此,以下为WithdrawAsset
的实际计算方式:
XCM-Planck-KSM-Cost = 145385000 * 0.307185687604
XCM-KSM-Cost = 44660191.1923 / 10^12
总花费为0.000044660191 KSM
。
作为范例,您可以使用以下权重和指令花费计算传送一条XCM消息以在Kusama网络上转移xcKSM至KSM的总花费:
指令 | 重量 | 成本 |
---|---|---|
WithdrawAsset |
145,385,000 | 0.000044660191 KSM |
ClearOrigin |
3,661,000 | 0.000001124607 KSM |
BuyExecution |
3,697,000 | 0.000001135665 KSM |
DepositAsset |
146,763,000 | 0.000045083493 KSM |
总量 | 299,506,000 | 0.000092003956 KSM |
基于Moonbeam网络的XCM费用计算¶
Substrate已推出一个权重系统,决定一个函数的权重,也就是从计算成本的角度决定一个extrinsic的昂贵程度。一个权重单位被定义为一皮秒的执行时间。当在支付费用时,用户将会根据所调用函数的权重支付交易费用,接着每个平行链皆可以决定如何将权重转换至费用,举例而言,计算交易大小或是存储花费的额外费用。
Moonbeam对通用XCM指令进行了基准测试,而可替代的XCM指令仍然使用每条指令的固定权重。 因此,基准测试过的XCM指令的总权重成本除了给定指令所需的权重之外还考虑了数据库读/写的次数。 数据库操作的权重成本明细如下:
数据库 | 读 | 写 |
---|---|---|
RocksDB (default) | 25,000,000 | 100,000,000 |
现在您知道了Moonbase Alpha的数据库读取和写入的权重成本,您可以使用指令和额外的数据库读取/写入(如果适用)的基本权重来计算可替代和通用XCM指令的权重成本。
例如,WithdrawAsset
指令是可替代XCM指令集的一部分。因此,它没有进行基准测试,WithdrawAsset
指令的总权重成本为200,000,000
。
BuyExecution
指令有一个181,080,000
的基础权重,并执行四次数据库读取(assetManager
pallet以获得 unitsPerSecond
)。因此,BuyExecution
指令的总权重成本计算如下:
181080000 + 4 * 25000000 = 281080000
您可以在下表中找到所有XCM指令的所有权重值:
基准测试过的指令 | 无基准测试的指令 |
---|---|
通用XCM指令 | 可替代XCM指令 |
以下部分教程将会包含如何在基于Moonbeam的网络计算XCM费用,有两个主要的应用场景:
- 以储备Token支付费用(如GLMR、MOVR或DEV等原生Token)
- 使用外部资产(XC-20s)支付费用
储备资产的费用计算¶
对于每个XCM指令,权重单位将会被转换为余额单位作为费用计算的一部分。每个基于Moonbeam网络单个权重单位的Wei数量分别如下:
Moonbeam | Moonriver | Moonbase Alpha |
---|---|---|
5,000,000 | 50,000 | 50,000 |
这意味着以Moonbeam为例,计算一个XCM指令以储备资产作为费用的公式如下:
XCM-Wei-Cost = XCMInstrWeight * WeiPerWeight
XCM-GLMR-Cost = XCM-Wei-Cost / 10^18
因此,实际计算如下:
XCM-Wei-Cost = 200000000 * 5000000
XCM-GLMR-Cost = 1000000000000000 / 10^18
最后,在Moonbeam上一的XCM指令的总费用为0.001 GLMR
。
外部资产的费用计算¶
考虑Alice在Moonbeam上向Alith的账户发送DOT的场景,费用从Alith收到的xcDOT金额中收取。要确定支付多少费用,Moonbeam使用了一个名为UnitsPerSecond
的概念,代表网络在XCM执行时间内每秒收取的Token单位(包含小数)。 Moonbeam(可能还有其他平行链)将使用此概念来确定使用与其储备不同的资产执行XCM的费用。
此外,在Moonbeam上执行XCM可以由原本资产来源链的多种资产(XC-20s)支付。举例来说,在撰写本文时,从Statemine发送的XCM消息{target=_blank}可以用xcKSM、xcRMRK 或xcUSDT支付。只要该资产在Moonbeam/Moonriver中设置了UnitsPerSecond
,它就可以用于为来自该特定链的XCM消息支付XCM执行费用。
要找出给定的资产是否在UnitsPerSecond
列表中,您可以使用assetManager.assetTypeUnitsPerSecond
函数并输入想要查看的资产的multilocation。
如果您不确定其multilocation,您可以使用assetManager.assetIdType
函数检索。
举例来说,您可以导向至Polkadot.js App的Moonbeam页面,并在Developer下拉选单中选取Chain State。接着,您可以跟随以下步骤操作:
- 在selected state query下拉选单中,选取assetManager
- 选取assetIdType extrinsic
- 在Option下方输入资产ID或是关闭include option以移除所有资产的信息。在本教程中将会获得xcUNIT的信息,其资产ID为
42259045809535163221576417993425387648
- 点击+按钮提交查询
您可以使用查询结果,并将其用于查询assetTypeUnitesPerSecond extrinsic:
- 确保已选取assetManager
- 选取assetTypeUnitesPerSecond extrinsic
- 在MoonbeamRuntimeXcmConfigAssetType选取Xcm
- 在parents一栏输入
1
- 在interior选取
Here
- 点击+提交查询
xcDOT的UnitsPerSecond
数值为33,068,783,068
。
请记得,权重的单位定义为执行时间的一皮秒,以下为定义执行时间的公式:
ExecutionTime = (Weight / Picosecond) * NumberOfInstructions
指令 | 重量 |
---|---|
ReserveAssetDeposited |
200,000,000 |
ClearOrigin |
5,194,000 |
BuyExecution |
281,080,000 |
DepositAsset |
200,000,000 |
总量 | 686,274,000 |
要定义Alice转移DOT至Moonbeam的执行时间(包含4个XCM指令),您可以使用以下计算方式:
ExecutionTime = 686274000 / 10^12
这代表4个XCM指令需花费0.000686274
秒的区块执行时间。
要计算以xcDOT为单位的总花费,您将需要资产的单位位数作为查询,以xcDOT为例,其资产单位为10个位数。您可以通过检索资产元数据查询资产的单位位数。
区块执行的公式可以用于决定Alice转移DOT至Alith在Moonbeam上账户所需的花费,以下为总花费的计算公式:
XCM-Cost = ( UnitsPerSecond / DecimalConversion ) * ExecutionTime
转移花费的计算公式如下:
XCM-Cost = ( 33068783068 / 10^10 ) * 0.000686274
Alice转移DOT至Alith账户的总花费为0.0022694246 xcDOT
。
XCM Transactor费用¶
XCM Transactor Pallet构建了一个能够在其他生态链上远程交易的XCM消息。开发者有种方法通过pallet远程交易:transactThroughSigned
extrinsic,调用者在目标链上的账户为一个multilocation原生的账户,且必须要拥有足够支付XCM执行费用,加上其他用于远程执行函数调度的费用
一般而言,XCM指令通常包含以下远程执行:
- 首个指令将处理原链上的Token。这可以为将Token转移至某个主权账户,或是销毁相关的XC-20资产,让其可以被用于目标链。这些指令将会在原链上执行
DescendOrigin
- 使用指令中提供的multilocation来改变起点因为来源不再是主权账户,而是multilocation衍生账户WithdrawAsset
- 在目标链上执行。移除资产并将其放于待使用BuyExecution
- 在目标链上执行,将会把保存资产拿出以支付执行费用,支付的费用由目标链决定Transact
- 在目标链执行,自给定的原链调用编码的调用数据
通过签署费用交易¶
在通过multilocation衍生账户进行交易时,交易费用由发出调用的同一账户支付,其为目标链中的multilocation衍生帐户。因此,multilocation衍生帐户必须持有必要的资金来支付整个执行费用。请注意,支付费用的目标Token不需要在原链中注册为XC-20。
您可以想像以下情景:Alice想要使用通过签名函数的交易从Moonbase Alpha在另一条链(平行链 ID 888,在Moonbase Alpha中继链生态系统中)进行远程交易。要估计Alice的multilocation衍生账户执行远程调用所需的Token数量,您需要检查在目标链的特定交易信息。为此,请前往Polkadot.js Apps的链状态页面并设置以下选项:
- 选取xcmTransactor pallet
- 选取transactInfoWithWeightLimit方法
- 为目标链设置multilocation,根据您希望查询的交易信息。在此范例中,您可以将parents设置为
1
- 在interior中选取
X1
- 在X1一栏中选取
Parachain
- 将Parachain设置为
888
- 点击 +
在获得的回应中,您可以看到transactExtraWeightSigned
为400,000,000
。这是在该特定目标链中执行此远程调用的4个XCM指令所需的权重。接下来,您需要找到目标链每执行XCM权重收取的费用。通常,您会查看该特定链的UnitsPerSecond
。但在这种情况下并不会销毁XC-20 Token。因此,UnitsPerSecond
可以作为参考,但不能保证估算的Token数量是正确的。要获取UnitsPerSecond
作为参考值,在同一个Polkadot.js Apps页面,设置以下选项:
- 选取xcmTransactor pallet
- 选取destinationAssetFeePerSecond方法
- 为目标链设置multilocation,根据您希望查询的交易信息。在此范例中,您可以将parents设置为
1
- 在interior中选取
X2
- 在X1一栏中选取
Parachain
- 将Parachain设置为
888
- 在X2一栏选取
PalletInstance
- 将PalletInstance设置为
3
- 点击 +
请注意,此UnitsPerSecond
与中继链XCM费用计算部分中的预估成本有关,如果目标是另一个平行链,将与权重单位的Wei数值部分中显示的成本有关。您需要找到正确的数值,以确保multilocation衍生账户持有的Token数量是正确的。如同先前,计算相关的XCM执行费用与transactExtraWeight
乘以UnitsPerSecond
一样简单明了(用于估算):
XCM-Wei-Token-Cost = transactExtraWeight * UnitsPerSecond
XCM-Token-Cost = XCM-Wei-Token-Cost / DecimalConversion
因此,实际一个通过衍生调用的XCM Transactor交易费用的实际计算如下:
XCM-Wei-Token-Cost = 400000000 * 50000000000000000
XCM-Token-Cost = 20000000000000 / 10^18
通过签名进行交易的费用为0.00002 TOKEN
。 请注意,这不包括远程执行调用的费用,仅包括XCM执行费用。
| Created: August 8, 2022