使用Polygon zkEVM Bridge 站点,将网络添加到我们的钱包,并将 Goerli Token 桥接到 zkEVM Testnet:
Goerli Token转0.01 ETH到zkEVM Testnet
交易:0x10210572d6b4924af7ef946136295e9b209e1fa0 -> 0xf6beeebb578e214ca9e23b0e9683454ff88ed2a7
tx hash: https://goerli.etherscan.io/tx/0x07aa6363c5854180b41b8c4584314ca6d6af989d48332375f06f9caef3270dd7
执行合约
bridgeAsset(uint32 destinationNetwork,address destinationAddress,uint256 amount,address token,bool forceUpdateGlobalExitRoot,bytes permitData)
执行参数
Name | Type | Data | |
---|---|---|---|
0 | destinationNetwork | uint32 | 1 |
1 | destinationAddress | address | 0x10210572d6b4924Af7Ef946136295e9b209E1FA0 |
2 | amount | uint256 | 10000000000000000 |
3 | token | address | 0x0000000000000000000000000000000000000000 |
4 | forceUpdateGlobalExitRoot | bool | true |
5 | permitData | bytes |
0xF6BEEeBB578e214CA9E23B0e9683454Ff88Ed2A7为代理合约,使用EIP-1967 Transparent Proxy
逻辑合约地址:0x39e780D8800f7396e8B7530A8925B14025AedC77
关键逻辑合约代码:https://goerli.etherscan.io/address/0x39e780d8800f7396e8b7530a8925b14025aedc77#code
合约bridgeAsset接口源码
/**
* @notice Deposit add a new leaf to the merkle tree
* @param destinationNetwork Network destination
* @param destinationAddress Address destination
* @param amount Amount of tokens
* @param token Token address, 0 address is reserved for ether
* @param forceUpdateGlobalExitRoot Indicates if the new global exit root is updated or not
* @param permitData Raw data of the call `permit` of the token
*/
function bridgeAsset(
uint32 destinationNetwork,
address destinationAddress,
uint256 amount,
address token,
bool forceUpdateGlobalExitRoot,
bytes calldata permitData
) public payable virtual ifNotEmergencyState nonReentrant {
if (
destinationNetwork == networkID ||
destinationNetwork >= _CURRENT_SUPPORTED_NETWORKS
) {
revert DestinationNetworkInvalid();
}
address originTokenAddress;
uint32 originNetwork;
bytes memory metadata;
uint256 leafAmount = amount;
if (token == address(0)) {
// Ether transfer
if (msg.value != amount) {
revert AmountDoesNotMatchMsgValue();
}
// Ether is treated as ether from mainnet
originNetwork = _MAINNET_NETWORK_ID;
} else {
// Check msg.value is 0 if tokens are bridged
if (msg.value != 0) {
revert MsgValueNotZero();
}
TokenInformation memory tokenInfo = wrappedTokenToTokenInfo[token];
if (tokenInfo.originTokenAddress != address(0)) {
// The token is a wrapped token from another network
// Burn tokens
TokenWrapped(token).burn(msg.sender, amount);
originTokenAddress = tokenInfo.originTokenAddress;
originNetwork = tokenInfo.originNetwork;
} else {
// Use permit if any
if (permitData.length != 0) {
_permit(token, amount, permitData);
}
// In order to support fee tokens check the amount received, not the transferred
uint256 balanceBefore = IERC20Upgradeable(token).balanceOf(
address(this)
);
IERC20Upgradeable(token).safeTransferFrom(
msg.sender,
address(this),
amount
);
uint256 balanceAfter = IERC20Upgradeable(token).balanceOf(
address(this)
);
// Override leafAmount with the received amount
leafAmount = balanceAfter - balanceBefore;
originTokenAddress = token;
originNetwork = networkID;
// Encode metadata
metadata = abi.encode(
_safeName(token),
_safeSymbol(token),
_safeDecimals(token)
);
}
}
emit BridgeEvent(
_LEAF_TYPE_ASSET,
originNetwork,
originTokenAddress,
destinationNetwork,
destinationAddress,
leafAmount,
metadata,
uint32(depositCount)
);
_deposit(
getLeafValue(
_LEAF_TYPE_ASSET,
originNetwork,
originTokenAddress,
destinationNetwork,
destinationAddress,
leafAmount,
keccak256(metadata)
)
);
// Update the new root to the global exit root manager if set by the user
if (forceUpdateGlobalExitRoot) {
_updateGlobalExitRoot();
}
}
// TODO 代码分析
等待zkevm-test处理完成
zkevm-test处理完成
Bridge Details
zkevm-test 对应交易
交易 0xa49d20f2f5a26d4a8e6fe44409f862d744f5b1aa -> 0xf6beeebb578e214ca9e23b0e9683454ff88ed2a7
tx hash: https://testnet-zkevm.polygonscan.com/tx/0x830ac94e69eb9e3aacd384d4db8a46e7830b8f99b12b5c6b5176bd8326fddc4b
执行方法
claimAsset(bytes32[32] smtProof,uint32 index,bytes32 mainnetExitRoot,bytes32 rollupExitRoot,uint32 originNetwork,address originTokenAddress,uint32 destinationNetwork,address destinationAddress,uint256 amount,bytes metadata)
执行参数
# | Name | Type | Data |
---|---|---|---|
0 | smtProof | bytes32[32] | 0x0000000000000000000000000000000000000000000000000000000000000000 0x5c4dafd55279a81649518c48d62f1e9105c9e7f5a8933aa2fce126d207755c14 0x890afe4ec8996c6ddd3977287b067f0f67dd25cd11cda85b22a93deac5675cdd 0xb6b78f0847e6ecdfc18ee568a1349fae5f336bdce9716be04db241b68b8dd60b 0x18dd01806c4a8a02ac0303f33fe609a944d81197cb52e8b8e159fbf9e45f12ed 0x0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d 0x4ac259557eb77da7cf4309feb02d02d0884d94e56bbf71f539bb3871e5c5f0db 0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83 0x08f9cb503a809cc64017397ec880786e6713c3ba6a85c181d02ae7536e9b58e3 0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0 0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5 0xa647f1787afe7ec81c77a49649ba32057b0550470d3c9318dda05fcb8168d914 0xe1f88e3362870dcdb9c43a352e2b031a0c71080b78cc2a5732c3a5c1c0c8e3b4 0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb 0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc 0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2 0x645b9978ad76c57db977fe48efb0b43110e3ebe78f9badd9047aac6bcd8d66a5 0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a 0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0 0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0 0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2 0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9 0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377 0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652 0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef 0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d 0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0 0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e 0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e 0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322 0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735 0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9 |
1 | index | uint32 | 72030 |
2 | mainnetExitRoot | bytes32 | 0x8ac4bfc9b4381015f4d41ca9d127a0a4065827d9c61ae290ffbf401ae446a97a |
3 | rollupExitRoot | bytes32 | 0xd226edaccb2a0c0dc760d2a670a84862a271af7916e0a289b286f61435378411 |
4 | originNetwork | uint32 | 0 |
5 | originTokenAddress | address | 0x0000000000000000000000000000000000000000 |
6 | destinationNetwork | uint32 | 1 |
合约地址0xf6beeebb578e214ca9e23b0e9683454ff88ed2a7 为 EIP-1967 Transparent Proxy代理合约,代理的逻辑合约地址为0x39e780d8800f7396e8b7530a8925b14025aedc77
合约源码:https://testnet-zkevm.polygonscan.com/address/0x39e780d8800f7396e8b7530a8925b14025aedc77#code
/**
* @notice Verify merkle proof and withdraw tokens/ether
* @param smtProof Smt proof
* @param index Index of the leaf
* @param mainnetExitRoot Mainnet exit root
* @param rollupExitRoot Rollup exit root
* @param originNetwork Origin network
* @param originTokenAddress Origin token address, 0 address is reserved for ether
* @param destinationNetwork Network destination
* @param destinationAddress Address destination
* @param amount Amount of tokens
* @param metadata Abi encoded metadata if any, empty otherwise
*/
function claimAsset(
bytes32[_DEPOSIT_CONTRACT_TREE_DEPTH] calldata smtProof,
uint32 index,
bytes32 mainnetExitRoot,
bytes32 rollupExitRoot,
uint32 originNetwork,
address originTokenAddress,
uint32 destinationNetwork,
address destinationAddress,
uint256 amount,
bytes calldata metadata
) external ifNotEmergencyState {
// Verify leaf exist and it does not have been claimed
_verifyLeaf(
smtProof,
index,
mainnetExitRoot,
rollupExitRoot,
originNetwork,
originTokenAddress,
destinationNetwork,
destinationAddress,
amount,
metadata,
_LEAF_TYPE_ASSET
);
// Transfer funds
if (originTokenAddress == address(0)) {
// Transfer ether
/* solhint-disable avoid-low-level-calls */
(bool success, ) = destinationAddress.call{value: amount}(
new bytes(0)
);
if (!success) {
revert EtherTransferFailed();
}
} else {
// Transfer tokens
if (originNetwork == networkID) {
// The token is an ERC20 from this network
IERC20Upgradeable(originTokenAddress).safeTransfer(
destinationAddress,
amount
);
} else {
// The tokens is not from this network
// Create a wrapper for the token if not exist yet
bytes32 tokenInfoHash = keccak256(
abi.encodePacked(originNetwork, originTokenAddress)
);
address wrappedToken = tokenInfoToWrappedToken[tokenInfoHash];
if (wrappedToken == address(0)) {
// Get ERC20 metadata
(
string memory name,
string memory symbol,
uint8 decimals
) = abi.decode(metadata, (string, string, uint8));
// Create a new wrapped erc20 using create2
TokenWrapped newWrappedToken = (new TokenWrapped){
salt: tokenInfoHash
}(name, symbol, decimals);
// Mint tokens for the destination address
newWrappedToken.mint(destinationAddress, amount);
// Create mappings
tokenInfoToWrappedToken[tokenInfoHash] = address(
newWrappedToken
);
wrappedTokenToTokenInfo[
address(newWrappedToken)
] = TokenInformation(originNetwork, originTokenAddress);
emit NewWrappedToken(
originNetwork,
originTokenAddress,
address(newWrappedToken),
metadata
);
} else {
// Use the existing wrapped erc20
TokenWrapped(wrappedToken).mint(destinationAddress, amount);
}
}
}
emit ClaimEvent(
index,
originNetwork,
originTokenAddress,
destinationAddress,
amount
);
}
// TODO 代码分析
确认余额
https://testnet-zkevm.polygonscan.com/address/0x10210572d6b4924af7ef946136295e9b209e1fa0
// Note: Our ETH balance display is temporarily unavailable. Please check back later.
testnet-zkevm.polygonscan.com 浏览器余额出问题了,直接MetaMask查看
以正确到账
//TODO testnet-zkevm反向Goerli的转账跟踪