Cobo 开发者学堂:一文讲透智能合约的多链同地址部署
Cobo
2024-07-05 16:30
订阅此专栏
收藏此文章

Cobo 一直以来都十分重视开发者生态建设,希望可以为广大开发者提供帮助。Cobo 开发者学堂系列将从 Web3 开发者角度,介绍区块链开发方面的内容。本文介绍了智能合约多链同地址部署的基本原理,并在对主流方案调研的基础上,推出了 Cobo Factory 合约,此合约支持 create2, create3 等多种部署方式,factory 合约本身也提供无许可的重放部署脚本。


多链同地址部署

合约地址是智能合约的身份标识。在 Cobo 发布的区块链交互的安全实践指南中,也建议用户进行交易签名时要仔细核对交互的合约地址

需要注意的是,与通过密码学公私钥对生成的外部账户(EOA)不同,智能合约的地址是链相关的。即不同链上的相同合约地址上,可能部署着完全不同的智能合约;同个 DeFi 项目中相同功能的智能合约,也可能部署在不同的地址上。

比如 Uniswap 在不同链上的合约地址[1] 就不尽相同。在以太坊上 0xE592427A0AEce92De3Edee1F18E0157C05861564 是 Uniswap Router 的地址,而在 BSC 链上,该地址则是空地址。但仍有大量交易在错误地尝试与 BSC 链上的该地址进行合约交[2]。目前该地址已经被错误转入近 200 个 BNB。

为了优化用户体验,避免用户在多链交互时使用错误的合约地址,减少用户核对合约地址的负担,在实际的业务场景中,很多 Web3 项目方都会尝试将合约进行多链同地址部署。比如 1inch Router 的 0x1111111254EEB25477B68fb85Ed929f73A960582、Balancer Vault 的 0xba12222222228d8ba445958a75a0704d566bf2c8 ,这些地址在多条 EVM 兼容链上均为官方正确的合约。

合约地址的计算逻辑

那么如何实现多链同地址部署呢?想得到相同的合约地址,我们首先要了解下 EVM 链上合约地址的计算方式。

在 EVM 兼容链中部署智能合约有三种方式:

  1. EOA 发起智能合约部署交易。
  2. 智能合约中调用 create[3] 指令。
  3. 智能合约中调用 create2[4] 指令。

不同合约部署的方式,会按不同规则生成对应的合约地址。其中前两种合约部署方式生成地址的规则是一致的。

address = keccak256(rlp([sender_address,sender_nonce]))[12:]

此种合约部署方式下,合约地址仅与 sender 地址、sender nonce 两个值有关。其中 sender 可以是 EOA,也可以是调用 create 指令的智能合约。

create2 在 EIP-1014[5] 中引入,其计算规则为

address = keccak256(0xff + sender_address + salt + keccak256(initialisation_code))[12:]

此种合约部署方式下,合约地址与 sender 地址、salt、初始化代码三个值有关,与 sender nonce 无关。另外由于 create2 只能通过执行合约调用,因此这里的 sender 只能是智能合约地址而非 EOA 地址。

在清楚了解地址计算逻辑之后,可以进一步思考如何进行多链同地址部署。

方案一: create

根据 create 方式的合约地址计算规则,只要使用相同的 EOA 地址并使用相同的 nonce 进行合约部署即可得到相同的地址。

EOA 地址由公钥 hash 生成,而公钥又由私钥生成。即意味着同样的私钥,在不同的 EVM 链上的地址均相同。nonce 为地址执行过交易的次数。那么最直接的在不同链上部署同地址的方案就很直观了:生成一个所有链均未使用过的新的地址(此时 nonce 为 0),在不同链上进行合约部署。

这种方案最容易想到,但实际使用时要求使用者比较小心谨慎,需要妥善保管地址私钥,并管理 nonce。

  • 如果私钥丢失,那么将无法在新的链上完成同地址的部署。

  • 如果误操作发送了交易,导致 nonce 与其他链上不一致,此时也再无法部署出相同的合约地址。需要注意的是,除了主动发起交易外,有些 L2 在跨链交易会自动生成一笔自己给自己转账的系统交易,也会导致 nonce 增加。

  • 当需要部署多个合约的时候,需要保证合约部署顺序一致,来保证 nonce 一致。否则部署合约的地址也会不一致。

这种使用新地址部署合约还有一个弊端是会涉及到 gas 转账、部署后回收 gas 的问题,使成本增加并且部署流程也变得更加繁琐。

