1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
| // SPDX-License-Identifier: MIT // By 0xAA pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
contract EIP712Storage { using ECDSA for bytes32;
bytes32 private constant EIP712DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); bytes32 private constant STORAGE_TYPEHASH = keccak256("Storage(address spender,uint256 number)"); bytes32 private DOMAIN_SEPARATOR; uint256 number; address owner;
constructor(){ DOMAIN_SEPARATOR = keccak256(abi.encode( EIP712DOMAIN_TYPEHASH, // type hash keccak256(bytes("EIP712Storage")), // name keccak256(bytes("1")), // version block.chainid, // chain id address(this) // contract address )); owner = msg.sender; }
/** * @dev Store value in variable */ function permitStore(uint256 _num, bytes memory _signature) public { // 检查签名长度,65是标准r,s,v签名的长度 require(_signature.length == 65, "invalid signature length"); bytes32 r; bytes32 s; uint8 v; // 目前只能用assembly (内联汇编)来从签名中获得r,s,v的值 assembly { /* 前32 bytes存储签名的长度 (动态数组存储规则) add(sig, 32) = sig的指针 + 32 等效为略过signature的前32 bytes mload(p) 载入从内存地址p起始的接下来32 bytes数据 */ // 读取长度数据后的32 bytes r := mload(add(_signature, 0x20)) // 读取之后的32 bytes s := mload(add(_signature, 0x40)) // 读取最后一个byte v := byte(0, mload(add(_signature, 0x60))) }
// 获取签名消息hash bytes32 digest = keccak256(abi.encodePacked( "\x19\x01", DOMAIN_SEPARATOR, keccak256(abi.encode(STORAGE_TYPEHASH, msg.sender, _num)) )); address signer = digest.recover(v, r, s); // 恢复签名者 require(signer == owner, "EIP712Storage: Invalid signature"); // 检查签名
// 修改状态变量 number = _num; }
/** * @dev Return value * @return value of 'number' */ function retrieve() public view returns (uint256){ return number; } }
|