eth-offline

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

OfflineBase.sol (3187B)


      1 pragma solidity ^0.8.0;
      2 
      3 // SPDX-License-Identifier: AGPL-3.0-or-later
      4 // Some methods are copied under other licenses, please see code comments for details
      5 
      6 abstract contract Offline {
      7 	function executeOfflineRequest(bytes memory _data, bytes memory _signature, uint8 _version) public virtual returns(uint256);
      8 
      9 	function isOfflineValid(address _validator, bytes memory _data) external virtual view returns(bool);
     10 
     11 	function verifyOfflineRequest(bytes memory _data, bytes memory _signature, bytes32 _domainSeparator, bytes32 _typeHash) public view returns(bool) {
     12 		bytes memory message;
     13 		bytes32 messageDigest;
     14 		bytes memory dataDigest;
     15 		address _owner;
     16 
     17 		dataDigest = new bytes(32 + _data.length);
     18 		for (uint256 i = 0; i < 32; i++) {
     19 			dataDigest[i] = _typeHash[i];
     20 		}
     21 		for (uint256 i = 0; i < _data.length; i++) {
     22 			dataDigest[i+32] = _data[i];
     23 		}
     24 		messageDigest = keccak256(dataDigest);
     25 
     26 		message = new bytes(2 + 32 + 32);
     27 		message[0] = 0x19;
     28 		message[1] = 0x01;
     29 		for (uint256 i = 0; i < 32; i++) {
     30 			message[i+2] = _domainSeparator[i];
     31 		}
     32 		for (uint256 i = 0; i < 32; i++) {
     33 			message[i+34] = messageDigest[i];
     34 		}
     35 
     36 		messageDigest = keccak256(message);
     37 		_owner = recoverSigner(messageDigest, _signature);
     38 
     39 		return this.isOfflineValid(_owner, _data);
     40 	}
     41 
     42 	function verifyOfflineRequest(bytes memory _data, bytes memory _signature) public view returns(bool) {
     43 		bytes memory message;
     44 		bytes32 messageDigest;
     45 		address _owner;
     46 		
     47 		message = toValidatorMessage(_data); 
     48 		messageDigest = keccak256(message);
     49 		_owner = recoverSigner(messageDigest, _signature);
     50 
     51 		return this.isOfflineValid(_owner, _data);
     52 	}
     53 
     54 	function toValidatorMessage(bytes memory _data) private view returns(bytes memory) {
     55 		bytes memory message;
     56 		uint256 c;
     57 		bytes20 contractBytes;
     58 
     59 		message = new bytes(22 + _data.length);
     60 		message[0] = 0x19;
     61 
     62 		c = 2;
     63 		contractBytes = bytes20(address(this));
     64 		for (uint256 i = 0; i < 20; i++) {
     65 			message[i+c] = contractBytes[i];
     66 		}
     67 		
     68 		c += 20;
     69 		for (uint256 i = 0; i < _data.length; i++) {
     70 			message[i+c] = _data[i];
     71 		}
     72 		return message;
     73 	}
     74 
     75 	// from https://solidity-by-example.org/signature/
     76 	// Published under MIT license
     77 	function recoverSigner(bytes32 _ethSignedMessageHash, bytes memory _signature) private pure returns (address) {
     78 		(bytes32 r, bytes32 s, uint8 v) = splitSignature(_signature);
     79 		return ecrecover(_ethSignedMessageHash, v, r, s);
     80 	}
     81 
     82 	// from https://solidity-by-example.org/signature/
     83 	// Published under MIT license
     84 	function splitSignature(bytes memory sig) private pure returns (bytes32 r, bytes32 s, uint8 v) {
     85 		require(sig.length == 65, "invalid signature length");
     86 
     87 		assembly {
     88 		    /*
     89 		    First 32 bytes stores the length of the signature
     90 
     91 		    add(sig, 32) = pointer of sig + 32
     92 		    effectively, skips first 32 bytes of signature
     93 
     94 		    mload(p) loads next 32 bytes starting at the memory address p into memory
     95 		    */
     96 
     97 		    // first 32 bytes, after the length prefix
     98 		    r := mload(add(sig, 32))
     99 		    // second 32 bytes
    100 		    s := mload(add(sig, 64))
    101 		    // final byte (first byte of the next 32 bytes)
    102 		    v := byte(0, mload(add(sig, 96)))
    103 		}
    104 
    105 		// implicitly return (r, s, v)
    106 	}
    107 }