方案二:create2

使用 create2 可以在一定程度上缓解方案一中的不足。通过 create2 部署合约不受 sender nonce 变化的限制,只要使用相同的 salt,就可以得到相同的合约地址。因为不需要时刻小心管理 nonce。

但这里存在一个「鸡生蛋、蛋生鸡」的问题,因为 create2 只能由合约调用(这种用来部署合约的合约通常称为 factory 合约,即工厂合约),并且 create2 生成的合约地址,与 factory 合约地址有关。因此要在不同的链上生成相同的合约地址,首先需要有一个相同地址的 factory 合约。

所以我们仍需要先使用方案一来部署一个 factory 合约。需要一个谨慎负责的首发者在各条链上部署初始的 factory 合约。但相比方案一,factory 合约在一条链上只需要部署一次,就可以被所有人使用。将管理成本整合到首发者自己的身上。

不过 EVM 链的数量在不断增加,尤其是各类 L2 技术的成熟,现在已经可以比较容易的做到「一键发链」了。在这种情况下,我们需要这个谨慎负责的首发者在有新链发布的时候能够第一时间去进行合约部署。同时要一直妥善保管私钥,且不随意使用 nonce。

显然这种方式不太符合区块链的去中心化精神。在 deterministic-deployment-proxy[6] 项目中和 EIP-2470: Singleton Factory[7] 中提出了一种很巧妙的解决方法,利用非 EIP-155 的交[8] 跨链可重放的特性(有时候也是漏洞)来实现无许可的部署。具体思路如下:

  1. 生成一个一次性私钥。

  2. 使用上述私钥签名一个非 EIP-155 的 factory 合约部署交易,要设置足够大的 gas limit 以及足够高的 gas price。

  3. 将上述交易公开。

  4. 上述私钥在使用之后销毁私钥。

这样任何人均可以在任意 EVM 兼容链上重放该交易,并且此交易上链后,可以在各条链的同样地址上部署出一份同样的 factory 合约。同时无需考虑私钥与 nonce 管理的问题。

当各条链上就有了 factory 合约,后续开发者即可使用这个 factory 加上固定的 salt,在各条链上部署合约到相同的合约地址上。

方案三:create3

由 create2 计算公式来看,

address = keccak256(0xff + sender_address + salt + keccak256(initialisation_code))[12:]

除了保证 sender 和 salt,还需要保证初始化代码一致。

所谓初始化代码指创建合约的代码,其中也包含了合约的构造函数(constructor)及构造函数的参数。

这意味着使用 create2 只能在各条链上部署代码及初始参数配置完全一样的合约。但实际的应用场景中,不同链上的合约所需要的参数配置可能是不同的,甚至合约版本本身也是不同的。

能否在允许合约代码有差异的情况下,将合约部署到不同链的相同地址上?

回想 create 的地址计算方式

address = keccak256(rlp([sender_address,sender_nonce]))[12:]

create 创建合约的地址是与合约初始化代码无关的。利用这一点,可以将 create2 + create 组合使用完成前面的目的。操作如下:

  1. 部署同地址的 factory;

  2. 通过 factory 使用 create2 创建同地址 deployer 合约;

  3. 通过 deployer 合约调用 create 部署最终的合约。

此时最终合约地址是相同的,但合约内容可以任意变化。这种部署方式被称为 create3[9],已经有许多合约库中实现了此方案。

Cobo Factory

至此主流的多链同地址部署方案就介绍完毕了。可以看出 factory 合约是满足这种需求的一种重要的开发基础设施,在许多项目中都可以应用到。

目前已经存在一些公开部署

  • EIP-2470: Singleton Factory。0xce0042B868300000d44A59004Da54A005ffdcf9f[10] 是典型的使用 create2 部署方式的工厂合约。因为交易可重放,已经被多个链上成功部署。但因为是预签名[11] 限制了固定的 gas limit 与 gas price。gas limit 不够导致在 Arbitrum 等 gas 计算比较特殊的链上无法重放。在 Arbitrum 链上该合约是通过系统合约特殊部署的。而 gas price 的限制则会导致在平均 gas price 较高的链上无法上链,而在 gas 较低的链上重放则会造成资金的浪费。
  • Layerzero Labs 部署的 CREATE3Factory[12] 0x8Cad6A96B0a287e29bA719257d0eF431Ea6D888B[13] 则是使用 create3 部署方式的工厂合约。该合约在许多链上已有部署。但由于不可重放,因此在新链上需要等待 Layerzero 团队主动部署。

为解决已有工厂合约的一些问题,Cobo 团队也部署一套新的工厂合约,地址为 0xC0B000003148E9c3E0D314f3dB327Ef03ADF8Ba7。代码开源在 https://github.com/coboglobal/cobo-factory

Cobo Factory 提供如下特性:

  • 已在 Ethereum, Arbitrum 等十余条链上完成部署。
  • 提供了部署脚本。对接新链时任何人均可无许可地独立完成 Cobo Factory 的部署,无须通过 Cobo 团队。
    • 预签名了各种 gas limit 与 gas price 的部署交易,从而可以在各类 EVM 兼容链上进行重放,不受特殊 gas 计价与 gas price 浮动的困扰。
    • 脚本自动寻找合适的预签名交易发起部署。
    • 提供了 standard-json-input.json 文件,任何人均可以方便在部署后在区块链浏览器上验证源码,完成合约代码开源。
  • 根据创建方式使用 create2/create3、是否允许与 sender 绑定、是否 emit event,Cobo Factory 提供了 8 种不同的合约部署方式。并可通过统一的接口完成调用。
  • 提供了配套的 vanity address(靓号地址)计算脚本,可用于计算 create2/create3 部署方式下的特定 salt 生成项目方想要的标志性合约地址。

Cobo 一直以来都十分重视开发者生态建设,希望可以为广大开发者提供帮助。Cobo Factory 也是这项使命中的一小步。

Cobo 近期推出了一站式托管和钱包技术平台 Cobo Portal,是业内唯一将托管钱包、MPC 钱包、智能合约钱包和交易所钱包四种不同钱包技术集于一体的平台。Cobo Portal 中也将推出应用市场,允许开发者通过 Portal API 轻松构建自己的 Web3 应用。Cobo 希望能与众多 Web3 开发者一起,共建区块链大厦。

参考资料

[1]    Uniswap 合约地址: https://docs.uniswap.org/contracts/v3/reference/deployments/
[2]    错误的合约交互: https://bscscan.com/address/0xE592427A0AEce92De3Edee1F18E0157C05861564
[3]    Create 指令: https://www.evm.codes/#f0?fork=cancun
[4]    create2 指令: https://www.evm.codes/#f5?fork=cancun
[5]    EIP-1014: https://eips.ethereum.org/EIPS/eip-1014
[6]    deterministic-deployment-proxy: https://github.com/Arachnid/deterministic-deployment-proxy
[7]    EIP-2470: Singleton Factory: https://eips.ethereum.org/EIPS/eip-2470
[8]    EIP-155: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md
[9]    create3: https://github.com/0xsequence/create3
[10]    Singleton Factory 合约: https://etherscan.io/address/0xce0042b868300000d44a59004da54a005ffdcf9f
[11]    Singleton Factory 部署交易: https://etherscan.io/tx/0x803351deb6d745e91545a6a3e1c0ea3e9a6a02a1a4193b70edfcd2f40f71a01c
[12]    create3-factory : https://www.npmjs.com/package/@layerzerolabs/create3-factory?activeTab=code
[13]    CREATE3Factory 合约:https://etherscan.io/address/0x8Cad6A96B0a287e29bA719257d0eF431Ea6D888B#code

关于 Cobo 

Cobo 是数字资产托管和钱包技术的领导者,提供一站式钱包技术平台,让机构和开发者能够轻松构建、自动化和安全地扩展其数字资产业务。

Cobo 成立于 2017 年,总部位于新加坡,是全球 500 多家领先数字资产企业信任的区块链先驱,托管资产达数十亿美元。Cobo 提供行业内唯一集四种不同数字资产钱包技术的平台——托管钱包、MPC 钱包、智能合约钱包和交易所钱包。Cobo 致力于最高的安全标准和监管合规性,拥有零事故记录,并获得了 ISO 27001、SOC2(1 类和 2 类)认证,以及多个司法管辖区的许可。因在业界领先的创新,Cobo 获得了 Hedgeweek、Global Custodian 等权威机构的认可

了解更多信息,请访问:www.cobo.com

【免责声明】市场有风险,投资需谨慎。本文不构成投资建议,用户应考虑本文中的任何意见、观点或结论是否符合其特定状况。据此投资,责任自负。

Cobo
数据请求中
查看更多

推荐专栏

数据请求中
在 App 打开