EIP712以太坊签名和验签

EIP712旨在提高链下消息签名对链上的可用性。我们可以看到,因为节省gas以及减少链上交易的原因,采用链下消息签名的需求日益增长。现在已经被签名的消息,展示给用户的是一串难以理解的16进制的字符串,附带一些组成这个消息的项目的上下文。

EIP-712: Ethereum typed structured data hashing and signingicon-default.png?t=M1L8https://eips.ethereum.org/EIPS/eip-712Signing Data | MetaMask DocsDeveloper documentation for the MetaMask Ethereum wallethttps://docs.metamask.io/guide/signing-data.htmlDraft EIPs - OpenZeppelin Docsicon-default.png?t=M1L8https://docs.openzeppelin.com/contracts/3.x/api/draftsV4签名的js示例:

//创建web3对象
var Web3 = require('web3');
var sigUtil = require("eth-sig-util")
var provider = new Web3.providers.HttpProvider("http://localhost:7545");
var web3 = new Web3(provider);

var json = require("../build/contracts/Demo.json");
var contractAddr = '';

var account = "";
var account_to = "";
var privateKey = "";
var privateKeyHex = Buffer.from(privateKey, 'hex')

var demoContract = new web3.eth.Contract(json['abi'], contractAddr);

//获取链ID
demoContract.methods.getChainId().call({from: account}, function(error, result){
  if (error) {
    console.log(error);
  }
  console.log("getChainId:", result);
});

//V4签名
const typedData = {
  types: {
    EIP712Domain: [
      { name: 'name', type: 'string' },
      { name: 'version', type: 'string' },
      { name: 'chainId', type: 'uint256' },
      { name: 'verifyingContract', type: 'address' },
    ],
    Mail: [
      { name: 'from', type: 'address' },
      { name: 'to', type: 'address' },
      { name: 'value', type: 'uint256' },
    ],
  },
  domain: {
    name: 'Demo',
    version: '1.0',
    chainId: 1,
    verifyingContract: contractAddr,
  },
  primaryType: 'Mail',
  message: {
    from: account,
    to: account_to,
    value: 12345,
  },
}

//V4签名
var signature = sigUtil.signTypedData_v4(privateKeyHex, { data: typedData })
console.log("signature:", signature)

//V4验签
const recovered = sigUtil.recoverTypedSignature_v4({
  data: typedData,
  sig: signature,
});
console.log("recovered:", recovered)

//合约V4验签
demoContract.methods.verify(typedData.message.from, typedData.message.to, typedData.message.value, signature).call({from: account}, function(error, result){
  if (error) {
    console.log(error);
  }
  console.log("verify:", result);
});

V4验签的sol示例:

pragma solidity >=0.6.0 <0.9.0;

import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract Demo is EIP712 {
    constructor(string memory name, string memory version) EIP712(name, version) {
    }

    //获取签名人(V4)
    function recoverV4(
        address from,
        address to,
        uint256 value,
        bytes memory signature
    ) public view returns (address) {
        bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
        keccak256("Mail(address from,address to,uint256 value)"),
            from,
            to,
            value
        )));
        return ECDSA.recover(digest, signature);
    }

    //验签
    function verify(
        address from,
        address to,
        uint256 value,
        bytes memory signature
    ) public view returns (bool) {
        address signer = recoverV4(from, to, value, signature);
        return signer == from;
    }

    function getChainId() public view returns(uint256) {
        return block.chainid;
    }
}

猜你喜欢

转载自blog.csdn.net/watson2017/article/details/123131401