ETH Price: $3,085.13 (-1.55%)
Gas: 3 Gwei

Contract

0x88dA47FC43572BCDD781F2d7883aEC314AA17E5c
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Value
Withdraw Reward197959942024-05-04 9:57:472 days ago1714816667IN
0x88dA47FC...14AA17E5c
0 ETH0.000387535.19629845
Unstake197332222024-04-25 15:17:3511 days ago1714058255IN
0x88dA47FC...14AA17E5c
0 ETH0.0022153730.24984919
Withdraw Reward197332172024-04-25 15:16:3511 days ago1714058195IN
0x88dA47FC...14AA17E5c
0 ETH0.0019132431.41623539
Unstake196611122024-04-15 13:09:1121 days ago1713186551IN
0x88dA47FC...14AA17E5c
0 ETH0.0013569918.52901736
Withdraw Reward196611062024-04-15 13:07:5921 days ago1713186479IN
0x88dA47FC...14AA17E5c
0 ETH0.0011167318.33725711
Withdraw Reward196319152024-04-11 10:54:3525 days ago1712832875IN
0x88dA47FC...14AA17E5c
0 ETH0.0011181614.99276689
Stake196302452024-04-11 5:17:2325 days ago1712812643IN
0x88dA47FC...14AA17E5c
0 ETH0.0015255612.03370724
Deposit196264062024-04-10 16:25:3526 days ago1712766335IN
0x88dA47FC...14AA17E5c
0 ETH0.0010677624.47482558
Withdraw Reward196206252024-04-09 21:00:3527 days ago1712696435IN
0x88dA47FC...14AA17E5c
0 ETH0.0016472822.08754269
Unstake195958812024-04-06 9:46:3530 days ago1712396795IN
0x88dA47FC...14AA17E5c
0 ETH0.000866511.83171768
Withdraw Reward195958782024-04-06 9:45:5930 days ago1712396759IN
0x88dA47FC...14AA17E5c
0 ETH0.000936812.56108025
Unstake195622882024-04-01 16:52:4735 days ago1711990367IN
0x88dA47FC...14AA17E5c
0 ETH0.0022941731.32583742
Withdraw Reward195622852024-04-01 16:52:1135 days ago1711990331IN
0x88dA47FC...14AA17E5c
0 ETH0.0022660530.38423413
Stake195523562024-03-31 7:20:2336 days ago1711869623IN
0x88dA47FC...14AA17E5c
0 ETH0.0013591418.49223932
Stake195156462024-03-26 2:28:3542 days ago1711420115IN
0x88dA47FC...14AA17E5c
0 ETH0.0022852118.02588939
Unstake195102352024-03-25 8:12:2342 days ago1711354343IN
0x88dA47FC...14AA17E5c
0 ETH0.0009698317.27654371
Withdraw Reward195102312024-03-25 8:11:3542 days ago1711354295IN
0x88dA47FC...14AA17E5c
0 ETH0.0010881415.8795889
Stake194404552024-03-15 12:49:4752 days ago1710506987IN
0x88dA47FC...14AA17E5c
0 ETH0.0044515836.4890128
Unstake194268272024-03-13 14:44:2354 days ago1710341063IN
0x88dA47FC...14AA17E5c
0 ETH0.0036225164.53102533
Withdraw Reward194268222024-03-13 14:43:1154 days ago1710340991IN
0x88dA47FC...14AA17E5c
0 ETH0.0038609863.39868776
Stake194246552024-03-13 7:26:5954 days ago1710314819IN
0x88dA47FC...14AA17E5c
0 ETH0.005736745.25145011
Stake194201892024-03-12 16:27:4755 days ago1710260867IN
0x88dA47FC...14AA17E5c
0 ETH0.0091008374.60557171
Stake194153832024-03-12 0:19:4756 days ago1710202787IN
0x88dA47FC...14AA17E5c
0 ETH0.0052233953.64924498
Unstake193996522024-03-09 19:32:5958 days ago1710012779IN
0x88dA47FC...14AA17E5c
0 ETH0.0053767373.41659706
Withdraw Reward193996492024-03-09 19:32:2358 days ago1710012743IN
0x88dA47FC...14AA17E5c
0 ETH0.005263570.57531291
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Vault

Compiler Version
v0.8.15+commit.e14f2714

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 8 : Vault.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;

import {ERC20} from "solmate/tokens/ERC20.sol";
import {SafeTransferLib} from "solmate/utils/SafeTransferLib.sol";
import {Owned} from "solmate/auth/Owned.sol";
import {ReentrancyGuard} from "solmate/utils/ReentrancyGuard.sol";
import {FixedPointMathLib} from "solmate/utils/FixedPointMathLib.sol";
import {Pausable} from "openzeppelin-contracts/security/Pausable.sol";

contract Vault is Owned, ReentrancyGuard, Pausable {
    using SafeTransferLib for ERC20;
    uint private constant MULTIPLIER = 1e18;        // multiplier for 18 decimals

    address public immutable stakeTokenAddr;        // shopx token address
    uint256 public totalSupply;                     // total number of shopx tokens staked
    mapping(address => uint) public lockTime;       // lockup time for each user
    mapping(address => uint256) public balanceOf;   // token balance of each user
    uint256 public defaultLockTime = 90 days;       // default lockTime
    uint256 public maxStake = 500_000 ether;        // maximum shopx allowed to stake for each user: 500,000 SHOPX
    uint256 public minStake = 1_000 ether;          // minimum shopx allowed to stake: 1,000 SHOPX

    address public immutable rewardTokenAddr;       // reward token address
    uint256 private rewardIndex;                    // index to calculate rewards
    mapping(address => uint) private rewardIndexOf; // reward index of each user
    mapping(address => uint256) public earned;      // reward by address

    event Staked(address indexed user, uint256 amount);
    event Unstaked(address indexed user, uint256 amount, uint256 reward);
    event RewardWithdrawn(address indexed user, uint256 reward);
    event Deposited(address indexed admin, uint256 amount);
    event UpdateDefaultLockTime(uint256 defaultLockTime);
    event UpdateMaxStake(uint256 maxStake);
    event UpdateMinStake(uint256 minStake);

    error MaxStake();
    error MinStake();

    constructor(address _stakeTokenAddr, address _rewardTokenAddr) Owned(msg.sender) {
        stakeTokenAddr = _stakeTokenAddr;
        rewardTokenAddr = _rewardTokenAddr;
    }

    receive() external payable {
        revert("Bad Call: send ERC20 reward token to deposit() function.");
    }

    function deposit(uint reward) external {
        require(totalSupply > 0, "totalSupply is 0");
        require(reward > 0, "reward is 0");
        rewardToken().safeTransferFrom(msg.sender, address(this), reward);
        rewardIndex += (reward * MULTIPLIER) / totalSupply;

        emit Deposited(msg.sender, reward);
    }

    function stake(uint256 amount) external whenNotPaused {
        if (amount == 0) return;
        if (amount < minStake) revert MinStake();
        if (balanceOf[msg.sender] + amount > maxStake) revert MaxStake();

        _updateRewards(msg.sender);

        balanceOf[msg.sender] += amount;
        totalSupply += amount;

        // reset lockTime
        lockTime[msg.sender] = block.timestamp + defaultLockTime;

        stakeToken().safeTransferFrom(msg.sender, address(this), amount);

        emit Staked(msg.sender, amount);
    }

    function unstake() external nonReentrant() {
        require(balanceOf[msg.sender] > 0, "Insufficient balance");
        require(block.timestamp > lockTime[msg.sender], "Lock time not expired");

        _updateRewards(msg.sender);

        // withdraw stakeToken
        uint256 accountBalance = balanceOf[msg.sender];
        balanceOf[msg.sender] = 0;
        totalSupply -= accountBalance;
        stakeToken().safeTransfer(msg.sender, accountBalance);

        // withdraw rewardToken
        uint reward = earned[msg.sender];
        if (reward > 0) {
            earned[msg.sender] = 0;
            rewardToken().safeTransfer(msg.sender, reward);
        }

        emit Unstaked(msg.sender, accountBalance, reward);
    }

    function withdrawReward() external nonReentrant() returns (uint) {
        _updateRewards(msg.sender);

        require(earned[msg.sender] > 0, "Insufficient reward");

        uint reward = earned[msg.sender];
        earned[msg.sender] = 0;
        rewardToken().safeTransfer(msg.sender, reward);
        emit RewardWithdrawn(msg.sender, reward);

        return reward;
    }

    function calculateRewardsEarned(address account) external view returns (uint) {
        return earned[account] + _calculateRewards(account);
    }

    function updateDefaultLockTime(uint256 _defaultLockTime) external onlyOwner returns (uint256) {
        require(_defaultLockTime!=0, "Invalid input");
        defaultLockTime = _defaultLockTime;
        emit UpdateDefaultLockTime(defaultLockTime);
        return defaultLockTime;
    }

    function updateMaxStake(uint256 _maxStake) external onlyOwner returns (uint256) {
        require(_maxStake!=0, "Invalid input");
        maxStake = _maxStake;
        emit UpdateMaxStake(maxStake);
        return maxStake;
    }

    function updateMinStake(uint256 _minStake) external onlyOwner returns (uint256) {
        // minStake = 0 to disable the minimum stake amount
        minStake = _minStake;
        emit UpdateMinStake(_minStake);
        return minStake;
    }

    function pause() external onlyOwner {
        _pause();
    }

    function unpause() external onlyOwner {
        _unpause();
    }

    function stakeToken() public view returns (ERC20 _stakeToken) {
        return ERC20(stakeTokenAddr);
    }

    function rewardToken() public view returns (ERC20 _rewardToken) {
        return ERC20(rewardTokenAddr);
    }

    function _calculateRewards(address account) private view returns (uint) {
        uint shares = balanceOf[account];
        return (shares * (rewardIndex - rewardIndexOf[account])) / MULTIPLIER;
    }

    function _updateRewards(address account) private {
        earned[account] += _calculateRewards(account);
        rewardIndexOf[account] = rewardIndex;
    }
}

File 2 of 8 : Pausable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)

pragma solidity ^0.8.0;

import "../utils/Context.sol";

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
abstract contract Pausable is Context {
    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by `account`.
     */
    event Unpaused(address account);

    bool private _paused;

    /**
     * @dev Initializes the contract in unpaused state.
     */
    constructor() {
        _paused = false;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    modifier whenNotPaused() {
        _requireNotPaused();
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    modifier whenPaused() {
        _requirePaused();
        _;
    }

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view virtual returns (bool) {
        return _paused;
    }

    /**
     * @dev Throws if the contract is paused.
     */
    function _requireNotPaused() internal view virtual {
        require(!paused(), "Pausable: paused");
    }

    /**
     * @dev Throws if the contract is not paused.
     */
    function _requirePaused() internal view virtual {
        require(paused(), "Pausable: not paused");
    }

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function _pause() internal virtual whenNotPaused {
        _paused = true;
        emit Paused(_msgSender());
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        _paused = false;
        emit Unpaused(_msgSender());
    }
}

File 3 of 8 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

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;
    }
}

File 4 of 8 : Owned.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Simple single owner authorization mixin.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Owned.sol)
abstract contract Owned {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event OwnerUpdated(address indexed user, address indexed newOwner);

    /*//////////////////////////////////////////////////////////////
                            OWNERSHIP STORAGE
    //////////////////////////////////////////////////////////////*/

    address public owner;

    modifier onlyOwner() virtual {
        require(msg.sender == owner, "UNAUTHORIZED");

        _;
    }

    /*//////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    constructor(address _owner) {
        owner = _owner;

        emit OwnerUpdated(address(0), _owner);
    }

    /*//////////////////////////////////////////////////////////////
                             OWNERSHIP LOGIC
    //////////////////////////////////////////////////////////////*/

    function setOwner(address newOwner) public virtual onlyOwner {
        owner = newOwner;

        emit OwnerUpdated(msg.sender, newOwner);
    }
}

File 5 of 8 : ERC20.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
abstract contract ERC20 {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event Transfer(address indexed from, address indexed to, uint256 amount);

    event Approval(address indexed owner, address indexed spender, uint256 amount);

    /*//////////////////////////////////////////////////////////////
                            METADATA STORAGE
    //////////////////////////////////////////////////////////////*/

    string public name;

    string public symbol;

    uint8 public immutable decimals;

    /*//////////////////////////////////////////////////////////////
                              ERC20 STORAGE
    //////////////////////////////////////////////////////////////*/

    uint256 public totalSupply;

    mapping(address => uint256) public balanceOf;

    mapping(address => mapping(address => uint256)) public allowance;

    /*//////////////////////////////////////////////////////////////
                            EIP-2612 STORAGE
    //////////////////////////////////////////////////////////////*/

    uint256 internal immutable INITIAL_CHAIN_ID;

    bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;

    mapping(address => uint256) public nonces;

    /*//////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    constructor(
        string memory _name,
        string memory _symbol,
        uint8 _decimals
    ) {
        name = _name;
        symbol = _symbol;
        decimals = _decimals;

        INITIAL_CHAIN_ID = block.chainid;
        INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
    }

    /*//////////////////////////////////////////////////////////////
                               ERC20 LOGIC
    //////////////////////////////////////////////////////////////*/

    function approve(address spender, uint256 amount) public virtual returns (bool) {
        allowance[msg.sender][spender] = amount;

        emit Approval(msg.sender, spender, amount);

        return true;
    }

    function transfer(address to, uint256 amount) public virtual returns (bool) {
        balanceOf[msg.sender] -= amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(msg.sender, to, amount);

        return true;
    }

    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual returns (bool) {
        uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.

        if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;

        balanceOf[from] -= amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(from, to, amount);

        return true;
    }

    /*//////////////////////////////////////////////////////////////
                             EIP-2612 LOGIC
    //////////////////////////////////////////////////////////////*/

    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public virtual {
        require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");

        // Unchecked because the only math done is incrementing
        // the owner's nonce which cannot realistically overflow.
        unchecked {
            address recoveredAddress = ecrecover(
                keccak256(
                    abi.encodePacked(
                        "\x19\x01",
                        DOMAIN_SEPARATOR(),
                        keccak256(
                            abi.encode(
                                keccak256(
                                    "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
                                ),
                                owner,
                                spender,
                                value,
                                nonces[owner]++,
                                deadline
                            )
                        )
                    )
                ),
                v,
                r,
                s
            );

            require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");

            allowance[recoveredAddress][spender] = value;
        }

        emit Approval(owner, spender, value);
    }

    function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
        return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
    }

    function computeDomainSeparator() internal view virtual returns (bytes32) {
        return
            keccak256(
                abi.encode(
                    keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
                    keccak256(bytes(name)),
                    keccak256("1"),
                    block.chainid,
                    address(this)
                )
            );
    }

    /*//////////////////////////////////////////////////////////////
                        INTERNAL MINT/BURN LOGIC
    //////////////////////////////////////////////////////////////*/

    function _mint(address to, uint256 amount) internal virtual {
        totalSupply += amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(address(0), to, amount);
    }

    function _burn(address from, uint256 amount) internal virtual {
        balanceOf[from] -= amount;

        // Cannot underflow because a user's balance
        // will never be larger than the total supply.
        unchecked {
            totalSupply -= amount;
        }

        emit Transfer(from, address(0), amount);
    }
}

