Solidity

無法驗證簽名

  • August 16, 2021

我正在嘗試為即將到來的項目掌握 Web3 和 Solidity 的竅門。所以現在我只是在擺弄一些不同的東西,而且我一直堅持驗證簽名。我可以簽名,但我無法驗證。在過去的兩個晚上,我每晚都在嘗試 3-4 個小時,但我根本無法弄清楚問題是什麼,所以現在我爬到這裡尋求幫助。

我在這裡包含了我的客戶端和契約程式碼。我希望有人能指出我正確的方向。我確實從verify對契約的呼叫中得到了結果,但結果始終是false.

契約程式碼或多或少是從https://solidity-by-example.org/signature/複製/粘貼的,我知道這有點過時了。

以下範例中的所有地址和密鑰均來自測試網。

客戶端,使用 MetaMask:

const contractAddress = '0x94F9f9d16f2cb8542BE31D6fA99471Ea8251D7eC';

const sign = async (address) => {
 const nonce = Math.floor(Math.random() * 10000000000) + 1;
 console.log(nonce);

 const data = [{"address": address}, {"uint256": 1000000}, {"uint256": nonce}, {"address": contractAddress}];
 console.log(window.web3.eth.accounts.sign(generateHash(data), '61323f1a2911e70573be49819e68a7dbffa10216135bb06171e596a4f89bfd79'));
}

const verify = async (address, nonce, signature) => {
 const contractInstance = new window.web3.eth.Contract(
   ABI[0].abi,
   contractAddress,
   {
     from: address,
   }
 );

 const result = contractInstance.methods.verify(contractAddress, address, 1000000, nonce, signature).call(function (error, result) {
   console.log(result);
 });
}

const generateHash = (data) => {
 const keys = data.map((item) => {
   return Object.keys(item)[0];
 });

 const values = data.map((item) => {
   return Object.values(item)[0];
 });

 return "0x" + ethereumjs.soliditySHA3(keys, values).toString("hex");
}

//sign('0x93E16885EE732BFF281285efe2f2F46Dc92590C5');
verify('0x93E16885EE732BFF281285efe2f2F46Dc92590C5', 3421724946, '0x7eba658b197add3604c7d25c9305507cc67dd7a9298862fb4fcf2a2bcfd274d6039681008fa7a6201194258dee17eed4d709ea704427135cb80731a44908d29a1b');
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;

import "hardhat/console.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import '@openzeppelin/contracts/access/Ownable.sol';

contract Moonboi is ERC20, Ownable {
 constructor() ERC20("Moonboi Token", "MBT") {}

   function getMessageHash(
       address _to, uint _amount, uint _nonce
   ) public view returns (bytes32) {
       return keccak256(abi.encodePacked(_to, _amount, _nonce));
   }

   function getEthSignedMessageHash(bytes32 _messageHash) public pure returns (bytes32) {
       return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", _messageHash));
   }

   function verify(
       address _signer,
       address _to, uint256 _amount, uint256 _nonce,
       bytes memory signature
   ) public view returns (bool) {
       bytes32 messageHash = getMessageHash(_to, _amount, _nonce);
       bytes32 ethSignedMessageHash = getEthSignedMessageHash(messageHash);

       return recoverSigner(ethSignedMessageHash, signature) == _signer;
   }

   function recoverSigner(bytes32 _ethSignedMessageHash, bytes memory _signature) public pure returns (address) {
       (bytes32 r, bytes32 s, uint8 v) = splitSignature(_signature);

       return ecrecover(_ethSignedMessageHash, v, r, s);
   }

   function splitSignature(bytes memory sig) public pure returns (bytes32 r, bytes32 s, uint8 v) {
       require(sig.length == 65, "invalid signature length");

       assembly {
           r := mload(add(sig, 32))
           s := mload(add(sig, 64))
           v := byte(0, mload(add(sig, 96)))
       }

       return (r, s, v);
   }
}

我弄清楚我做錯了什麼,所以我會在這裡添加我的發現作為答案,以防其他人犯了同樣的錯誤。一旦我意識到發生了什麼,問題就很明顯了。

在呼叫智能合約方法時verify,我將智能合約地址作為簽名者傳入,而實際上簽名者是智能合約的所有者。

所以在這個方法中:

const verify = async (address, nonce, signature) => {
 const contractInstance = new window.web3.eth.Contract(
   ABI[0].abi,
   contractAddress,
   {
     from: address,
   }
 );

 contractInstance.methods.verify(contractAddress, address, 1000000, nonce, signature).call(function (error, result) {
   console.log(error);
   console.log(result);
 });
}

..verify方法中的第一個參數應該是契約所有者,如下所示:

const contractOwner = '0xa914E79148447A9affe1bCC4A72859e26c0f75AB';

contractInstance.methods.verify(contractOwner, address, 1000000, nonce, signature).call(function (error, result) {
 console.log(error);
 console.log(result);
});

我犯的另一個錯誤是私鑰需要以 為前綴0x,所以:

window.web3.eth.accounts.sign(generateHash(data), '61323f1a2911e70573be49819e68a7dbffa10216135bb06171e596a4f89bfd79')

不會奏效的。我應該進去0x61323f1a2911e70573be49819e68a7dbffa10216135bb06171e596a4f89bfd79

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