适配新链ID教程
#
新应用如何适配PlatON新链IDPlatON主网关于支持新链ID的提案PIP-7已经获得通过,并且第一阶段已经在主网实施,这意味着PlatON主网的ChainId将会从100 逐步切换到新值210425,为了尽量减少应用在后续版本升级过程中的影响,新应用应尽量从一开始就支持新的ChainId。
但是现阶段PlatON EVM虚拟机返回给合约的ChainId还是100(之后会返回210425),所以在开发应用的过程中如果有与链ID有关的逻辑需要做特别的适配,下文的实例将从两个场景来介绍适配的地方,第一个是PRC20 代币permit方法,第二个治理代币的投票权委托。
#
PRC20 代币permit方法通常Swap在每次移除流动性的时候,需要先使用metamask的eth_signTypedData_v4接口在客户端签名(签名内容包含ChainId),然后使用签名作为参数调用router合约的removeLiquidityWithPermit,签名是用来做PRC20合约的permit(允许合约扣用户的PRC20资产)
适配代码如下所示:
constructor()函数增加DOMAIN_SEPARATOR_NEW,生成方法包含210425的ChainId
......DOMAIN_SEPARATOR = keccak256( abi.encode( keccak256('EIP712Domain(string name,string version,uint256 ChainId,address verifyingContract)'), keccak256(bytes(name)), keccak256(bytes('1')), ChainId, address(this) ));DOMAIN_SEPARATOR_NEW = keccak256( abi.encode( keccak256('EIP712Domain(string name,string version,uint256 ChainId,address verifyingContract)'), keccak256(bytes(name)), keccak256(bytes('1')), 210425, address(this) ));......
permit函数增加对于两个ChainId相关签名的验证
require(deadline >= block.timestamp, 'EXPIRED');bytes32 digest = keccak256( abi.encodePacked( '\x19\x01', DOMAIN_SEPARATOR_NEW, keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner], deadline)) ));address recoveredAddress = ecrecover(digest, v, r, s);if (recoveredAddress == address(0) || recoveredAddress != owner) { digest = keccak256( abi.encodePacked( '\x19\x01', DOMAIN_SEPARATOR, keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner], deadline)) ) ); recoveredAddress = ecrecover(digest, v, r, s); require(recoveredAddress != address(0) && recoveredAddress == owner, 'INVALID_SIGNATURE');}
nonces[owner] += 1;......
#
治理代币投票权委托治理代币投票权委托的时候也用到了类似的签名和验证逻辑。代码修改如下:
delegateBySig函数增加对于两个ChainId相关签名的验证
constructor(address account, address minter_) public { ...... DOMAIN_SEPARATOR = keccak256(abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(name)), getChainId(), address(this))); DOMAIN_SEPARATOR_NEW = keccak256(abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(name)), 210425, address(this)));} ......
function delegateBySig(address delegatee, uint nonce, uint expiry, uint8 v, bytes32 r, bytes32 s) public { bytes32 structHash = keccak256(abi.encode(DELEGATION_TYPEHASH, delegatee, nonce, expiry)); bytes32 digest = keccak256(abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR_NEW, structHash)); address signatory = ecrecover(digest, v, r, s); if (signatory == address(0) || nonce != nonces[signatory]) { digest = keccak256(abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR, structHash)); signatory = ecrecover(digest, v, r, s); require(signatory != address(0), "delegateBySig: invalid signature"); require(nonce == nonces[signatory], "delegateBySig: invalid nonce"); } nonces[signatory] += 1; require(now <= expiry, "delegateBySig: signature expired"); return _delegate(signatory, delegatee);}