File 6 of 8 : FixedPointMathLib.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Arithmetic library with operations for fixed-point numbers.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol)
/// @author Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol)
library FixedPointMathLib {
    /*//////////////////////////////////////////////////////////////
                    SIMPLIFIED FIXED POINT OPERATIONS
    //////////////////////////////////////////////////////////////*/

    uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s.

    function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down.
    }

    function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up.
    }

    function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down.
    }

    function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up.
    }

    /*//////////////////////////////////////////////////////////////
                    LOW LEVEL FIXED POINT OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function mulDivDown(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 z) {
        assembly {
            // Store x * y in z for now.
            z := mul(x, y)

            // Equivalent to require(denominator != 0 && (x == 0 || (x * y) / x == y))
            if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) {
                revert(0, 0)
            }

            // Divide z by the denominator.
            z := div(z, denominator)
        }
    }

    function mulDivUp(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 z) {
        assembly {
            // Store x * y in z for now.
            z := mul(x, y)

            // Equivalent to require(denominator != 0 && (x == 0 || (x * y) / x == y))
            if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) {
                revert(0, 0)
            }

            // First, divide z - 1 by the denominator and add 1.
            // We allow z - 1 to underflow if z is 0, because we multiply the
            // end result by 0 if z is zero, ensuring we return 0 if z is zero.
            z := mul(iszero(iszero(z)), add(div(sub(z, 1), denominator), 1))
        }
    }

    function rpow(
        uint256 x,
        uint256 n,
        uint256 scalar
    ) internal pure returns (uint256 z) {
        assembly {
            switch x
            case 0 {
                switch n
                case 0 {
                    // 0 ** 0 = 1
                    z := scalar
                }
                default {
                    // 0 ** n = 0
                    z := 0
                }
            }
            default {
                switch mod(n, 2)
                case 0 {
                    // If n is even, store scalar in z for now.
                    z := scalar
                }
                default {
                    // If n is odd, store x in z for now.
                    z := x
                }

                // Shifting right by 1 is like dividing by 2.
                let half := shr(1, scalar)

                for {
                    // Shift n right by 1 before looping to halve it.
                    n := shr(1, n)
                } n {
                    // Shift n right by 1 each iteration to halve it.
                    n := shr(1, n)
                } {
                    // Revert immediately if x ** 2 would overflow.
                    // Equivalent to iszero(eq(div(xx, x), x)) here.
                    if shr(128, x) {
                        revert(0, 0)
                    }

                    // Store x squared.
                    let xx := mul(x, x)

                    // Round to the nearest number.
                    let xxRound := add(xx, half)

                    // Revert if xx + half overflowed.
                    if lt(xxRound, xx) {
                        revert(0, 0)
                    }

                    // Set x to scaled xxRound.
                    x := div(xxRound, scalar)

                    // If n is even:
                    if mod(n, 2) {
                        // Compute z * x.
                        let zx := mul(z, x)

                        // If z * x overflowed:
                        if iszero(eq(div(zx, x), z)) {
                            // Revert if x is non-zero.
                            if iszero(iszero(x)) {
                                revert(0, 0)
                            }
                        }

                        // Round to the nearest number.
                        let zxRound := add(zx, half)

                        // Revert if zx + half overflowed.
                        if lt(zxRound, zx) {
                            revert(0, 0)
                        }

                        // Return properly scaled zxRound.
                        z := div(zxRound, scalar)
                    }
                }
            }
        }
    }

    /*//////////////////////////////////////////////////////////////
                        GENERAL NUMBER UTILITIES
    //////////////////////////////////////////////////////////////*/

    function sqrt(uint256 x) internal pure returns (uint256 z) {
        assembly {
            let y := x // We start y at x, which will help us make our initial estimate.

            z := 181 // The "correct" value is 1, but this saves a multiplication later.

            // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad
            // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.

            // We check y >= 2^(k + 8) but shift right by k bits
            // each branch to ensure that if x >= 256, then y >= 256.
            if iszero(lt(y, 0x10000000000000000000000000000000000)) {
                y := shr(128, y)
                z := shl(64, z)
            }
            if iszero(lt(y, 0x1000000000000000000)) {
                y := shr(64, y)
                z := shl(32, z)
            }
            if iszero(lt(y, 0x10000000000)) {
                y := shr(32, y)
                z := shl(16, z)
            }
            if iszero(lt(y, 0x1000000)) {
                y := shr(16, y)
                z := shl(8, z)
            }

            // Goal was to get z*z*y within a small factor of x. More iterations could
            // get y in a tighter range. Currently, we will have y in [256, 256*2^16).
            // We ensured y >= 256 so that the relative difference between y and y+1 is small.
            // That's not possible if x < 256 but we can just verify those cases exhaustively.

            // Now, z*z*y <= x < z*z*(y+1), and y <= 2^(16+8), and either y >= 256, or x < 256.
            // Correctness can be checked exhaustively for x < 256, so we assume y >= 256.
            // Then z*sqrt(y) is within sqrt(257)/sqrt(256) of sqrt(x), or about 20bps.

            // For s in the range [1/256, 256], the estimate f(s) = (181/1024) * (s+1) is in the range
            // (1/2.84 * sqrt(s), 2.84 * sqrt(s)), with largest error when s = 1 and when s = 256 or 1/256.

            // Since y is in [256, 256*2^16), let a = y/65536, so that a is in [1/256, 256). Then we can estimate
            // sqrt(y) using sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2^18.

            // There is no overflow risk here since y < 2^136 after the first branch above.
            z := shr(18, mul(z, add(y, 65536))) // A mul() is saved from starting z at 181.

            // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))

            // If x+1 is a perfect square, the Babylonian method cycles between
            // floor(sqrt(x)) and ceil(sqrt(x)). This statement ensures we return floor.
            // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division
            // Since the ceil is rare, we save gas on the assignment and repeat division in the rare case.
            // If you don't care whether the floor or ceil square root is returned, you can remove this statement.
            z := sub(z, lt(div(x, z), z))
        }
    }

    function unsafeMod(uint256 x, uint256 y) internal pure returns (uint256 z) {
        assembly {
            // Mod x by y. Note this will return
            // 0 instead of reverting if y is zero.
            z := mod(x, y)
        }
    }

    function unsafeDiv(uint256 x, uint256 y) internal pure returns (uint256 r) {
        assembly {
            // Divide x by y. Note this will return
            // 0 instead of reverting if y is zero.
            r := div(x, y)
        }
    }

    function unsafeDivUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
        assembly {
            // Add 1 to x * y if x % y > 0. Note this will
            // return 0 instead of reverting if y is zero.
            z := add(gt(mod(x, y), 0), div(x, y))
        }
    }
}

File 7 of 8 : ReentrancyGuard.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Gas optimized reentrancy protection for smart contracts.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/ReentrancyGuard.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/security/ReentrancyGuard.sol)
abstract contract ReentrancyGuard {
    uint256 private locked = 1;

    modifier nonReentrant() virtual {
        require(locked == 1, "REENTRANCY");

        locked = 2;

        _;

        locked = 1;
    }
}

