本文详细介绍了Wormhole跨链桥如何确保桥接代币的正确性,包括代币信息验证、注册流程、代币数量的处理等核心机制。通过阐述Token Attestation和相关智能合约函数,文章深入解析了Wormhole确保不同链之间代币一致性的技术原理。
继 第一部分 和 第二部分 之后,本文重点解释 Wormhole 如何确保桥接的代币是正确的。
这里,“正确”意味着代币类型和转移数量与在源链上转移的代币相同或等价。
在 VAA 中,代币信息通过 tokenChain 和 tokenAddress 在 VAA 负载中指定:
// 代币的地址。如果少于 32 字节则左侧补零
bytes32 tokenAddress;
// 代币的链 ID
uint16 tokenChain;
请注意,代币不一定是源链或目标链代币,但可以是任何链上的代币地址。例如,Alice可能会从 Solana 转移 USDC( tokenChain 1)到 Polygon( tokenChain 5),而 VAA 中指定的代币可能是以太坊上的 美元货币(USDC)(tokenAddress 0xa0b8, tokenChain 2)。
为了将 VAA 中指定的代币转换为目标链上的正确代币,Wormhole 提供了一个称为 代币背书(token attestation) 的功能,允许用户注册代币。假设Alice想要在 Solana 上注册一个新代币,该代币对应于以太坊上一个现有的代币 X,流程如下:
1. Alice可以在源链的 Wormhole 代币桥合约上调用 attestToken 函数,传入代币 X 的 tokenAddress 和一个 nonce:
attestToken 函数将发布包含代币元数据的消息,包括 tokenAddress、tokenChain(以太坊为 2)、代币 decimals、symbol 和 name:
2. 消息将被守护者观察,随后他们会生成一个 背书 VAA(attestation VAA),可以使用 attestToken 函数返回的 sequence 数字进行检索。
3. 然后,Alice可以通过在外链上的 Wormhole 代币桥的 CreateWrapped 函数,将背书 VAA 提交到每个其他链(称为该代币的 foreign chains):
在上述操作中,调用 create_wrapped 函数并传入背书 VAA 及代币铸造地址将建立被背书代币和铸造地址之间的对应关系。
请注意,代币铸造地址必须是唯一的:两个不同的被背书代币必须对应不同的铸造地址。在 Solana 中,这是通过从被背书的代币元数据( chain,token_address,original_decimals)创建一个 PDA 来实现的:
PDA 是对应源代币的铸造地址。当在 Solana 上赎回代币时,可以通过 verify_derivation 函数在 PDA( wrapped_meta)上进行验证:
由于铸造地址是 PDA,只有 Wormhole 代币桥程序有权铸造相应的代币。这确保了任何人都可以使用背书 VAA 调用 create_wrapped(如果铸造地址尚未注册),但攻击者不能伪造 mint。
如果攻击者在Alice之前调用 create_wrapped 并提供一个错误的铸造地址,例如在 Solana 上注册了狗狗币( D56d),而不是 ETH — 以太(Portal) 的 WETH,那么 accs.mint.verify_derivation(ctx.program_id, &derivation_data) 中的检查将会失败。
在其他链上的流程类似。例如,在以太坊上,createWrapped 函数将为代币部署一个新合约(创建一个 Wormhole 包装代币),并调用 setWrappedAsset 来更新储存( tokenChainId、tokenAddress)和一个包装地址 wrapper 的映射 wrappedAsset:
当在以太坊上赎回代币时,wrappedAsset 映射将用于根据 tokenChainId 和 tokenAddress 检索相应的代币:
完整的转移函数( CompleteNative 和 CompleteWrapped)都检查铸造地址的相等性,如下所示:
一个警示是用户提供的接收者 to 必须是一个有效的代币接收者。例如,在 Solana 上,这意味着接收者必须是具有与 create_wrapped 中创建的 PDA 相同铸造地址的代币账户。
如果(由于用户错误)接收者地址不是代币账户,或者其代币铸造地址与带种子的 PDA( chain,token_address,original_decimals)不匹配,则用户将无法赎回该代币。该代币可能会被锁定在桥上,直到守护者网络发出带有正确接收者地址的新 VAA。
VAA 包含转移数量 uint256 amount,该数量确保在目标链上铸造的代币数量应该与 amount 一致。然而,这里存在一个技术问题,即桥接的代币可能具有不同的小数位数。例如,以太坊上的以太币具有 18 位小数,但 Wormhole 限制代币的小数位数为 8( 代码中第 147 行):
为了解决这个问题,Wormhole 必须确保正确处理代币的小数位数。如果代币的小数位数超过 8(例如以太币),则 Wormhole 必须根据 8 位小数限制规范化其转移量。
更具体地说,在对 VAA 负载中的 amount 进行编码时,Wormhole 通过调用 deNormalizeAmount 和 deNormalizeAmount 来去规范化转移数量:
在上述代码中( 276 和 285 行),如果 decimals 大于 8,amount 将分别向右和向左移动 decimals - 8 位小数。
注意,由于小数的移动,存款尘埃不会被转移到目标链上,Wormhole 会将尘埃(如果有的话)退款给源链的发送者:
在下一篇文章中,我们将继续讨论 Wormhole 如何避免消息重复交付,即 VAA 重放攻击。
sec3 是一家安全研究公司,为数百万用户准备 Solana 项目。sec3 的 Launch Audit 是一个严格的、由研究人员领导的代码审查,调查并认证主网级别的智能合约;sec3 的持续审计软件平台 X-ray 集成了 GitHub,以逐步扫描拉取请求,帮助项目在部署前强化代码;而 sec3 的后部署安全解决方案 WatchTower 确保资金安全。sec3 正在为 Web3 项目构建基于技术的可扩展解决方案,以确保协议在扩展时保持安全。
要了解更多关于 sec3 的信息,请访问 https://www.sec3.dev
- 原文链接: sec3.dev/blog/bridges3...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!