pragma experimental ABIEncoderV2; pragma solidity ^0.5.0; contract Verifier { mapping (address => uint) public smiles; mapping (address => uint) public nods; function nod(address nodder, uint nodNum, uint nodMultiplier) public { nods[nodder] = nods[nodder]*nodMultiplier + nodNum; } function smile(address smiler, uint256 smileNum) public { smiles[smiler] += smileNum; } // ---------- For Meta Tx --------- // string private constant SMILE_METHOD_SIG = 'smile(address,uint256)'; bytes4 private constant SMILE_METHOD_IDENTIFIER = bytes4(keccak256(bytes(SMILE_METHOD_SIG))); string private constant SMILE_TYPE = "Packet(string method_name,address smiler,uint256 smile_num,bytes4 method_identifier,bytes params_packed)"; bytes32 private constant SMILE_TYPEHASH = keccak256(abi.encodePacked(SMILE_TYPE)); string public constant NOD_METHOD_SIG = 'nod(address,uint256,uint256)'; bytes4 public constant NOD_METHOD_IDENTIFIER = bytes4(keccak256(bytes(NOD_METHOD_SIG))); string private constant NOD_TYPE = "Packet(string method_name,address nodder,uint256 nod_num,uint256 nod_mult,bytes4 method_identifier,bytes params_packed)"; bytes32 private constant NOD_TYPEHASH = keccak256(abi.encodePacked(NOD_TYPE)); bytes32 constant SALT = 0xf2d857f4a3edcb9b78b4d503bfe733db1e3f6cdc2b7971ee739626c97e86a558; // Finally method to identify Dapp string private constant EIP712_DOMAIN = "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract,bytes32 salt)"; bytes32 private constant EIP712_DOMAIN_TYPEHASH = keccak256(abi.encodePacked(EIP712_DOMAIN)); bytes32 private DOMAIN_SEPARATOR = keccak256(abi.encode( EIP712_DOMAIN_TYPEHASH, keccak256("EIP712Dapp"), // Dapp name keccak256("1"), // Contract version 3, // Network id address(this), // verifying contract address SALT )); function verifyMeta(address signer, bytes4 method, bytes memory params, bytes32 r, bytes32 s, uint8 v) public returns (bool) { require((method == SMILE_METHOD_IDENTIFIER) || (method == NOD_METHOD_IDENTIFIER)); if (method == SMILE_METHOD_IDENTIFIER) { (address addr, uint256 x) = abi.decode(params, (address, uint256)); bytes32 digest = keccak256(abi.encodePacked( "\x19\x01", DOMAIN_SEPARATOR, keccak256(abi.encode( SMILE_TYPEHASH, keccak256(bytes(SMILE_METHOD_SIG)), // * EIP712: strings are encoded as its hash; bytes() works but abi.encodePacked doesn't addr, x, method, keccak256(params) // * EIP712: bytes are encoded as its hash )) )); require(signer == ecrecover(digest, v, r, s)); // TODO: 驗證 nonce,但是注意 metamask 在 Gitcoin 上說: // "This method may make use of a nonce, but for some use cases, // allowing these messages to be submitted in any order may be an advantage, // and so another replay-protection measure may be preferable." smile(addr, x); } else if (method == NOD_METHOD_IDENTIFIER) { (address addr, uint256 x, uint256 m) = abi.decode(params, (address, uint256, uint256)); bytes32 digest = keccak256(abi.encodePacked( "\x19\x01", DOMAIN_SEPARATOR, keccak256(abi.encode( NOD_TYPEHASH, keccak256(bytes(NOD_METHOD_SIG)), // * EIP712: strings are encoded as its hash; bytes() works but abi.encodePacked doesn't addr, x, m, method, keccak256(params) // * EIP712: bytes are encoded as its hash )) )); require(signer == ecrecover(digest, v, r, s)); // TODO: 驗證 nonce,但是注意 metamask 在 Gitcoin 上說: // "This method may make use of a nonce, but for some use cases, // allowing these messages to be submitted in any order may be an advantage, // and so another replay-protection measure may be preferable." nod(addr, x, m); } return true; } }
0.4.18