作者:林冠宏 / 指尖下的幽灵。转载者,请: 务必标明出处。
掘金:https://juejin.im/user/1785262612681997
博客:http://www.cnblogs.com/linguanh/
GitHub : https://github.com/af913337456/
出版的书籍:
- 《1.0-区块链DApp开发实战》
- 《2.0-区块链DApp开发:基于公链》
本次是系列文章,这是第二篇。第一篇在: 以太坊 layer2: optimism 源码学习 (一)
目录:
- 为什么存在提现动作
- 提现的原子性
- 提现的调用链
- 源码中的提现实现
- 下一篇核心组件
Relayer
的源码实现
为什么存在提现动作?
OP 本质是个大型的 DApp,我们要使用它,就要先从以太坊的主网充值 Token 进去,充值的原理及其源码分析在第一篇文章中。
用户在 OP 里面进行了系列的交易动作后,需要把 Token 转回到主网,才能与其他的 DApp 的交互或主网转账。因此对应地,OP 提供了提现 Token 到主网的功能。
提现的原子性
虽然在 OP 中的交易都直接发生在 OP 的网络中,比如转账的地址是 OP 网络中的以太坊地址。但是所有的交易都会被同步到以太坊主网中,与 OP 的合约发生实际的主网交互。这就意味着,地址所在 OP 中 Token 余额的变化也会导致主网上的余额变化。这一点见第一篇文章中的 OP 原理介绍。
提现的调用链
用户是提现发起的对象,提现遵循下面的步骤:
- 用户向 OP 的
Sequencer
发起提现交易; - 这笔交易是一次合约调用交易,指向
L2StanderBridger.sol
中的withdraw
函数; withdraw
函数中会构造最后在主网合约中发起真正提现的函数数据;- 交易被 OP 网络正常打包;
- 交易被
Batch-Submitter
提交到主网CTC
合约,走正常的挑战机制; - 挑战期过后,
Relayer
为此交易生成证明,调用 L1 上的L1CrossDomainMessenger.relayMessage
函数,使之完成合约检查
然后在内部调用目标合约,最终在 L1 完成 L2 交易的最终目的,用户的 Token 在 L1 地址上得到了提现; - 提现闭环。
源码中的提现实现
首先是 L2 上的 withdraw
函数,如下图所示,参数细节描述在图中。要知道同个地址的私钥是一样的,意味着用户在 OP 的地址,在主网上,一样是这个私钥所拥有所有权。
withdraw
函数组装 L1 合约上的目标最终提现函数。如下图所示,留意这句重点 IL1StandardBridge.finalizeETHWithdrawal.selector
,和充值流程中的 deposit.selector
是异曲同工
的做法。
最终 Relayer
会调用到的 L1CrossDomainMessenger.relayMessage
函数,在这个函数里面,就会把前面包装的,对应到 L1StandardBridge.sol
合约中的 finalizeETHWithdrawal
函数给执行掉。实现最终的提现。如下图所示。
上图 relayMessage
函数中,_target
就是合约 L1StandardBridge.sol
,_message
就是被 L2StanderBriger.sol
的提现函数中包装的数据,如下:
message = abi.encodeWithSelector(
IL1StandardBridge.finalizeETHWithdrawal.selector,
_from,
_to,
_amount,
_data
);
这个 message
就是对应 relayMessage
函数中的 _message
。最终执行到 L1StandardBridge.sol
中的 finalizeETHWithdrawal
函数,其源码如下: