ETH Price: $1,949.95 (-1.69%)

Transaction Decoder

Block:
15964447 at Nov-13-2022 11:39:11 PM +UTC
Transaction Fee:
0.000811830229728428 ETH $1.58
Gas Used:
54,454 Gas / 14.908550882 Gwei

Emitted Events:

398 MLAReward.Payout( to=[Sender] 0x24f94bca5b7c685248636d0004c93f2025f817fd, amount=84000000000000000 )

Account State Difference:

  Address   Before After State Difference Code
0x24F94BCA...025F817FD
0.094647483178489932 Eth
Nonce: 27
0.177835652948761504 Eth
Nonce: 28
0.083188169770271572
0x398fbeAD...8C10fFB8D 45.531 Eth45.447 Eth0.084
(beaverbuild)
95.007219022826409896 Eth95.007292174872929764 Eth0.000073152046519868

Execution Trace

MLAReward.payout( _amount=84000000000000000, _timestamp=1668382735, _signature=0x7CDCD2F55561415DE8859AE6F458785E4819EE02FB62EB2C094C0FA4579149127F696A4261EF91AD377C90B7F4306461B4DEC41119060E8B152F6C44B3CC31D11C )
  • Null: 0x000...001.34730c3b( )
  • ETH 0.084 0x24f94bca5b7c685248636d0004c93f2025f817fd.CALL( )
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.13;
    import "@openzeppelin/contracts/access/Ownable.sol";
    import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
    import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
    // @author: olive
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //                                                                                                          //
    //                                                                                                          //
    //    888b     d888 888             d8888      8888888b.                                             888    //
    //    8888b   d8888 888            d88888      888   Y88b                                            888    //
    //    88888b.d88888 888           d88P888      888    888                                            888    //
    //    888Y88888P888 888          d88P 888      888   d88P .d88b.  888  888  888  8888b.  888d888 .d88888    //
    //    888 Y888P 888 888         d88P  888      8888888P" d8P  Y8b 888  888  888     "88b 888P"  d88" 888    //
    //    888  Y8P  888 888        d88P   888      888 T88b  88888888 888  888  888 .d888888 888    888  888    //
    //    888   "   888 888       d8888888888      888  T88b Y8b.     Y88b 888 d88P 888  888 888    Y88b 888    //
    //    888       888 88888888 d88P     888      888   T88b "Y8888   "Y8888888P"  "Y888888 888     "Y88888    //
    //                                                                                                          //     
    //                                                                                                          //
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////
    contract MLAReward is Ownable, ReentrancyGuard {
        address private signerAddress;
        mapping(address => bool) internal admins;
        mapping(address => uint256) lastCheckPoint;
        uint256 public delayBetweenPayout = 20 * 24 * 60 * 60;
        mapping(address => uint256) payoutLimit;
        uint256 public defaultLimit = 5 ether;
        uint256 timeLimit = 90;
        address public constant topAdminAddress = 0xe4Fb4CC7d6A568231B139553636bfa2A6dBcDb46;
        event Deposited(uint256 amount);
        event Payout(address to, uint256 amount);
        constructor(address _signer) {
          admins[msg.sender] = true;
          signerAddress = _signer;
        }
        modifier onlyAdmin() {
            require(admins[_msgSender()], 'MLAReward: 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, "MLAReward: 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, "MLAReward: 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, bytes memory _signature) external nonReentrant {
          uint256 balance = address(this).balance;
          require(_amount <= balance, "MLAReward: Not enough balance");
          address wallet = _msgSender();
          address signerOwner = signatureWallet(wallet, _amount, _timestamp, _signature);
          require(signerOwner == signerAddress, "MLAReward: Invalid data provided");
          require(_timestamp >= block.timestamp - timeLimit, "MLAReward: Out of time");
          
          require(_timestamp >= lastCheckPoint[wallet] + delayBetweenPayout, "MLAReward: Invalid timestamp");
          require(_amount < getLimit(wallet), "MLAReward: Amount exceeds limit");
          lastCheckPoint[wallet] = block.timestamp;
          _widthdraw(wallet, _amount);
          emit Payout(wallet, _amount);
        }
        function signatureWallet(address _wallet, uint256 _amount, uint256 _timestamp, bytes memory _signature) public pure returns (address){
          return ECDSA.recover(keccak256(abi.encode(_wallet, _amount, _timestamp)), _signature);
        }
        function setCheckPoint(address _claimer, uint256 _point) public onlyOwner {
          require(_claimer != address(0), "MLAReward: 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;
        }
        function updateDefaultLimit(uint256 _limit) public onlyOwner {
          defaultLimit = _limit;
        }
    }// 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);
        }
    }