You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
// BridgeDepositBox.sol 文件中function canBridge(addressl2Token) publicviewreturns (bool) {
returnisWhitelistToken(l2Token) &&_hasEnoughTimeElapsedToBridge(l2Token);
}
// AVM_BridgeDepositBox.sol文件中function bridgeTokens(addressl2Token, uint32l1Gas) publicoverridenonReentrant() {
uint256 bridgeDepositBoxBalance =TokenLike(l2Token).balanceOf(address(this));
require(bridgeDepositBoxBalance >0, "can't bridge zero tokens");
require(canBridge(l2Token), "non-whitelisted token or last bridge too recent");
whitelistedTokens[l2Token].lastBridgeTime =uint64(getCurrentTime());
StandardBridgeLike(l2GatewayRouter).outboundTransfer(
whitelistedTokens[l2Token].l1Token, // _l1Token. Address of the L1 token to bridge over.
whitelistedTokens[l2Token].l1BridgePool, // _to. Withdraw, over the bridge, to the l1 withdraw contract.
bridgeDepositBoxBalance, // _amount. Send the full balance of the deposit box to bridge.""// _data. We don't need to send any data for the bridging action.
);
emitTokensBridged(l2Token, bridgeDepositBoxBalance, l1Gas, msg.sender);
}
什么是 Across
以太坊跨链协议 Across 是一种新颖的跨链方法,它结合了乐观预言机(Optimistic Oracle)、绑定中继者和单边流动性池,可以提供从 Rollup 链到以太坊主网的去中心化即时交易。目前,Across 协议通过集成以太坊二层扩容方案Optimism、Arbitrum和Boba Network支持双向桥接,即可将资产从L1发送至L2,亦可从L2发送至L1。
存款跨链流程
来源于:https://docs.across.to/bridge/how-does-across-work-1/architecture-process-walkthrough
Across 协议中,存款跨链有几种可能的流程,最重要的是,存款人在任何这些情况下都不会损失资金。在每一种情况下,在 L2 上存入的任何代币都会通过 Optimism 或 Arbitrum 的原生桥转移到 L1 上的流动池,用以偿还给流动性提供者。
从上面的流程中,我们可以看到 Across 协议流程包括以下几种:
Across 协议中主要包括几类角色:
项目总览
Across 的合约源码地址为 https://github.com/across-protocol/contracts-v1,目前 Across Protocol 正在进行 v2 版本合约的开发,我们这一篇文章主要分析 v1 版本的合约源码。首先我们下载源码:
git clone https://github.com/across-protocol/contracts-v1 cd contracts-v1
合约源码的主要的目录结构为:
在这篇解析中,我们主要关注
contracts
和deploy
目录下的文件。合约总览
合约目录
contracts
的目录结构为:contracts/ ├── common │ ├── implementation │ └── interfaces ├── external │ ├── README.md │ ├── avm │ ├── chainbridge │ ├── ovm │ └── polygon ├── insured-bridge │ ├── BridgeAdmin.sol │ ├── BridgeDepositBox.sol │ ├── BridgePool.sol │ ├── RateModelStore.sol │ ├── avm │ ├── interfaces │ ├── ovm │ └── test └── oracle ├── implementation └── interfaces
其中,各个目录包含的内容为:
common
:一些通用功能的库方法等,包括:external
:外部合约,主要用于实现在管理员合约中对不同 L2 的消息发送;insured-bridge
合约主要功能,我们会在接下来的章节章节中重点分析;oracle
:主要是 Optimistic Oracle 提供功能的方法接口,在这篇文章中我们不对 Optimistic Oracle 的原理实现进行介绍,主要会介绍 Across 协议会在何处使用 Optimistic Oracle。接下来我们会重点分析
insured-bridge
中的合约的功能,这是 Across 主要功能的合约所在。在
insured-bridge
目录中:BridgeAdmin.sol
:管理合约,负责管理和生成生成 L2 上的 DepositBox 合约和 L1 上的 BridgePool 合约;BridgeDepositBox.sol
:L2 层上负责存款的抽象合约,Arbitrum,Optimism 和 Boba 网络的合约都是继承自这个合约;BridgePool.sol
:桥接池合约,管理 L1 层资金池。BridgeAdmin
这个合约是管理员合约,部署在L1层,并有权限管理 L1 层上的流动性池和 L2 上的存款箱(DepositBoxes)。可以注意的是,这个合约的管理帐号是一个多钱钱包,避免了一些安全问题。
首先我们看到合约中的几个状态变量:
其中:
finder
用来记录查询最新 OptimisticOracle 和 UMA 生态中其他合约的合约地址;_depositContracts
该合约可以将消息中继到任意数量的 L2 存款箱,每个 L2 网络一个,每个都由唯一的网络 ID 标识。 要中继消息,需要存储存款箱合约地址和信使(messenger)合约地址。 每个 L2 的信使实现不同,因为 L1 --> L2 消息传递是非标准的;_whitelistedTokens
记录了 L1 代币地址与对应 L2 代币地址以及桥接池的映射;optimisticOracleLiveness
中继存款的争议时长;proposerBondPct
Optimistic Oracle 中 proposer 的绑定费率管理员可以设置以上这些变量的内容,以及可以设置每秒的 LP 费率,转移桥接池的管理员权限等。
同时,管理员还可以通过信使设置 L2 层合约的参数,包括;
setCrossDomainAdmin
:设置 L2 存款合约的管理员地址;setMinimumBridgingDelay
:设置 L2 存款合约的最小桥接延迟;setEnableDepositsAndRelays
:开启或者暂停代币 L2 存款,这个方法会同时暂停 L1 层桥接池;whitelistToken
:关联 L2 代币地址,这样这个代币就可以开始存款和中继;对于消息发送,管理员合约通过调用不同的信使的
relayMessage
方法来完成,将 msg.value == l1CallValue 发送给信使,然后它可以以任何方式使用它来执行跨域消息。不同L2的消息方法分别在对应链的
CrossDomainEnabled.sol
合约中,比如:contracts/insured-bridge/avm/Arbitrum_CrossDomainEnabled.sol
;contracts/insured-bridge/ovm/OVM_CrossDomainEnabled.sol
;BridgeDepositBox
接下来我们看到
BridgeDepositBox.sol
,抽象合约BridgeDepositBox
合约中主要有两个功能。bridgeTokens
第一个是
bridgeTokens
方法,用于将 L2 层代币通过原生代币桥转移到 L1 上,这个方法需要在不同的 L2 层合约上实现,目前支持的 L2 层包括 Arbitrum,Optimism 和 Boba,分别对应的文件为:contracts/insured-bridge/avm/AVM_BridgeDepositBox.sol
contracts/insured-bridge/ovm/OVM_BridgeDepositBox.sol
contracts/insured-bridge/ovm/OVM_OETH_BridgeDepositBox.sol
以 Arbitrum 链上的
bridgeToken
为例:bridgeTokens
上有一个装饰器canBridge
包含两个判断,isWhitelistToken
用于判断对应 L2 层代币是否已经在 L1 层上添加了桥接池,_hasEnoughTimeElapsedToBridge
用来减少频繁跨连导致的费用消耗问题,因此设置了最小的跨链接时间。bridgeTokens
主要就是调用了 L2 层原生的跨链方法,比如outboundTransfer
。deposit
第二个是
deposit
方法用于将 L2 层资产转移到以太坊 L1 层上,对应与前端页面 Deposit 操作。对应代码为:其中,合约区分了 ETH 和 ERC20 代币的存入方式。
存入资产后,合约产生了一个事件
FundsDeposited
,用于中继者程序捕获并进行资产跨链,事件信息包含合约部署的 L2 链ID,存款IDnumberOfDeposits
,L1层接收者,存款者,L1和L2层代币地址,数量和费率,以及时间戳。BridgePool
BridgePool
合约部署在 Layer 1 上,提供了给中继者完成 Layer2 上存款订单的函数。主要包含以下功能:addLiquidity
,removeLiquidity
;relayDeposit
relayAndSpeedUp
,speedUpRelay
disputeRelay
settleRelay
构造器
在合约初始时,合约设置了对应的桥管理员地址,L1代币地址,每秒的 LP 费率,以及标识是否为 WETH 池。同时,通过
syncUmaEcosystemParams
和syncWithBridgeAdminParams
两个方法同步了 Optimistic Oracle 地址信息,Store 的地址信息,以及对应的ProposerBondPct
,OptimisticOracleLiveness
等参数。添加和删除流动性
我们首先看到添加和删除流动性,添加流动性即流动性提供者向连接池中提供 L1 代币,并获取相应数量的 LP 代币作为证明,LP 代币数量根据现行汇率计算。
由于合约支持 WETH 作为流动性池,因此添加流动性区分了 WETH 和其他 ERC20 代币的添加方法。
此处的难点在于 LP 代币和 L1 代币之间的汇率换算
_exchangeRateCurrent
的实现,我们从合约中提取出了_exchangeRateCurrent
所使用的函数,包括_updateAccumulatedLpFees
和_sync
:换算汇率等于当前合约中代币的储备与总 LP 供应量的比值,计算步骤如下:
_updateAccumulatedLpFees
possibleUnpaidFees
,等于未分配的 Lp 费用undistributedLpFees
* 每秒 LP 费率 *(当前时间-上次更新时间),目前 WETH 桥接池中每秒LP费率为 0.0000015。unallocatedAccumulatedFees
,如果possibleUnpaidFees
小于未分配的 Lp 费用,则所有未分配的 LP 费用都将用于累积费用;liquidReserves
,则被使用的储备utilizedReserves
= 原先被使用的储备 -(当前合约中的代币储备 - 流动储备);利用换算汇率,可以计算得到添加
l1TokenAmount
数量的代币时所能得到的 LP 代币的数量。对于移除流动性,过程与添加流动性相反,这里不再赘述。
慢速中继
慢速中继,以及之后要讨论的即时中继,都会用到
DepositData
和RelayData
这两个数据,前者表示存框交易的数据,后者表示中继交易的信息。下面我们看到
relayDeposit
方法,这个方法由中继者调用,执行从 L2 到 L1 的慢速中继。对于每一个存款而言,只能有一个待处理的中继,这个待处理的中继不包括有争议的中继。可以看到,存款哈希与
depositData
有关,中继哈希与depositData
和relayData
都有关。最后我们可以看到,relayDeposit
还未实际付款给用户的 L1 地址,需要等待中继者处理,或者通过加速处理中继。加速中继
speedUpRelay
方法立即将存款金额减去费用后转发给l1Recipient
,即时中继者在待处理的中继挑战期后获得奖励。即时中继
relayAndSpeedUp
执行即时中继。这个方法的函数内容与relayDeposit
和speedUpRelay
方法是一致的,这里就不具体注释了,可以参考前文中的注释。这个函数的代码几乎是直接将relayDeposit
和speedUpRelay
的代码进行了合并,代码冗余。争议
当对待处理的中继提出争议时,争议者需要想 Optimistic Oracle 提交提案,并等待争议解决。
其中,
_requestProposeDispute
的函数内容如下:最后,我们来看看
settleRelay
。至此,我们分析完了 Across 合约的主要功能的代码。
合约部署
部署合约目录
deploy
下包含 8 脚本,依次部署了管理合约,WETH 桥接池,Optimism,Arbitrum和Boba的信使,以及 Arbitrum,Optimism 和 Boba 的存款合约。由于过程比较简单,这里就不仔细分析了。总结
Across 协议整体结构简单,流程清晰,支持了 Across 协议安全,快速的从 L2 向 L1 的资金转移。
代码中调用了 Optimistic Oracle 的接口来出和解决争议,对应的逻辑有空之后详说。
The text was updated successfully, but these errors were encountered: