Transaction Hash:
Block:
8718607 at Oct-11-2019 05:43:17 AM +UTC
Transaction Fee:
0.000040192 ETH
$0.08
Gas Used:
40,192 Gas / 1 Gwei
Emitted Events:
| 47 |
MCHDailyActionV3.Action( user=[Sender] 0x1c98fb27a9ddb4bec62ce95543f8a9e2bce9c2d8, at=1570772589 )
|
Account State Difference:
| Address | Before | After | State Difference | ||
|---|---|---|---|---|---|
| 0x1C98Fb27...2BCe9C2d8 |
0.011342227910806983 Eth
Nonce: 152
|
0.011302035910806983 Eth
Nonce: 153
| 0.000040192 | ||
| 0x5e07B6F1...F1c177753 | (MCH: Daily Action 3) | ||||
|
0xb2930B35...e543a0347
Miner
| (MiningPoolHub: Old Address) | 9,105.113801253645189536 Eth | 9,105.113841445645189536 Eth | 0.000040192 |
Execution Trace
MCHDailyActionV3.requestDailyActionReward( _signature=0xF7F9E9DFA245B82A346C890B6AB97866499C120681E075D53361E66DB8DBBFF41BD545D02399F9106C7D091DFA543570F2A9945DB7ED62282C7F8AD2DB24B5D501, _time=1570772589 )
-
Null: 0x000...001.42c7455c( )
requestDailyActionReward[MCHDailyActionV3 (ln:267)]
validateSig[MCHDailyActionV3 (ln:268)]recover[MCHDailyActionV3 (ln:280)]recover[MCHDailyActionV3 (ln:297)]ecrecover[ECDSA (ln:143)]
ethSignedMessageHash[MCHDailyActionV3 (ln:280)]toEthSignedMessageHash[MCHDailyActionV3 (ln:293)]
encodeData[MCHDailyActionV3 (ln:280)]
Action[MCHDailyActionV3 (ln:272)]
pragma solidity ^0.5.0;
// produced by the Solididy File Flattener (c) David Appleton 2018
// contact : dave@akomba.com
// 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);
}
}