File 8 of 8 : SafeTransferLib.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

import {ERC20} from "../tokens/ERC20.sol";

/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer.
/// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller.
library SafeTransferLib {
    /*//////////////////////////////////////////////////////////////
                             ETH OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function safeTransferETH(address to, uint256 amount) internal {
        bool success;

        assembly {
            // Transfer the ETH and store if it succeeded or not.
            success := call(gas(), to, amount, 0, 0, 0, 0)
        }

        require(success, "ETH_TRANSFER_FAILED");
    }

    /*//////////////////////////////////////////////////////////////
                            ERC20 OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function safeTransferFrom(
        ERC20 token,
        address from,
        address to,
        uint256 amount
    ) internal {
        bool success;

        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), from) // Append the "from" argument.
            mstore(add(freeMemoryPointer, 36), to) // Append the "to" argument.
            mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 100 because the length of our calldata totals up like so: 4 + 32 * 3.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the or() call in the
                // surrounding and() call or else returndatasize() will be zero during the computation.
                call(gas(), token, 0, freeMemoryPointer, 100, 0, 32)
            )
        }

        require(success, "TRANSFER_FROM_FAILED");
    }

    function safeTransfer(
        ERC20 token,
        address to,
        uint256 amount
    ) internal {
        bool success;

        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument.
            mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the or() call in the
                // surrounding and() call or else returndatasize() will be zero during the computation.
                call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
            )
        }

        require(success, "TRANSFER_FAILED");
    }

    function safeApprove(
        ERC20 token,
        address to,
        uint256 amount
    ) internal {
        bool success;

        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument.
            mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the or() call in the
                // surrounding and() call or else returndatasize() will be zero during the computation.
                call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
            )
        }

        require(success, "APPROVE_FAILED");
    }
}

Settings
{
  "remappings": [
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "forge-std/=lib/forge-std/src/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/",
    "solmate/=lib/solmate/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "london",
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_stakeTokenAddr","type":"address"},{"internalType":"address","name":"_rewardTokenAddr","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"MaxStake","type":"error"},{"inputs":[],"name":"MinStake","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"admin","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Deposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"reward","type":"uint256"}],"name":"RewardWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Staked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"reward","type":"uint256"}],"name":"Unstaked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"defaultLockTime","type":"uint256"}],"name":"UpdateDefaultLockTime","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxStake","type":"uint256"}],"name":"UpdateMaxStake","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"minStake","type":"uint256"}],"name":"UpdateMinStake","type":"event"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"calculateRewardsEarned","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"defaultLockTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"reward","type":"uint256"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"earned","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"lockTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxStake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minStake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardToken","outputs":[{"internalType":"contract ERC20","name":"_rewardToken","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardTokenAddr","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stakeToken","outputs":[{"internalType":"contract ERC20","name":"_stakeToken","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stakeTokenAddr","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unstake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_defaultLockTime","type":"uint256"}],"name":"updateDefaultLockTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxStake","type":"uint256"}],"name":"updateMaxStake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minStake","type":"uint256"}],"name":"updateMinStake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawReward","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

60c0604052600180556276a7006006556969e10de76676d0800000600755683635c9adc5dea0000060085534801561003657600080fd5b506040516112a33803806112a3833981016040819052610055916100d3565b600080546001600160a01b031916339081178255604051909182917f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d76908290a3506002805460ff191690556001600160a01b039182166080521660a052610106565b80516001600160a01b03811681146100ce57600080fd5b919050565b600080604083850312156100e657600080fd5b6100ef836100b7565b91506100fd602084016100b7565b90509250929050565b60805160a05161114761015c600039600081816104ad015281816104f40152818161071501528181610afe0152610c4601526000818161029201528181610459015281816106b80152610a0801526111476000f3fe60806040526004361061014e5760003560e01c80638cdb442f116100b6578063c885bc581161006f578063c885bc5814610432578063d9385c9914610447578063de4cd4f41461047b578063e89dec6d1461049b578063ea1b28e0146104cf578063f7c618c1146104e557600080fd5b80638cdb442f146103655780638da5cb5b146103855780638fa7f745146103a5578063a4beda63146103c5578063a694fc3a146103f2578063b6b55f251461041257600080fd5b806351ed6a301161010857806351ed6a30146102835780635c975abb146102ca57806370a08231146102ed5780637e18f27f1461031a5780638456cb59146103305780638b0867641461034557600080fd5b80628cc262146101cb57806313af40351461020b57806318160ddd1461022d5780632def662014610243578063375b3c0a146102585780633f4ba83a1461026e57600080fd5b366101c65760405162461bcd60e51b815260206004820152603860248201527f4261642043616c6c3a2073656e642045524332302072657761726420746f6b6560448201527f6e20746f206465706f73697428292066756e6374696f6e2e000000000000000060648201526084015b60405180910390fd5b600080fd5b3480156101d757600080fd5b506101f86101e6366004611023565b600b6020526000908152604090205481565b6040519081526020015b60405180910390f35b34801561021757600080fd5b5061022b610226366004611023565b610518565b005b34801561023957600080fd5b506101f860035481565b34801561024f57600080fd5b5061022b61058d565b34801561026457600080fd5b506101f860085481565b34801561027a57600080fd5b5061022b61077c565b34801561028f57600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b039091168152602001610202565b3480156102d657600080fd5b5060025460ff166040519015158152602001610202565b3480156102f957600080fd5b506101f8610308366004611023565b60056020526000908152604090205481565b34801561032657600080fd5b506101f860065481565b34801561033c57600080fd5b5061022b6107b0565b34801561035157600080fd5b506101f8610360366004611023565b6107e2565b34801561037157600080fd5b506101f861038036600461104c565b610816565b34801561039157600080fd5b506000546102b2906001600160a01b031681565b3480156103b157600080fd5b506101f86103c036600461104c565b610881565b3480156103d157600080fd5b506101f86103e0366004611023565b60046020526000908152604090205481565b3480156103fe57600080fd5b5061022b61040d36600461104c565b61092c565b34801561041e57600080fd5b5061022b61042d36600461104c565b610a73565b34801561043e57600080fd5b506101f8610b89565b34801561045357600080fd5b506102b27f000000000000000000000000000000000000000000000000000000000000000081565b34801561048757600080fd5b506101f861049636600461104c565b610ca8565b3480156104a757600080fd5b506102b27f000000000000000000000000000000000000000000000000000000000000000081565b3480156104db57600080fd5b506101f860075481565b3480156104f157600080fd5b507f00000000000000000000000000000000000000000000000000000000000000006102b2565b6000546001600160a01b031633146105425760405162461bcd60e51b81526004016101bd90611065565b600080546001600160a01b0319166001600160a01b0383169081178255604051909133917f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d769190a350565b6001546001146105cc5760405162461bcd60e51b815260206004820152600a6024820152695245454e5452414e435960b01b60448201526064016101bd565b6002600155336000908152600560205260409020546106245760405162461bcd60e51b8152602060048201526014602482015273496e73756666696369656e742062616c616e636560601b60448201526064016101bd565b33600090815260046020526040902054421161067a5760405162461bcd60e51b8152602060048201526015602482015274131bd8dac81d1a5b59481b9bdd08195e1c1a5c9959605a1b60448201526064016101bd565b61068333610d53565b33600090815260056020526040812080549082905560038054919283926106ab9084906110a1565b909155506106e8905033827f00000000000000000000000000000000000000000000000000000000000000005b6001600160a01b03169190610da8565b336000908152600b6020526040902054801561073957336000818152600b602052604081205561073990827f00000000000000000000000000000000000000000000000000000000000000006106d8565b604080518381526020810183905233917f7fc4727e062e336010f2c282598ef5f14facb3de68cf8195c2f23e1454b2b74e910160405180910390a2505060018055565b6000546001600160a01b031633146107a65760405162461bcd60e51b81526004016101bd90611065565b6107ae610e26565b565b6000546001600160a01b031633146107da5760405162461bcd60e51b81526004016101bd90611065565b6107ae610e78565b60006107ed82610eb5565b6001600160a01b0383166000908152600b602052604090205461081091906110b8565b92915050565b600080546001600160a01b031633146108415760405162461bcd60e51b81526004016101bd90611065565b60088290556040518281527f04441d80e67b89118dd786c6c0ad193a6d320b801b57c80f8e4f1064ad5bb9999060200160405180910390a1505060085490565b600080546001600160a01b031633146108ac5760405162461bcd60e51b81526004016101bd90611065565b816000036108ec5760405162461bcd60e51b815260206004820152600d60248201526c125b9d985b1a59081a5b9c1d5d609a1b60448201526064016101bd565b60078290556040518281527f449e21d2b77d562e834991b685ff20550f5edef166d349b0529899f3c8d025309060200160405180910390a1505060075490565b610934610f0a565b8015610a705760085481101561095d57604051632acb3f9b60e21b815260040160405180910390fd5b6007543360009081526005602052604090205461097b9083906110b8565b111561099a576040516326eba2cf60e01b815260040160405180910390fd5b6109a333610d53565b33600090815260056020526040812080548392906109c29084906110b8565b9250508190555080600360008282546109db91906110b8565b90915550506006546109ed90426110b8565b33600081815260046020526040902091909155610a399030837f00000000000000000000000000000000000000000000000000000000000000005b6001600160a01b0316929190610f50565b60405181815233907f9e71bc8eea02a63969f509818f2dafb9254532904319f9dbda79b67bd34a5f3d906020015b60405180910390a25b50565b600060035411610ab85760405162461bcd60e51b815260206004820152601060248201526f0746f74616c537570706c7920697320360841b60448201526064016101bd565b60008111610af65760405162461bcd60e51b815260206004820152600b60248201526a072657761726420697320360ac1b60448201526064016101bd565b610b223330837f0000000000000000000000000000000000000000000000000000000000000000610a28565b600354610b37670de0b6b3a7640000836110d0565b610b4191906110ef565b60096000828254610b5291906110b8565b909155505060405181815233907f2da466a7b24304f47e87fa2e1e5a81b9831ce54fec19055ce277ca2f39ba42c490602001610a67565b6000600154600114610bca5760405162461bcd60e51b815260206004820152600a6024820152695245454e5452414e435960b01b60448201526064016101bd565b6002600155610bd833610d53565b336000908152600b6020526040902054610c2a5760405162461bcd60e51b8152602060048201526013602482015272125b9cdd59999a58da595b9d081c995dd85c99606a1b60448201526064016101bd565b336000818152600b60205260408120805491905590610c6a90827f00000000000000000000000000000000000000000000000000000000000000006106d8565b60405181815233907f1d3eee4ca001cff39eec6ec7615aacf2f2bd61791273830728ba00ccbd6e13379060200160405180910390a290506001805590565b600080546001600160a01b03163314610cd35760405162461bcd60e51b81526004016101bd90611065565b81600003610d135760405162461bcd60e51b815260206004820152600d60248201526c125b9d985b1a59081a5b9c1d5d609a1b60448201526064016101bd565b60068290556040518281527f3d6d629e47c86ddc08d842b4a309300c603a17ab66a03e223773d9e14f5c5d299060200160405180910390a1505060065490565b610d5c81610eb5565b6001600160a01b0382166000908152600b602052604081208054909190610d849084906110b8565b90915550506009546001600160a01b039091166000908152600a6020526040902055565b600060405163a9059cbb60e01b8152836004820152826024820152602060006044836000895af13d15601f3d1160016000511416171691505080610e205760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b60448201526064016101bd565b50505050565b610e2e610fda565b6002805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b610e80610f0a565b6002805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258610e5b3390565b6001600160a01b038116600090815260056020908152604080832054600a909252822054600954670de0b6b3a764000091610eef916110a1565b610ef990836110d0565b610f0391906110ef565b9392505050565b60025460ff16156107ae5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016101bd565b60006040516323b872dd60e01b81528460048201528360248201528260448201526020600060648360008a5af13d15601f3d1160016000511416171691505080610fd35760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b60448201526064016101bd565b5050505050565b60025460ff166107ae5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016101bd565b60006020828403121561103557600080fd5b81356001600160a01b0381168114610f0357600080fd5b60006020828403121561105e57600080fd5b5035919050565b6020808252600c908201526b15539055551213d49256915160a21b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b6000828210156110b3576110b361108b565b500390565b600082198211156110cb576110cb61108b565b500190565b60008160001904831182151516156110ea576110ea61108b565b500290565b60008261110c57634e487b7160e01b600052601260045260246000fd5b50049056fea2646970667358221220907bdbbb845bafda5b27f6b5a88219041478e153833fe2f6470e7b196f0f94e364736f6c634300080f00330000000000000000000000007bef710a5759d197ec0bf621c3df802c2d60d848000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2

