eth-offline

EVM token minter frontend for offline issuance using ERC712 structured signatures.
Info | Log | Files | Refs

Offline.sol (3107B)


      1 pragma solidity ^0.8.0;
      2 
      3 // SPDX-License-Identifier: AGPL-3.0-or-later
      4 
      5 import './OfflineBase.sol';
      6 
      7 contract OfflineRubber is Offline {
      8 
      9 	struct Instruction {
     10 		bytes32 domain;
     11 		uint256 value;
     12 		address beneficiary;
     13 	}
     14 
     15 	address public contractOwner;
     16 	uint256 public executedTimes;
     17 
     18 	bytes32 public eip712DomainSeparator;
     19 	bytes32 constant public eip712TypeHash = keccak256("Instruction(bytes32 domain,uint256 value,address beneficiary)");
     20 
     21 	struct EIP712Domain {
     22 		string  name;
     23 		string  version;
     24 		uint256 chainId;
     25 		address verifyingContract;
     26 		bytes32 salt;
     27 	}
     28 
     29 	bytes32 constant eip712DomainTypehash = keccak256(
     30 		"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract,bytes32 salt)"
     31 	);
     32 
     33 	function hash(EIP712Domain memory eip712Domain) internal pure returns (bytes32) {
     34 		return keccak256(abi.encode(
     35 			eip712DomainTypehash,
     36 			keccak256(bytes(eip712Domain.name)),
     37 			keccak256(bytes(eip712Domain.version)),
     38 			eip712Domain.chainId,
     39 			eip712Domain.verifyingContract,
     40 			eip712Domain.salt
     41 		));
     42 	}
     43 
     44 	constructor(uint256 chainId) {
     45 		contractOwner = msg.sender;
     46 		eip712DomainSeparator = hash(EIP712Domain({
     47 		    name: "Offline signing test",
     48 		    version: '0',
     49 		    chainId: chainId,
     50 		    verifyingContract: address(this),
     51 		    //salt: blockhash(block.number)
     52 		    salt: bytes32(0x00)
     53 		}));
     54 	}
     55 
     56 	function toBytes(Instruction memory _instruction) public pure returns(bytes memory) {
     57 		return abi.encode(_instruction);
     58 	}
     59 
     60 	function executeOfflineRequest(bytes memory _data, bytes memory _signature, uint8 _version) public override returns(uint256) {
     61 		if (_version == 0) {
     62 			require(verifyOfflineRequest(_data, _signature), 'ERR_UNVERIFIED');
     63 		} else if (_version == 1) {
     64 			require(verifyOfflineRequest(_data, _signature, eip712DomainSeparator, eip712TypeHash), 'ERR_UNVERIFIED');
     65 		} else {
     66 			revert('UNKNOWN VERSION');	
     67 		}
     68 		executedTimes++;
     69 		return 0;
     70 	}
     71 
     72 	function isOfflineValid(address _signer, bytes memory _data) external override view returns(bool) {
     73 		if (_signer == address(0)) {
     74 			return false;
     75 		}
     76 		if (uint96(bytes12(_data)) == 0) {
     77 			return false;
     78 		}
     79 		if (_data.length != 96) {
     80 			return false;
     81 		}
     82 		return contractOwner == _signer;
     83 	}
     84 
     85 //	function splitData(bytes memory _data) private pure returns(Instruction memory instruction) {
     86 //		bytes memory nonce;
     87 //		bytes memory beneficiary;
     88 //		bytes memory domain;
     89 //		bytes memory value;
     90 //
     91 //		if(_data.length != 84) {
     92 //			return instruction;
     93 //		}
     94 //
     95 //		nonce = new bytes(12);
     96 //		beneficiary = new bytes(20);
     97 //		value = new bytes(32);
     98 //		domain = new bytes(32);
     99 //
    100 //		for (uint256 i; i < nonce.length; i++) {
    101 //			nonce[i] = _data[i];
    102 //		}
    103 //		for (uint256 i; i < beneficiary.length; i++) {
    104 //			beneficiary[i] = _data[i+12];
    105 //		}
    106 //		for (uint256 i; i < 32; i++) {
    107 //			domain[i] = _data[i + 32];
    108 //		}
    109 //		for (uint256 i; i < 32; i++) {
    110 //			value[i] = _data[i + 64];
    111 //		}
    112 //		instruction.nonce = bytes12(nonce);
    113 //		instruction.beneficiary = address(bytes20(beneficiary));
    114 //		instruction.domain = bytes32(domain);
    115 //		instruction.value = uint256(bytes32(value));
    116 //	}
    117 }