ETH Price: $1,906.72 (-0.85%)

Transaction Decoder

Block:
9863112 at Apr-13-2020 09:11:24 AM +UTC
Transaction Fee:
0.0000918684 ETH $0.18
Gas Used:
39,260 Gas / 2.34 Gwei

Emitted Events:

Account State Difference:

  Address   Before After State Difference Code
(Spark Pool)
23.140264901815832336 Eth23.140356770215832336 Eth0.0000918684
0x5e07B6F1...F1c177753
(MCH: Daily Action 3)
0xd6FacaC5...d1EB1D1a4
0.019804725952305628 Eth
Nonce: 338
0.019712857552305628 Eth
Nonce: 339
0.0000918684

Execution Trace

MCHDailyActionV3.requestDailyActionReward( _signature=0x7B831546D54D212C2CFBF0CAB358A90C9790BA02B845772055271BA98FE37F330610AA0D07DC0E0B5E7268B94498796B90EFF97A1172C1CF4C6181C58AE495A100, _time=1586768440 )
  • Null: 0x000...001.69fde7aa( )
    pragma solidity ^0.5.0;
    // produced by the Solididy File Flattener (c) David Appleton 2018
    // contact : [email protected]
    // released under Apache 2.0 licence
    // input  /Users/rmanzoku/src/github.com/doublejumptokyo/mch-dailyaction/contracts/MCHDailyActionV3.sol
    // flattened :  Monday, 30-Sep-19 08:38:23 UTC
    contract Ownable {
        address private _owner;
    
        event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    
        /**
         * @dev The Ownable constructor sets the original `owner` of the contract to the sender
         * account.
         */
        constructor () internal {
            _owner = msg.sender;
            emit OwnershipTransferred(address(0), _owner);
        }
    
        /**
         * @return the address of the owner.
         */
        function owner() public view returns (address) {
            return _owner;
        }
    
        /**
         * @dev Throws if called by any account other than the owner.
         */
        modifier onlyOwner() {
            require(isOwner());
            _;
        }
    
        /**
         * @return true if `msg.sender` is the owner of the contract.
         */
        function isOwner() public view returns (bool) {
            return msg.sender == _owner;
        }
    
        /**
         * @dev Allows the current owner to relinquish control of the contract.
         * @notice Renouncing to ownership will leave the contract without an owner.
         * It will not be possible to call the functions with the `onlyOwner`
         * modifier anymore.
         */
        function renounceOwnership() public onlyOwner {
            emit OwnershipTransferred(_owner, address(0));
            _owner = address(0);
        }
    
        /**
         * @dev Allows the current owner to transfer control of the contract to a newOwner.
         * @param newOwner The address to transfer ownership to.
         */
        function transferOwnership(address newOwner) public onlyOwner {
            _transferOwnership(newOwner);
        }
    
        /**
         * @dev Transfers control of the contract to a newOwner.
         * @param newOwner The address to transfer ownership to.
         */
        function _transferOwnership(address newOwner) internal {
            require(newOwner != address(0));
            emit OwnershipTransferred(_owner, newOwner);
            _owner = newOwner;
        }
    }
    
    library Roles {
        struct Role {
            mapping (address => bool) bearer;
        }
    
        /**
         * @dev give an account access to this role
         */
        function add(Role storage role, address account) internal {
            require(account != address(0));
            require(!has(role, account));
    
            role.bearer[account] = true;
        }
    
        /**
         * @dev remove an account's access to this role
         */
        function remove(Role storage role, address account) internal {
            require(account != address(0));
            require(has(role, account));
    
            role.bearer[account] = false;
        }
    
        /**
         * @dev check if an account has this role
         * @return bool
         */
        function has(Role storage role, address account) internal view returns (bool) {
            require(account != address(0));
            return role.bearer[account];
        }
    }
    
    library ECDSA {
        /**
         * @dev Recover signer address from a message by using their signature
         * @param hash bytes32 message, the hash is the signed message. What is recovered is the signer address.
         * @param signature bytes signature, the signature is generated using web3.eth.sign()
         */
        function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
            bytes32 r;
            bytes32 s;
            uint8 v;
    
            // Check the signature length
            if (signature.length != 65) {
                return (address(0));
            }
    
            // Divide the signature in r, s and v variables
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            // solhint-disable-next-line no-inline-assembly
            assembly {
                r := mload(add(signature, 0x20))
                s := mload(add(signature, 0x40))
                v := byte(0, mload(add(signature, 0x60)))
            }
    
            // Version of signature should be 27 or 28, but 0 and 1 are also possible versions
            if (v < 27) {
                v += 27;
            }
    
            // If the version is correct return the signer address
            if (v != 27 && v != 28) {
                return (address(0));
            } else {
                return ecrecover(hash, v, r, s);
            }
        }
    
        /**
         * toEthSignedMessageHash
         * @dev prefix a bytes32 value with "\x19Ethereum Signed Message:"
         * and hash the result
         */
        function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
            // 32 is the length in bytes of hash,
            // enforced by the type signature above
            return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
        }
    }
    
    contract PauserRole {
        using Roles for Roles.Role;
    
        event PauserAdded(address indexed account);
        event PauserRemoved(address indexed account);
    
        Roles.Role private _pausers;
    
        constructor () internal {
            _addPauser(msg.sender);
        }
    
        modifier onlyPauser() {
            require(isPauser(msg.sender));
            _;
        }
    
        function isPauser(address account) public view returns (bool) {
            return _pausers.has(account);
        }
    
        function addPauser(address account) public onlyPauser {
            _addPauser(account);
        }
    
        function renouncePauser() public {
            _removePauser(msg.sender);
        }
    
        function _addPauser(address account) internal {
            _pausers.add(account);
            emit PauserAdded(account);
        }
    
        function _removePauser(address account) internal {
            _pausers.remove(account);
            emit PauserRemoved(account);
        }
    }
    
    contract Pausable is PauserRole {
        event Paused(address account);
        event Unpaused(address account);
    
        bool private _paused;
    
        constructor () internal {
            _paused = false;
        }
    
        /**
         * @return true if the contract is paused, false otherwise.
         */
        function paused() public view returns (bool) {
            return _paused;
        }
    
        /**
         * @dev Modifier to make a function callable only when the contract is not paused.
         */
        modifier whenNotPaused() {
            require(!_paused);
            _;
        }
    
        /**
         * @dev Modifier to make a function callable only when the contract is paused.
         */
        modifier whenPaused() {
            require(_paused);
            _;
        }
    
        /**
         * @dev called by the owner to pause, triggers stopped state
         */
        function pause() public onlyPauser whenNotPaused {
            _paused = true;
            emit Paused(msg.sender);
        }
    
        /**
         * @dev called by the owner to unpause, returns to normal state
         */
        function unpause() public onlyPauser whenPaused {
            _paused = false;
            emit Unpaused(msg.sender);
        }
    }
    
    contract MCHDailyActionV3 is Ownable, Pausable {
    
      address public validator;
      mapping(address => int64) public lastActionDate;
    
      event Action(
                   address indexed user,
                   int64 at
                   );
    
      constructor(address _varidator) public {
        validator = _varidator;
      }
    
      function setValidater(address _varidator) external onlyOwner() {
        validator = _varidator;
      }
    
      function requestDailyActionReward(bytes calldata _signature, int64 _time) external whenNotPaused() {
        require(validateSig(msg.sender, _time, _signature), "invalid signature");
        int64 day = _time / 86400;
        require(lastActionDate[msg.sender] < day);
        lastActionDate[msg.sender] = day;
        emit Action(
                    msg.sender,
                    _time
                    );
      }
    
      function validateSig(address _from, int64 _time, bytes memory _signature) public view returns (bool) {
        require(validator != address(0));
        address signer = recover(ethSignedMessageHash(encodeData(_from, _time)), _signature);
        return (signer == validator);
      }
    
      function encodeData(address _from, int64 _time) public pure returns (bytes32) {
        return keccak256(abi.encode(
                                    _from,
                                    _time
                                    )
                         );
      }
    
      function ethSignedMessageHash(bytes32 _data) public pure returns (bytes32) {
        return ECDSA.toEthSignedMessageHash(_data);
      }
    
      function recover(bytes32 _data, bytes memory _signature) public pure returns (address) {
        return ECDSA.recover(_data, _signature);
      }
    }