Deployed Bytecode

0x60806040526004361061014e5760003560e01c80638cdb442f116100b6578063c885bc581161006f578063c885bc5814610432578063d9385c9914610447578063de4cd4f41461047b578063e89dec6d1461049b578063ea1b28e0146104cf578063f7c618c1146104e557600080fd5b80638cdb442f146103655780638da5cb5b146103855780638fa7f745146103a5578063a4beda63146103c5578063a694fc3a146103f2578063b6b55f251461041257600080fd5b806351ed6a301161010857806351ed6a30146102835780635c975abb146102ca57806370a08231146102ed5780637e18f27f1461031a5780638456cb59146103305780638b0867641461034557600080fd5b80628cc262146101cb57806313af40351461020b57806318160ddd1461022d5780632def662014610243578063375b3c0a146102585780633f4ba83a1461026e57600080fd5b366101c65760405162461bcd60e51b815260206004820152603860248201527f4261642043616c6c3a2073656e642045524332302072657761726420746f6b6560448201527f6e20746f206465706f73697428292066756e6374696f6e2e000000000000000060648201526084015b60405180910390fd5b600080fd5b3480156101d757600080fd5b506101f86101e6366004611023565b600b6020526000908152604090205481565b6040519081526020015b60405180910390f35b34801561021757600080fd5b5061022b610226366004611023565b610518565b005b34801561023957600080fd5b506101f860035481565b34801561024f57600080fd5b5061022b61058d565b34801561026457600080fd5b506101f860085481565b34801561027a57600080fd5b5061022b61077c565b34801561028f57600080fd5b507f0000000000000000000000007bef710a5759d197ec0bf621c3df802c2d60d8485b6040516001600160a01b039091168152602001610202565b3480156102d657600080fd5b5060025460ff166040519015158152602001610202565b3480156102f957600080fd5b506101f8610308366004611023565b60056020526000908152604090205481565b34801561032657600080fd5b506101f860065481565b34801561033c57600080fd5b5061022b6107b0565b34801561035157600080fd5b506101f8610360366004611023565b6107e2565b34801561037157600080fd5b506101f861038036600461104c565b610816565b34801561039157600080fd5b506000546102b2906001600160a01b031681565b3480156103b157600080fd5b506101f86103c036600461104c565b610881565b3480156103d157600080fd5b506101f86103e0366004611023565b60046020526000908152604090205481565b3480156103fe57600080fd5b5061022b61040d36600461104c565b61092c565b34801561041e57600080fd5b5061022b61042d36600461104c565b610a73565b34801561043e57600080fd5b506101f8610b89565b34801561045357600080fd5b506102b27f0000000000000000000000007bef710a5759d197ec0bf621c3df802c2d60d84881565b34801561048757600080fd5b506101f861049636600461104c565b610ca8565b3480156104a757600080fd5b506102b27f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b3480156104db57600080fd5b506101f860075481565b3480156104f157600080fd5b507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26102b2565b6000546001600160a01b031633146105425760405162461bcd60e51b81526004016101bd90611065565b600080546001600160a01b0319166001600160a01b0383169081178255604051909133917f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d769190a350565b6001546001146105cc5760405162461bcd60e51b815260206004820152600a6024820152695245454e5452414e435960b01b60448201526064016101bd565b6002600155336000908152600560205260409020546106245760405162461bcd60e51b8152602060048201526014602482015273496e73756666696369656e742062616c616e636560601b60448201526064016101bd565b33600090815260046020526040902054421161067a5760405162461bcd60e51b8152602060048201526015602482015274131bd8dac81d1a5b59481b9bdd08195e1c1a5c9959605a1b60448201526064016101bd565b61068333610d53565b33600090815260056020526040812080549082905560038054919283926106ab9084906110a1565b909155506106e8905033827f0000000000000000000000007bef710a5759d197ec0bf621c3df802c2d60d8485b6001600160a01b03169190610da8565b336000908152600b6020526040902054801561073957336000818152600b602052604081205561073990827f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26106d8565b604080518381526020810183905233917f7fc4727e062e336010f2c282598ef5f14facb3de68cf8195c2f23e1454b2b74e910160405180910390a2505060018055565b6000546001600160a01b031633146107a65760405162461bcd60e51b81526004016101bd90611065565b6107ae610e26565b565b6000546001600160a01b031633146107da5760405162461bcd60e51b81526004016101bd90611065565b6107ae610e78565b60006107ed82610eb5565b6001600160a01b0383166000908152600b602052604090205461081091906110b8565b92915050565b600080546001600160a01b031633146108415760405162461bcd60e51b81526004016101bd90611065565b60088290556040518281527f04441d80e67b89118dd786c6c0ad193a6d320b801b57c80f8e4f1064ad5bb9999060200160405180910390a1505060085490565b600080546001600160a01b031633146108ac5760405162461bcd60e51b81526004016101bd90611065565b816000036108ec5760405162461bcd60e51b815260206004820152600d60248201526c125b9d985b1a59081a5b9c1d5d609a1b60448201526064016101bd565b60078290556040518281527f449e21d2b77d562e834991b685ff20550f5edef166d349b0529899f3c8d025309060200160405180910390a1505060075490565b610934610f0a565b8015610a705760085481101561095d57604051632acb3f9b60e21b815260040160405180910390fd5b6007543360009081526005602052604090205461097b9083906110b8565b111561099a576040516326eba2cf60e01b815260040160405180910390fd5b6109a333610d53565b33600090815260056020526040812080548392906109c29084906110b8565b9250508190555080600360008282546109db91906110b8565b90915550506006546109ed90426110b8565b33600081815260046020526040902091909155610a399030837f0000000000000000000000007bef710a5759d197ec0bf621c3df802c2d60d8485b6001600160a01b0316929190610f50565b60405181815233907f9e71bc8eea02a63969f509818f2dafb9254532904319f9dbda79b67bd34a5f3d906020015b60405180910390a25b50565b600060035411610ab85760405162461bcd60e51b815260206004820152601060248201526f0746f74616c537570706c7920697320360841b60448201526064016101bd565b60008111610af65760405162461bcd60e51b815260206004820152600b60248201526a072657761726420697320360ac1b60448201526064016101bd565b610b223330837f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2610a28565b600354610b37670de0b6b3a7640000836110d0565b610b4191906110ef565b60096000828254610b5291906110b8565b909155505060405181815233907f2da466a7b24304f47e87fa2e1e5a81b9831ce54fec19055ce277ca2f39ba42c490602001610a67565b6000600154600114610bca5760405162461bcd60e51b815260206004820152600a6024820152695245454e5452414e435960b01b60448201526064016101bd565b6002600155610bd833610d53565b336000908152600b6020526040902054610c2a5760405162461bcd60e51b8152602060048201526013602482015272125b9cdd59999a58da595b9d081c995dd85c99606a1b60448201526064016101bd565b336000818152600b60205260408120805491905590610c6a90827f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26106d8565b60405181815233907f1d3eee4ca001cff39eec6ec7615aacf2f2bd61791273830728ba00ccbd6e13379060200160405180910390a290506001805590565b600080546001600160a01b03163314610cd35760405162461bcd60e51b81526004016101bd90611065565b81600003610d135760405162461bcd60e51b815260206004820152600d60248201526c125b9d985b1a59081a5b9c1d5d609a1b60448201526064016101bd565b60068290556040518281527f3d6d629e47c86ddc08d842b4a309300c603a17ab66a03e223773d9e14f5c5d299060200160405180910390a1505060065490565b610d5c81610eb5565b6001600160a01b0382166000908152600b602052604081208054909190610d849084906110b8565b90915550506009546001600160a01b039091166000908152600a6020526040902055565b600060405163a9059cbb60e01b8152836004820152826024820152602060006044836000895af13d15601f3d1160016000511416171691505080610e205760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b60448201526064016101bd565b50505050565b610e2e610fda565b6002805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b610e80610f0a565b6002805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258610e5b3390565b6001600160a01b038116600090815260056020908152604080832054600a909252822054600954670de0b6b3a764000091610eef916110a1565b610ef990836110d0565b610f0391906110ef565b9392505050565b60025460ff16156107ae5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016101bd565b60006040516323b872dd60e01b81528460048201528360248201528260448201526020600060648360008a5af13d15601f3d1160016000511416171691505080610fd35760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b60448201526064016101bd565b5050505050565b60025460ff166107ae5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016101bd565b60006020828403121561103557600080fd5b81356001600160a01b0381168114610f0357600080fd5b60006020828403121561105e57600080fd5b5035919050565b6020808252600c908201526b15539055551213d49256915160a21b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b6000828210156110b3576110b361108b565b500390565b600082198211156110cb576110cb61108b565b500190565b60008160001904831182151516156110ea576110ea61108b565b500290565b60008261110c57634e487b7160e01b600052601260045260246000fd5b50049056fea2646970667358221220907bdbbb845bafda5b27f6b5a88219041478e153833fe2f6470e7b196f0f94e364736f6c634300080f0033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

0000000000000000000000007bef710a5759d197ec0bf621c3df802c2d60d848000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2

-----Decoded View---------------
Arg [0] : _stakeTokenAddr (address): 0x7BEF710a5759d197EC0Bf621c3Df802C2D60D848
Arg [1] : _rewardTokenAddr (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000007bef710a5759d197ec0bf621c3df802c2d60d848
Arg [1] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.