Solidity
無法從地址和 uint256 構造散列以進行 ecrecover 和簽名驗證
我正在使用 web3.js 創建一個簽名,形成一個包含兩個數字和一個地址的散列消息:
const tokenIds = [1,2,3]; const state = 1; const messageHash = web3.utils.keccak256(tokenIds.length + state + web3.utils.keccak256(fromAddress)); const sign = await web3.eth.accounts.sign(messageHash, signer.privateKey); await contract.myFn( tokenIds, sign.v, sign.r, sign.s, { from: fromAddress, } );
然後在我的智能合約中,我嘗試重建雜湊
message
並驗證簽名,如下所示:function myFn(uint[] calldata tokenIds, uint8 v, bytes32 r, bytes32 s) external { require( _signerAddress == ecrecover( keccak256(abi.encodePacked( "\x19Ethereum Signed Message:\n32", // messageHash: // When I concat those two strings with the address // this hash is invalid (not the same as the on from the client). keccak256(abi.encodePacked( // uint256 amount Strings.toString(tokenIds.length), // uint256 state Strings.toString(state), // address msg.sender is fromAddress keccak256(abi.encodePacked(msg.sender)) )) )) , v, r, s ), 'mint not allowed' ); }
基本上,在雜湊上重新創建時的字元串連接
messageHash
似乎不匹配。也許有一種可靠的方法可以將msg.sender
(fromAddress
) 轉換為字元串?
多虧了這篇精彩的文章,我才明白了這一點。
秘訣是使用
web3.utils.soliditySha3
which 將像 Solidity 一樣進行 abi 編碼和散列!const message = web3.utils.soliditySha3( tokenIds.length, state, fromAddress );
並在契約中簡單地做:
keccak256(abi.encodePacked( tokenIds.length, state, msg.sender ))