名词解释
RootChain | polygon的基链,部署了polygon的staking等一系列合约,指 EthereumMainnet 或 Goerli |
ChildChain | Polygon 主网或 Mumbai 测试网 |
RootToken | 桥的 RootChain 侧对应的token,即在以太坊链上部署的token |
ChildToken | 桥的ChildChain 侧对应的token,即在Polygon链上部署的token |
PoS-Bridge & Plasma Bridge
桥是用来帮助资产在 RootChain 和ChildChain 之间转移的,由一系列合约实现。
Polygon 提供了两种桥, Plasma Bridge 和 PoS Bridge.
由于Plasma的退出机制,Plasma桥更加安全, 并且从Polygon到Etherum方向的withdraw 有七天的提现周期.
相应的,PoS Bridge 只需要一个 checkpoint 周期.
PoS Bridge 实现原理
PoS Bridge 由一系列合约实现,合约链接 https://github.com/maticnetwork/contracts/blob/main/contracts .
1. 创建token映射
如果你的token需要PoS Bridge 支持以太坊-Polygon间传输,需要添加一个映射,即 RootToken 与 ChildToken 的对应关系.
Polygon 提供了操作页面 https://mapper.polygon.technology/ ,帮助你提交映射请求。提交请求之后,由Polygon Team 帮助你在合约中加入映射关系。
映射的合约代码在 https://github.com/maticnetwork/contracts/blob/main/contracts/common/Registry.sol
/**
* @dev Map root token to child token
* @param _rootToken Token address on the root chain
* @param _childToken Token address on the child chain
* @param _isERC721 Is the token being mapped ERC721
*/
function mapToken(
address _rootToken,
address _childToken,
bool _isERC721
) external onlyGovernance {
require(_rootToken != address(0x0) && _childToken != address(0x0), "INVALID_TOKEN_ADDRESS");
rootToChildToken[_rootToken] = _childToken;
childToRootToken[_childToken] = _rootToken;
isERC721[_rootToken] = _isERC721;
IWithdrawManager(contractMap[WITHDRAW_MANAGER]).createExitQueue(_rootToken);
emit TokenMapped(_rootToken, _childToken);
}
只有Polygon团队有权限调用这个接口。
2. token从以太坊转至Polygon
当需要将token从以太坊转到Polygon时,由以太坊上部署的Depositmanager合约来处理.
https://github.com/maticnetwork/contracts/blob/main/contracts/root/depositManager/DepositManager.sol
rootchain
以ERC20为例, 当用户将token从以太坊转移至Polygon时,在以太坊的合约中进行了锁定,并通过StateSender机制,将此消息发送到了 Polygon 的 ChildERC20合约中. StateSender 机制在其他文档中有描述,是Polygon实现的一种 以太坊和Polygon之间的双向通信机制。
function depositERC20(address _token, uint256 _amount) external {
depositERC20ForUser(_token, msg.sender, _amount);
}
function depositERC20ForUser(
address _token,
address _user,
uint256 _amount
) public {
require(_amount <= maxErc20Deposit, "exceed maximum deposit amount");
IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount);
_safeCreateDepositBlock(_user, _token, _amount);
}
function _safeCreateDepositBlock(
address _user,
address _token,
uint256 _amountOrToken
) internal onlyWhenUnlocked isTokenMapped(_token) {
_createDepositBlock(
_user,
_token,
_amountOrToken,
rootChain.updateDepositId(1) /* returns _depositId */
);
}
function _createDepositBlock(
address _user,
address _token,
uint256 _amountOrToken,
uint256 _depositId
) internal {
deposits[_depositId] = DepositBlock(keccak256(abi.encodePacked(_user, _token, _amountOrToken)), now);
stateSender.syncState(childChain, abi.encode(_user, _token, _amountOrToken, _depositId));
emit NewDepositBlock(_user, _token, _amountOrToken, _depositId);
}
child chain
在Polygon链上的 ChildChain 合约代码地址
https://github.com/maticnetwork/contracts/blob/main/contracts/child/ChildChain.sol
当root chain 通过stateSender 发送了deposit消息后,经过一个 checkpoint周期 ,在childchain合约中会收到该信息. 并调用相应的childToken合约的deposit接口.
function onStateReceive(
uint256, /* id */
bytes calldata data
) external onlyStateSyncer {
(address user, address rootToken, uint256 amountOrTokenId, uint256 depositId) = abi
.decode(data, (address, address, uint256, uint256));
depositTokens(rootToken, user, amountOrTokenId, depositId);
}
function depositTokens(
address rootToken,
address user,
uint256 amountOrTokenId,
uint256 depositId
) internal {
// check if deposit happens only once
require(deposits[depositId] == false);
// set deposit flag
deposits[depositId] = true;
// retrieve child tokens
address childToken = tokens[rootToken];
// check if child token is mapped
require(childToken != address(0x0));
ChildToken obj;
if (isERC721[rootToken]) {
obj = ChildERC721(childToken);
} else {
obj = ChildERC20(childToken);
}
// deposit tokens
obj.deposit(user, amountOrTokenId);
// Emit TokenDeposited event
emit TokenDeposited(
rootToken,
childToken,
user,
amountOrTokenId,
depositId
);
}
ChildChain 是由Polygon 团队部署的,不必每个token开发者部署。token开发者必须在合约中实现 deposit 和 withdraw 方法.
当在childchain 中调用deposit方法时,token合约为该跨链用户 mint 出相应数量的token.文章来源:https://www.toymoban.com/news/detail-680758.html
示例如下:文章来源地址https://www.toymoban.com/news/detail-680758.html
pragma solidity 0.6.6;
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
contract ChildERC20 is ERC20,
{
using SafeMath for uint256;
constructor(string memory name, string memory symbol, uint8 decimals) public ERC20(name, symbol) {
_setupDecimals(decimals);
// can't mint here, because minting in child chain smart contract's constructor not allowed
// _mint(msg.sender, 10 ** 27);
}
function deposit(address user, bytes calldata depositData) external {
uint256 amount = abi.decode(depositData, (uint256));
// `amount` token getting minted here & equal amount got locked in RootChainManager
_totalSupply = _totalSupply.add(amount);
_balances[user] = _balances[user].add(amount);
emit Transfer(address(0), user, amount);
}
function withdraw(uint256 amount) external {
_balances[msg.sender] = _balances[msg.sender].sub(amount, "ERC20: burn amount exceeds balance");
_totalSupply = _totalSupply.sub(amount);
emit Transfer(msg.sender, address(0), amount);
}
}
资产从 Polygon 转移到 以太坊的实现原理和上面的过程基本一致.
到了这里,关于Polygon POS 桥实现原理的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!