EIP712旨在提高链下消息签名对链上的可用性。我们可以看到,因为节省gas以及减少链上交易的原因,采用链下消息签名的需求日益增长。现在已经被签名的消息,展示给用户的是一串难以理解的16进制的字符串,附带一些组成这个消息的项目的上下文。
EIP-712: Ethereum typed structured data hashing and signinghttps://eips.ethereum.org/EIPS/eip-712Signing Data | MetaMask DocsDeveloper documentation for the MetaMask Ethereum wallethttps://docs.metamask.io/guide/signing-data.htmlDraft EIPs - OpenZeppelin Docshttps://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;
}
}