Solidity

無法從地址和 uint256 構造散列以進行 ecrecover 和簽名驗證

  • January 13, 2022

我正在使用 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.soliditySha3which 將像 Solidity 一樣進行 abi 編碼和散列!

const message = web3.utils.soliditySha3(
 tokenIds.length,
 state,
 fromAddress
);

並在契約中簡單地做:

keccak256(abi.encodePacked(
 tokenIds.length,
 state,
 msg.sender
))

引用自:https://ethereum.stackexchange.com/questions/118763