ETH Price: $2,484.00 (+0.64%)

Transaction Decoder

Block:
16448585 at Jan-20-2023 02:22:11 PM +UTC
Transaction Fee:
0.000961484033702094 ETH $2.39
Gas Used:
54,663 Gas / 17.589302338 Gwei

Emitted Events:

62 MBHReward.Payout( to=[Sender] 0xc4eb258c30ec7e19a28561a6bca2bd0e2ed3df3f, amount=113000000000000000 )

Account State Difference:

  Address   Before After State Difference Code
0xc4EB258c...e2ed3DF3f
2.380302997644563732 Eth
Nonce: 48
2.492341513610861638 Eth
Nonce: 49
0.112038515966297906
(Flashbots: Builder)
1.166240437696510889 Eth1.166372846598087638 Eth0.000132408901576749
0xE9663ae7...626A63B89 58.159 Eth58.046 Eth0.113

Execution Trace

MBHReward.payout( _amount=113000000000000000, _timestamp=1674224512, _oldCheckPoint=0, _signature=0xC003AE146BD9A01DF3EEE0DE1E4E5307D1B16BA4F01D5F611221BAB3E0A19D0556789F205577CB7097CDA69DE4DB974F31F785E9F2932E29B0E1055C8AEA85901B )
  • Null: 0x000...001.729e95df( )
  • ETH 0.113 0xc4eb258c30ec7e19a28561a6bca2bd0e2ed3df3f.CALL( )
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.7;
    import "@openzeppelin/contracts/access/Ownable.sol";
    import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
    import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
    // @author: olive
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //                                                                                                                //
    //                                                                                                                //
    //                                                                                                                //
    //     $$\\      $$\\ $$$$$$$\\  $$\\   $$\\       $$$$$$$\\                                                    $$\\     //
    //     $$$\\    $$$ |$$  __$$\\ $$ |  $$ |      $$  __$$\\                                                   $$ |    //
    //     $$$$\\  $$$$ |$$ |  $$ |$$ |  $$ |      $$ |  $$ | $$$$$$\\  $$\\  $$\\  $$\\  $$$$$$\\   $$$$$$\\   $$$$$$$ |    //
    //     $$\\$$\\$$ $$ |$$$$$$$\\ |$$$$$$$$ |      $$$$$$$  |$$  __$$\\ $$ | $$ | $$ | \\____$$\\ $$  __$$\\ $$  __$$ |    //
    //     $$ \\$$$  $$ |$$  __$$\\ $$  __$$ |      $$  __$$< $$$$$$$$ |$$ | $$ | $$ | $$$$$$$ |$$ |  \\__|$$ /  $$ |    //
    //     $$ |\\$  /$$ |$$ |  $$ |$$ |  $$ |      $$ |  $$ |$$   ____|$$ | $$ | $$ |$$  __$$ |$$ |      $$ |  $$ |    //
    //     $$ | \\_/ $$ |$$$$$$$  |$$ |  $$ |      $$ |  $$ |\\$$$$$$$\\ \\$$$$$\\$$$$  |\\$$$$$$$ |$$ |      \\$$$$$$$ |    //
    //     \\__|     \\__|\\_______/ \\__|  \\__|      \\__|  \\__| \\_______| \\_____\\____/  \\_______|\\__|       \\_______|    //
    //                                                                                                                //
    //                                                                                                                //
    //                                                                                                                //
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    contract MBHReward is Ownable, ReentrancyGuard {
        address private signerAddress;
        mapping(address => bool) internal admins;
        mapping(address => uint256) lastCheckPoint;
        uint256 public delayBetweenPayout = 5 * 24 * 60 * 60;
        mapping(address => uint256) payoutLimit;
        uint256 public defaultLimit = 5 ether;
        uint256 timeLimit = 90;
        address public constant topAdminAddress = 0x075Dc6D3a35eD0eaD2e10632161Dfc4E1bD59697;
        event Deposited(uint256 amount);
        event Payout(address to, uint256 amount);
        constructor(address _signer) {
          signerAddress = _signer;
        }
        modifier onlyAdmin() {
            require(admins[_msgSender()], 'Caller is not the admin');
            _;
        }
        function addAdminRole(address _address) external onlyOwner {
            admins[_address] = true;
        }
        function revokeAdminRole(address _address) external onlyOwner {
            admins[_address] = false;
        }
        function deposit() public payable onlyAdmin {
          require(msg.value > 0, "Not a valid amount");
          emit Deposited(msg.value);
        }
        function withdrawSome(uint256 _amount) public onlyAdmin {
          uint256 balance = address(this).balance;
          require(balance > 0 && _amount <= balance);
          _widthdraw(topAdminAddress, _amount);
        }
        function withdrawAll() public onlyAdmin {
          uint256 balance = address(this).balance;
          require(balance > 0);
          _widthdraw(topAdminAddress, address(this).balance);
        }
        function _widthdraw(address _address, uint256 _amount) private {
          (bool success, ) = _address.call{value: _amount}("");
          require(success, "Transfer failed.");
        }
        function getLimit(address _claimer) public view returns (uint256) {
          uint256 limit = payoutLimit[_claimer];
          if (limit == 0) { limit = defaultLimit; }
          return limit;
        }
        function setLimit(address[] memory _claimer, uint256[] memory _limit) public onlyOwner {
            for(uint i = 0; i < _claimer.length; i ++){
                payoutLimit[_claimer[i]] = _limit[i];
            }
        }
        function payout(uint256 _amount, uint256 _timestamp, uint256 _oldCheckPoint, bytes memory _signature) external nonReentrant {
          uint256 balance = address(this).balance;
          require(_amount <= balance, "Not enough balance");
          address wallet = _msgSender();
          address signerOwner = signatureWallet(wallet, _amount, _timestamp, _oldCheckPoint, _signature);
          require(signerOwner == signerAddress, "Invalid data provided");
          require(_timestamp >= block.timestamp - timeLimit, "Out of time");
          
          uint256 checkPoint = lastCheckPoint[wallet];
          if(_oldCheckPoint > checkPoint) checkPoint = _oldCheckPoint;
          require(_timestamp >= checkPoint + delayBetweenPayout, "Invalid timestamp");
          require(_amount < getLimit(wallet), "Amount exceeds limit");
          lastCheckPoint[wallet] = block.timestamp;
          _widthdraw(wallet, _amount);
          emit Payout(wallet, _amount);
        }
        function signatureWallet(address _wallet, uint256 _amount, uint256 _timestamp, uint256 _oldCheckPoint, bytes memory _signature) public pure returns (address){
          return ECDSA.recover(keccak256(abi.encode(_wallet, _amount, _timestamp, _oldCheckPoint)), _signature);
        }
        function setCheckPoint(address _claimer, uint256 _point) public onlyOwner {
          require(_claimer != address(0), "Unknown address");
          lastCheckPoint[_claimer] = _point;
        }
        function getCheckPoint(address _claimer) external view returns (uint256) {
          return lastCheckPoint[_claimer];
        }
        function updateSignerAddress(address _signer) public onlyOwner {
          signerAddress = _signer;
        }
        function updateTimeLimit(uint256 _timeLimit) public onlyOwner {
          timeLimit = _timeLimit;
        }
    }// SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    /**
     * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
     *
     * These functions can be used to verify that a message was signed by the holder
     * of the private keys of a given address.
     */
    library ECDSA {
        enum RecoverError {
            NoError,
            InvalidSignature,
            InvalidSignatureLength,
            InvalidSignatureS,
            InvalidSignatureV
        }
        function _throwError(RecoverError error) private pure {
            if (error == RecoverError.NoError) {
                return; // no error: do nothing
            } else if (error == RecoverError.InvalidSignature) {
                revert("ECDSA: invalid signature");
            } else if (error == RecoverError.InvalidSignatureLength) {
                revert("ECDSA: invalid signature length");
            } else if (error == RecoverError.InvalidSignatureS) {
                revert("ECDSA: invalid signature 's' value");
            } else if (error == RecoverError.InvalidSignatureV) {
                revert("ECDSA: invalid signature 'v' value");
            }
        }
        /**
         * @dev Returns the address that signed a hashed message (`hash`) with
         * `signature` or error string. This address can then be used for verification purposes.
         *
         * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
         * this function rejects them by requiring the `s` value to be in the lower
         * half order, and the `v` value to be either 27 or 28.
         *
         * IMPORTANT: `hash` _must_ be the result of a hash operation for the
         * verification to be secure: it is possible to craft signatures that
         * recover to arbitrary addresses for non-hashed data. A safe way to ensure
         * this is by receiving a hash of the original message (which may otherwise
         * be too long), and then calling {toEthSignedMessageHash} on it.
         *
         * Documentation for signature generation:
         * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
         * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
         *
         * _Available since v4.3._
         */
        function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
            // Check the signature length
            // - case 65: r,s,v signature (standard)
            // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._
            if (signature.length == 65) {
                bytes32 r;
                bytes32 s;
                uint8 v;
                // ecrecover takes the signature parameters, and the only way to get them
                // currently is to use assembly.
                assembly {
                    r := mload(add(signature, 0x20))
                    s := mload(add(signature, 0x40))
                    v := byte(0, mload(add(signature, 0x60)))
                }
                return tryRecover(hash, v, r, s);
            } else if (signature.length == 64) {
                bytes32 r;
                bytes32 vs;
                // ecrecover takes the signature parameters, and the only way to get them
                // currently is to use assembly.
                assembly {
                    r := mload(add(signature, 0x20))
                    vs := mload(add(signature, 0x40))
                }
                return tryRecover(hash, r, vs);
            } else {
                return (address(0), RecoverError.InvalidSignatureLength);
            }
        }
        /**
         * @dev Returns the address that signed a hashed message (`hash`) with
         * `signature`. This address can then be used for verification purposes.
         *
         * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
         * this function rejects them by requiring the `s` value to be in the lower
         * half order, and the `v` value to be either 27 or 28.
         *
         * IMPORTANT: `hash` _must_ be the result of a hash operation for the
         * verification to be secure: it is possible to craft signatures that
         * recover to arbitrary addresses for non-hashed data. A safe way to ensure
         * this is by receiving a hash of the original message (which may otherwise
         * be too long), and then calling {toEthSignedMessageHash} on it.
         */
        function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
            (address recovered, RecoverError error) = tryRecover(hash, signature);
            _throwError(error);
            return recovered;
        }
        /**
         * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
         *
         * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
         *
         * _Available since v4.3._
         */
        function tryRecover(
            bytes32 hash,
            bytes32 r,
            bytes32 vs
        ) internal pure returns (address, RecoverError) {
            bytes32 s;
            uint8 v;
            assembly {
                s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
                v := add(shr(255, vs), 27)
            }
            return tryRecover(hash, v, r, s);
        }
        /**
         * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
         *
         * _Available since v4.2._
         */
        function recover(
            bytes32 hash,
            bytes32 r,
            bytes32 vs
        ) internal pure returns (address) {
            (address recovered, RecoverError error) = tryRecover(hash, r, vs);
            _throwError(error);
            return recovered;
        }
        /**
         * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
         * `r` and `s` signature fields separately.
         *
         * _Available since v4.3._
         */
        function tryRecover(
            bytes32 hash,
            uint8 v,
            bytes32 r,
            bytes32 s
        ) internal pure returns (address, RecoverError) {
            // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
            // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
            // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
            // signatures from current libraries generate a unique signature with an s-value in the lower half order.
            //
            // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
            // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
            // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
            // these malleable signatures as well.
            if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
                return (address(0), RecoverError.InvalidSignatureS);
            }
            if (v != 27 && v != 28) {
                return (address(0), RecoverError.InvalidSignatureV);
            }
            // If the signature is valid (and not malleable), return the signer address
            address signer = ecrecover(hash, v, r, s);
            if (signer == address(0)) {
                return (address(0), RecoverError.InvalidSignature);
            }
            return (signer, RecoverError.NoError);
        }
        /**
         * @dev Overload of {ECDSA-recover} that receives the `v`,
         * `r` and `s` signature fields separately.
         */
        function recover(
            bytes32 hash,
            uint8 v,
            bytes32 r,
            bytes32 s
        ) internal pure returns (address) {
            (address recovered, RecoverError error) = tryRecover(hash, v, r, s);
            _throwError(error);
            return recovered;
        }
        /**
         * @dev Returns an Ethereum Signed Message, created from a `hash`. This
         * produces hash corresponding to the one signed with the
         * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
         * JSON-RPC method as part of EIP-191.
         *
         * See {recover}.
         */
        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:\
    32", hash));
        }
        /**
         * @dev Returns an Ethereum Signed Typed Data, created from a
         * `domainSeparator` and a `structHash`. This produces hash corresponding
         * to the one signed with the
         * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
         * JSON-RPC method as part of EIP-712.
         *
         * See {recover}.
         */
        function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
            return keccak256(abi.encodePacked("\\x19\\x01", domainSeparator, structHash));
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    /**
     * @dev Provides information about the current execution context, including the
     * sender of the transaction and its data. While these are generally available
     * via msg.sender and msg.data, they should not be accessed in such a direct
     * manner, since when dealing with meta-transactions the account sending and
     * paying for execution may not be the actual sender (as far as an application
     * is concerned).
     *
     * This contract is only required for intermediate, library-like contracts.
     */
    abstract contract Context {
        function _msgSender() internal view virtual returns (address) {
            return msg.sender;
        }
        function _msgData() internal view virtual returns (bytes calldata) {
            return msg.data;
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    /**
     * @dev Contract module that helps prevent reentrant calls to a function.
     *
     * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
     * available, which can be applied to functions to make sure there are no nested
     * (reentrant) calls to them.
     *
     * Note that because there is a single `nonReentrant` guard, functions marked as
     * `nonReentrant` may not call one another. This can be worked around by making
     * those functions `private`, and then adding `external` `nonReentrant` entry
     * points to them.
     *
     * TIP: If you would like to learn more about reentrancy and alternative ways
     * to protect against it, check out our blog post
     * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
     */
    abstract contract ReentrancyGuard {
        // Booleans are more expensive than uint256 or any type that takes up a full
        // word because each write operation emits an extra SLOAD to first read the
        // slot's contents, replace the bits taken up by the boolean, and then write
        // back. This is the compiler's defense against contract upgrades and
        // pointer aliasing, and it cannot be disabled.
        // The values being non-zero value makes deployment a bit more expensive,
        // but in exchange the refund on every call to nonReentrant will be lower in
        // amount. Since refunds are capped to a percentage of the total
        // transaction's gas, it is best to keep them low in cases like this one, to
        // increase the likelihood of the full refund coming into effect.
        uint256 private constant _NOT_ENTERED = 1;
        uint256 private constant _ENTERED = 2;
        uint256 private _status;
        constructor() {
            _status = _NOT_ENTERED;
        }
        /**
         * @dev Prevents a contract from calling itself, directly or indirectly.
         * Calling a `nonReentrant` function from another `nonReentrant`
         * function is not supported. It is possible to prevent this from happening
         * by making the `nonReentrant` function external, and make it call a
         * `private` function that does the actual work.
         */
        modifier nonReentrant() {
            // On the first call to nonReentrant, _notEntered will be true
            require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
            // Any calls to nonReentrant after this point will fail
            _status = _ENTERED;
            _;
            // By storing the original value once again, a refund is triggered (see
            // https://eips.ethereum.org/EIPS/eip-2200)
            _status = _NOT_ENTERED;
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    import "../utils/Context.sol";
    /**
     * @dev Contract module which provides a basic access control mechanism, where
     * there is an account (an owner) that can be granted exclusive access to
     * specific functions.
     *
     * By default, the owner account will be the one that deploys the contract. This
     * can later be changed with {transferOwnership}.
     *
     * This module is used through inheritance. It will make available the modifier
     * `onlyOwner`, which can be applied to your functions to restrict their use to
     * the owner.
     */
    abstract contract Ownable is Context {
        address private _owner;
        event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
        /**
         * @dev Initializes the contract setting the deployer as the initial owner.
         */
        constructor() {
            _setOwner(_msgSender());
        }
        /**
         * @dev Returns the address of the current owner.
         */
        function owner() public view virtual returns (address) {
            return _owner;
        }
        /**
         * @dev Throws if called by any account other than the owner.
         */
        modifier onlyOwner() {
            require(owner() == _msgSender(), "Ownable: caller is not the owner");
            _;
        }
        /**
         * @dev Leaves the contract without owner. It will not be possible to call
         * `onlyOwner` functions anymore. Can only be called by the current owner.
         *
         * NOTE: Renouncing ownership will leave the contract without an owner,
         * thereby removing any functionality that is only available to the owner.
         */
        function renounceOwnership() public virtual onlyOwner {
            _setOwner(address(0));
        }
        /**
         * @dev Transfers ownership of the contract to a new account (`newOwner`).
         * Can only be called by the current owner.
         */
        function transferOwnership(address newOwner) public virtual onlyOwner {
            require(newOwner != address(0), "Ownable: new owner is the zero address");
            _setOwner(newOwner);
        }
        function _setOwner(address newOwner) private {
            address oldOwner = _owner;
            _owner = newOwner;
            emit OwnershipTransferred(oldOwner, newOwner);
        }
    }