Skip to content

与GMP预编译交互

概览

Moonbeam路由流动性(MRL)是指Moonbeam作为端口平行链的用例,适用于从源链到其他波卡平行链的流动性。此用例因为通用消息传递(GMP)的出现而实现,其中带有任意数据和Token的消息可以通过与链无关的GMP协议在非平行链区块链上发送。这些GMP协议可以与波卡的XCM消息传递系统结合,以实现无缝流动性路由。

GMP预编译充当Moonbeam路由流动性的接口,作为来自GMP协议的承载Token消息和通过XCMP连接到Moonbeam的平行链之间的中间人。目前GMP预编译仅支持通过 Wormhole GMP协议传递流动性。

GMP预编译位于以下地址:

0x0000000000000000000000000000000000000816
0x0000000000000000000000000000000000000816
0x0000000000000000000000000000000000000816

实际上,开发者不太可能直接与预编译进行交互。GMP协议的中继层与预编译交互以完成跨链操作,因此跨链操作起源的源链是开发者有责任确保最终使用GMP预编译的地方。

GMP Solidity接口

Gmp.sol是一个允许开发者与预编译交互的Solidity接口:

  • wormholeTransferERC20(bytes memory vaa) - 接受一个Wormhole的桥接转账VAA (Verified Action Approval),通过Wormhole Token桥铸造Token并将流动性转移至自定义的有效负载multilocation
  • VAA为在源链交易后生成的包含有效负载的包,由Wormhole守护者网络间谍发现。有效负载被预计称为预编译专属的SCALE编码项目,如先前在此教程的Wormhole部分解释一般

用户必须与预编译交互的最常见实例是在恢复的情况下,也就是中继器不完成MRL事务。举例来说,用户必须搜索其源链交易附带的VAA,然后手动调用wormholeTransferERC20函数。

为Wormhole构建有效负载

目前GMP预编译仅支持使用Wormhole通过Moonbeam发送流动性以及发送到其他平行链。GMP预编译不协助从平行链返回Moonbeam以及其他Wormhole连接链的路线。

要从像以太坊这样的与Wormhole连接的源链发送流动性,用户必须调用transferTokensWithPayload函数WormholeTokenBridge智能合约origin-chain部署。此函数需要一个字节有效负载,该有效负载必须格式化为包含在另一个预编译特定版本类型中的SCALE编码multilocation对象。

如果您不熟悉波卡生态系统,您可能不熟悉SCALE编码和multilocation。SCALE编码是波卡使用的一种紧凑形式的编码。MultiLocation类型用于定义波卡中的相对点,例如特定平行链上的特定账户(Polkadot区块链)。

Moonbeam的GMP协议需要一个multilocation来代表流动性路由的目的地,目的地可能代表着其他平行链上的账户。不论它是什么,这个目的地必须相对于Moonbeam来表达。

注意事项

Multilocation以相对形式出现是非常重要的,因为平行链团队有可能给你一个相对于他们自身链的multilocation,有可能与你认知不同。提供错误的multilocation有可能导致资金损失

每一个平行链有他们自己解读multilocation的函数,建议您与项目确认您所形成的multilocation是正确的,也就是说,一个最有可能通过账户形成的multilocation。

有很多种账户可以被包含在multilocation之中,您需要在行程您的multilocation之前了解相关信息。其中两种最常见的分别为:

  • AccountKey20 — 20个字节长的账户ID,包含如在Moonbeam中的以太坊兼容账户ID
  • AccountId32 — 32个字节长的账户ID,为波卡及平行链的标准

以下multilocation模板以其他平行链上的账户为目标,以Moonbeam作为相对来源。要使用它们,请将INSERT_PARACHAIN_ID替换为您希望向其发送资金的网络的平行链ID,并将INSERT_ADDRESS替换为您希望向该平行链发送资金的账户地址。

{
    "parents": 1,
    "interior": {
        "X2": [
            { "Parachain": "INSERT_PARACHAIN_ID" },
            { 
                "AccountId32": { 
                    "id": "INSERT_ADDRESS" 
                } 
            }
        ]
    }
}
{
    "parents": 1,
    "interior": {
        "X2": [
            { "Parachain": "INSERT_PARACHAIN_ID" },
            { 
                "AccountKey20": { 
                    "key": "INSERT_ADDRESS" 
                } 
            }
        ]
    }
}

如果没有正确的工具,可能很难对整个有效负载进行正确的SCALE编码,特别是因为预编译所需的自定义类型。幸运的是,有波卡JavaScript包可以帮助实现这一点,例如@polkadot/types。以下脚本展示了如何创建可用作GMP预编译有效负载的Uint8Array

import { TypeRegistry, Enum, Struct } from '@polkadot/types';

// Creates a type registry to properly work with the precompile's input types
const registry = new TypeRegistry();

// Define the precompile's input types VersionedUserAction and XcmRoutingUserAction
// https://github.com/moonbeam-foundation/moonbeam/blob/1d664f3938698a6cd341fb8f36ccc4bb1104f1ff/precompiles/gmp/src/types.rs#L25-L39
class VersionedUserAction extends Enum {
 constructor(value) {
   super(registry, { V1: XcmRoutingUserAction }, value);
 }
}
class XcmRoutingUserAction extends Struct {
 constructor(value) {
   super(registry, { destination: 'VersionedMultiLocation' }, value);
 }
}

// A function that creates a SCALE encoded payload to use with transferTokensWithPayload
function createMRLPayload(parachainId, account, isEthereumStyle) {
  // Create a multilocation object based on the target parachain's account type
  const versionedMultiLocation = { 
    v1: {
      parents: 1,
      interior: {
        X2: [
          { Parachain: parachainId },
          isEthereumStyle ? 
            { AccountKey20: { key: account } } : 
            { AccountId32: { id: account }
        }]
      }
    }
  };

  // Format multilocation object as a Polkadot.js type
  const destination = registry.createType('VersionedMultiLocation', versionedMultiLocation);

  // Wrap and format the MultiLocation object into the precompile's input type
  const userAction = new XcmRoutingUserAction({ destination });
  const versionedUserAction = new VersionedUserAction({ V1: userAction });

  // SCALE encode resultant precompile formatted objects
  return versionedUserAction.toU8a();
}

限制

GMP预编译仍然在其发展的早期阶段,目前还是有许多限制,当前仅支持至平行链“满意路径”。以下为您需要了解的限制内容:

  • 目前没有费用机制。在Moonbeam上运行将流动性转移至其他平行链的中继层将会负责支付交易费用,此机制或将在未来更动
  • 预编译并不会确保目标链是否支持传送的Token。错误的multilocation有可能导致资金损失
  • 错误的构建multilocation将导致回溯,Token将会被锁住并导致资金损失
  • 目前并没有从平行链至其他如以太坊的链的返回路径。这会是一个在一键方案实现前需要研究的协议层级课题
    • 由于ERC-20 XC资产的限制,通过Moonbeam从平行链发送回Token的唯一方法是在原始平行链上拥有xcGLMR,并在发送回Token时将其用作费用
Last update: August 31, 2023
| Created: August 2, 2023