• solidity“abi.encode/abi.encodePacked”使用golang编码


    uniswap v2 erc20合约中有一个预授权功能,也就是链下签名链上验证,授权方法如下:

        function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external {
            require(deadline >= block.timestamp, 'UniswapV2: EXPIRED');
            bytes32 digest = keccak256(
                abi.encodePacked(
                    'x19x01',
                    DOMAIN_SEPARATOR,
                    keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline))
                )
            );
            address recoveredAddress = ecrecover(digest, v, r, s);
            require(recoveredAddress != address(0) && recoveredAddress == owner, 'UniswapV2: INVALID_SIGNATURE');
            _approve(owner, spender, value);
        }
    

    里面在对签名数据进行编码时用到了abi.encode/abi.encodePacked两种方法,查阅solitidy文档得知两种方法区别在于:abi.encode 编码的数据需要32字节对齐,abi.encodePacked对小于32字节的数据不补0,以及其他一些区别:https://solidity.readthedocs.io/en/v0.7.3/abi-spec.html#abi-packed-mode

    使用golang实现如下

    // hash of packed byte array with arguments
    
    hash := crypto.Keccak256Hash(
            common.HexToAddress("0x0000000000000000000000000000000000000000").Bytes(),
            [32]byte{'I','D','1'},
            common.LeftPadBytes(big.NewInt(42).Bytes(), 32),// 不足32字节的补齐
            []byte("Some other string value"),//最后的参数不需要补齐
        )
    
    // normally we sign prefixed hash
    // as in solidity with `ECDSA.toEthSignedMessageHash`
    
    prefixedHash := crypto.Keccak256Hash(
            []byte(fmt.Sprintf("x19Ethereum Signed Message:
    %v", len(hash))),//不足32字节 不补齐
            hash.Bytes(),
        )
    

    最后,使用golang写了一个UNISWAP合约中相关计算的例子。

    
    const (
    	// keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)')
    	EIP712DomainHash = "0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f"
    	// keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
    	PERMIT_TYPEHASH = "0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9"
    )
    
    func calcDigest(verifyingContract, owner, spender ethcmn.Address, value *big.Int, nonce, deadline int64) ethcmn.Hash {
    	return crypto.Keccak256Hash(
    		[]byte("x19x01"),
    		calcDomainSeparatorHash(verifyingContract).Bytes(),
    		calcDigestPermitFuncHash(owner, spender, value, nonce, deadline).Bytes(),
    	)
    }
    
    func TestCalcDigest(t *testing.T) {
    	digest := calcDigest(ethcmn.HexToAddress("0x5B38Da6a701c568545dCfcB03FcB875f56beddC4"),
    		ethcmn.HexToAddress("0x5B38Da6a701c568545dCfcB03FcB875f56beddC4"),
    		ethcmn.HexToAddress("0x5B38Da6a701c568545dCfcB03FcB875f56beddC4"),
    		big.NewInt(123),
    		1,
    		1600000000)
    	fmt.Println(digest.Hex())
    }
    
    func calcDomainSeparatorHash(verifyingContract ethcmn.Address) ethcmn.Hash {
    	nameHash := crypto.Keccak256Hash([]byte("Uniswap V2")) //0xbfcc8ef98ffbf7b6c3fec7bf5185b566b9863e35a9d83acd49ad6824b5969738
    	versionHash := crypto.Keccak256Hash([]byte("1"))       //0xc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6
    	chainId := big.NewInt(1).Bytes()
    	return crypto.Keccak256Hash(
    		ethcmn.HexToHash(EIP712DomainHash).Bytes(),
    		nameHash.Bytes(),
    		versionHash.Bytes(),
    		ethcmn.LeftPadBytes(chainId, 32),
    		ethcmn.LeftPadBytes(verifyingContract.Bytes(), 32),
    	)
    }
    
    func calcDigestPermitFuncHash(owner, spender ethcmn.Address, value *big.Int, nonce int64, deadline int64) ethcmn.Hash {
    	return crypto.Keccak256Hash(
    		ethcmn.HexToHash(PERMIT_TYPEHASH).Bytes(),
    		ethcmn.LeftPadBytes(owner.Bytes(), 32),
    		ethcmn.LeftPadBytes(spender.Bytes(), 32),
    		ethcmn.LeftPadBytes(value.Bytes(), 32),
    		ethcmn.LeftPadBytes(big.NewInt(nonce).Bytes(), 32),
    		ethcmn.LeftPadBytes(big.NewInt(deadline).Bytes(), 32),
    	)
    }
    
    
  • 相关阅读:
    thinkPHP中怎么访问域名直接跳到后台登录页面
    使用ajax方法实现form表单的提交
    微信小程序根据生日获取年龄
    微信小程序出现 text 设置行高 line-height 无效的问题
    微信小程序中换行,空格(多个空格)写法
    如何用css实现弧度圆角?三角形以及圆形
    微信小程序的bindtap事件
    JS控制只能输入数字并且最多允许小数点两位
    微信小程序如何做金额输入限制
    微信小程序使用函数的三种方法
  • 原文地址:https://www.cnblogs.com/cqvoip/p/13852705.html
Copyright © 2020-2023  润新知