Cryo Explorer Ethereum Mainnet

Address Contract Verified

Address 0xa2CD89a5aF16ddB782F25A4ea1D62777De245108
Balance 0 ETH
Nonce 1
Code Size 4104 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

4104 bytes
0x608060405234801561001057600080fd5b50600436106100f55760003560e01c8063a638f2e211610097578063e30c397811610066578063e30c39781461026d578063e449f3411461027e578063f2fde38b14610291578063fc0c546a146102a457600080fd5b8063a638f2e2146101c7578063ac4afa38146101da578063b13ae80414610247578063d790366a1461025a57600080fd5b8063715018a6116100d3578063715018a61461017f57806379ba50971461018757806380abfb661461018f5780638da5cb5b146101a257600080fd5b80630e36e355146100fa578063584b62a11461012d5780635e8ead771461016a575b600080fd5b61011a610108366004610dbd565b60056020526000908152604090205481565b6040519081526020015b60405180910390f35b61014061013b366004610ddf565b6102cb565b6040805195865260208601949094529284019190915260608301521515608082015260a001610124565b61017d610178366004610e09565b61031c565b005b61017d61036a565b61017d61037e565b61017d61019d366004610e6e565b6103c7565b6000546001600160a01b03165b6040516001600160a01b039091168152602001610124565b61017d6101d5366004610ec1565b61056f565b61021b6101e8366004610e09565b60036020526000908152604090208054600182015460028301546004909301549192909160ff8082169161010090041685565b60408051958652602086019490945292840191909152151560608301521515608082015260a001610124565b61017d610255366004610e09565b6108bd565b61017d610268366004610e09565b610908565b6001546001600160a01b03166101af565b61017d61028c366004610eed565b610958565b61017d61029f366004610dbd565b610bc7565b6101af7f0000000000000000000000008fc17671d853341d9e8b001f5fc3c892d09cb53a81565b600460205281600052604060002081815481106102e757600080fd5b600091825260209091206005909102018054600182015460028301546003840154600490940154929550909350919060ff1685565b610324610c38565b600081815260036020526040808220600401805460ff191660011790555182917ff18e8c210f1a92a818e663f01d9918cfde3c8b4919af0b6666f41ca61c7cec3491a250565b610372610c38565b61037c6000610c65565b565b60015433906001600160a01b031681146103bb5760405163118cdaa760e01b81526001600160a01b03821660048201526024015b60405180910390fd5b6103c481610c65565b50565b6103cf610c38565b600084815260036020526040902060010154156103ff57604051630188c99160e11b815260040160405180910390fd5b82600003610420576040516361bf397360e01b815260040160405180910390fd5b60005b8181101561046c5782828281811061043d5761043d610f2f565b9050602002013560000361046457604051633e76242f60e11b815260040160405180910390fd5b600101610423565b506040518060c0016040528085815260200184815260200160008152602001838380806020026020016040519081016040528093929190818152602001838360200280828437600092018290525093855250505060208083018290526040928301829052878252600380825291839020845181558482015160018201559284015160028401556060840151805161050a938501929190910190610d41565b5060808201516004909101805460a09093015115156101000261ff00199215159290921661ffff1990931692909217179055604051839085907f37d4a71449cd4163b2d08aeed513412fe798bf25bb804c48f90470f32a17308f90600090a350505050565b610577610c7e565b60008381526003602052604081206001015490036105a8576040516302721e1f60e61b815260040160405180910390fd5b6000838152600360208181526040808420815160c08101835281548152600182015481850152600282015481840152938101805483518186028101860190945280845291936060860193929083018282801561062357602002820191906000526020600020905b81548152602001906001019080831161060f575b50505091835250506004919091015460ff8082161515602084015261010090910416151560409091015260a081015190915015610673576040516314a5d40960e01b815260040160405180910390fd5b806080015115610696576040516321081abf60e01b815260040160405180910390fd5b6000848152600360205260409081902060010154908201516106b89085610f5b565b11156106d757604051632795088960e11b815260040160405180910390fd5b6106e5816060015183610ca6565b61070257604051631578094360e01b815260040160405180910390fd5b6040516323b872dd60e01b8152336004820152306024820152604481018490527f0000000000000000000000008fc17671d853341d9e8b001f5fc3c892d09cb53a6001600160a01b0316906323b872dd906064016020604051808303816000875af1158015610775573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107999190610f6e565b5033600090815260046020908152604091829020825160a081018452878152918201869052918101849052606081016107d28542610f5b565b8152600060209182018190528354600180820186559482528282208451600592830290910190815584840151958101959095556040808501516002870155606085015160038701556080909401516004909501805460ff191695151595909517909455338152929052812080549161084983610f90565b90915550506000848152600360205260408120600201805485929061086f908490610f5b565b90915550506040518381528290859033907fb4caaf29adda3eefee3ad552a8e85058589bf834c7466cae4ee58787f70589ed9060200160405180910390a4506108b86001600255565b505050565b6108c5610c38565b600081815260036020526040808220600401805460ff191690555182917f99e9115f189244af0fdf309a161ca24f1a1acb222a66a0840caa7b2d48e4ec0191a250565b610910610c38565b600081815260036020526040808220600401805461ff0019166101001790555182917fcc8f7cd6b59cbac2c458254806d88c1baa77abbe2d83dc4ccdc8ac0debecc0d691a250565b610960610c7e565b6000805b82811015610ae55733600090815260046020526040812085858481811061098d5761098d610f2f565b90506020020135815481106109a4576109a4610f2f565b60009182526020909120600590910201600481015490915060ff16156109dd57604051636c18a98960e11b815260040160405180910390fd5b80546000908152600360208181526040808420815160c081018352815481526001820154818501526002820154818401529381018054835181860281018601909452808452919360608601939290830182828015610a5a57602002820191906000526020600020905b815481526020019060010190808311610a46575b50505091835250506004919091015460ff8082161515602084015261010090910416151560409091015260a0810151909150158015610a9c5750428260030154115b15610aba57604051635859e3d960e01b815260040160405180910390fd5b60048201805460ff19166001908117909155820154610ad99085610f5b565b93505050600101610964565b5060405163a9059cbb60e01b8152336004820152602481018290527f0000000000000000000000008fc17671d853341d9e8b001f5fc3c892d09cb53a6001600160a01b03169063a9059cbb906044016020604051808303816000875af1158015610b53573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b779190610f6e565b508282604051610b88929190610fa9565b604051908190038120907f60c9526b8f0e175eb21947f2eb757106195e0f6831bf27bdaac04369a8abbcfd90600090a250610bc36001600255565b5050565b610bcf610c38565b600180546001600160a01b0383166001600160a01b03199091168117909155610c006000546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6000546001600160a01b0316331461037c5760405163118cdaa760e01b81523360048201526024016103b2565b600180546001600160a01b03191690556103c481610cf1565b6002805403610ca057604051633ee5aeb560e01b815260040160405180910390fd5b60028055565b6000805b8351811015610ce55782848281518110610cc657610cc6610f2f565b602002602001015103610cdd576001915050610ceb565b600101610caa565b50600090505b92915050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b828054828255906000526020600020908101928215610d7c579160200282015b82811115610d7c578251825591602001919060010190610d61565b50610d88929150610d8c565b5090565b5b80821115610d885760008155600101610d8d565b80356001600160a01b0381168114610db857600080fd5b919050565b600060208284031215610dcf57600080fd5b610dd882610da1565b9392505050565b60008060408385031215610df257600080fd5b610dfb83610da1565b946020939093013593505050565b600060208284031215610e1b57600080fd5b5035919050565b60008083601f840112610e3457600080fd5b50813567ffffffffffffffff811115610e4c57600080fd5b6020830191508360208260051b8501011115610e6757600080fd5b9250929050565b60008060008060608587031215610e8457600080fd5b8435935060208501359250604085013567ffffffffffffffff811115610ea957600080fd5b610eb587828801610e22565b95989497509550505050565b600080600060608486031215610ed657600080fd5b505081359360208301359350604090920135919050565b60008060208385031215610f0057600080fd5b823567ffffffffffffffff811115610f1757600080fd5b610f2385828601610e22565b90969095509350505050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b80820180821115610ceb57610ceb610f45565b600060208284031215610f8057600080fd5b81518015158114610dd857600080fd5b600060018201610fa257610fa2610f45565b5060010190565b60006001600160fb1b03831115610fbf57600080fd5b8260051b8085843791909101939250505056fea264697066735822122003d8360f91520f9e6da6167c20ef046c0cf0673b9a2c65a5d10059a71797eb7064736f6c63430008180033

Verified Source Code Full Match

Compiler: v0.8.24+commit.e11b9ed9 EVM: paris Optimization: Yes (200 runs)
Staking.sol 280 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.24;

import {Ownable2Step, Ownable} from "lib/openzeppelin-contracts/contracts/access/Ownable2Step.sol";
import {ReentrancyGuard} from "lib/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol";
import {IERC20} from "lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";

/// @title Staking
/// @notice $BLOCK staking
contract Staking is Ownable2Step, ReentrancyGuard {
    /*==============================================================
                      CONSTANTS & IMMUTABLES
    ==============================================================*/

    /// @notice $BLOCK address
    IERC20 public immutable token;

    /*==============================================================
                       STORAGE VARIABLES
    ==============================================================*/

    struct Pool {
        uint256 poolId;
        uint256 amountLimit;
        uint256 amount;
        uint256[] lockupPeriods;
        bool paused;
        bool terminated;
    }

    struct Stake {
        uint256 poolId;
        uint256 amount;
        uint256 lockupPeriod;
        uint256 expiresAt;
        bool unstaked;
    }

    /// @notice Pool ID => Pool
    mapping(uint256 => Pool) public pools;

    /// @notice User => Stake[]
    mapping(address => Stake[]) public stakes;

    /// @notice User => Stake count
    mapping(address => uint256) public stakesCount;

    /*==============================================================
                            FUNCTIONS
    ==============================================================*/

    /// @notice Staking contract constructor
    /// @param _initialOwner Initial owner of the contract
    /// @param _token $BLOCK token address
    constructor(address _initialOwner, address _token) Ownable(_initialOwner) {
        if (_token == address(0)) {
            revert InvalidTokenAddressSet();
        }

        token = IERC20(_token);
    }

    /// @notice Stake $BLOCK tokens
    /// @param _poolId Pool ID
    /// @param _amount Amount of $BLOCK tokens to stake
    /// @param _lockupPeriod Lockup period in seconds
    function stake(
        uint256 _poolId,
        uint256 _amount,
        uint256 _lockupPeriod
    ) external nonReentrant {
        if (pools[_poolId].amountLimit == 0) {
            revert PoolDoesNotExist();
        }

        Pool memory pool = pools[_poolId];
        if (pool.terminated) {
            revert PoolIsTerminated();
        } else if (pool.paused) {
            revert PoolIsPaused();
        } else if (_amount + pool.amount > pools[_poolId].amountLimit) {
            revert ExceedsLimit();
        } else if (!_exists(pool.lockupPeriods, _lockupPeriod)) {
            revert InvalidLockupPeriod();
        }

        token.transferFrom(msg.sender, address(this), _amount);
        stakes[msg.sender].push(
            Stake({
                poolId: _poolId,
                amount: _amount,
                lockupPeriod: _lockupPeriod,
                expiresAt: block.timestamp + _lockupPeriod,
                unstaked: false
            })
        );

        stakesCount[msg.sender]++;
        pools[_poolId].amount += _amount;

        emit Staked(msg.sender, _poolId, _amount, _lockupPeriod);
    }

    /// @notice Unstake $BLOCK tokens
    /// @param _stakeIds Stake ID
    function unstake(uint256[] calldata _stakeIds) external nonReentrant {
        uint256 unstakeAmount = 0;

        for (uint256 i = 0; i < _stakeIds.length; i++) {
            Stake storage stake_ = stakes[msg.sender][_stakeIds[i]];
            if (stake_.unstaked) {
                revert AlreadyUnstaked();
            }

            Pool memory pool = pools[stake_.poolId];
            if (!pool.terminated && stake_.expiresAt > block.timestamp) {
                revert StakeNotExpired();
            }

            stake_.unstaked = true;
            unstakeAmount += stake_.amount;
        }

        token.transfer(msg.sender, unstakeAmount);

        emit Unstaked(_stakeIds);
    }

    /*==============================================================
                        ADMIN FUNCTIONS
    ==============================================================*/

    /// @notice Create a new pool
    /// @param _poolId Pool ID
    /// @param _amountLimit Total limit of the pool
    /// @param _lockupPeriods Lockup periods
    function createPool(uint256 _poolId, uint256 _amountLimit, uint256[] calldata _lockupPeriods) external onlyOwner {
        if (pools[_poolId].amountLimit != 0) {
            revert PoolAlreadyExists();
        } else if (_amountLimit == 0) {
            revert InvalidAmountLimitSet();
        }

        for (uint256 i = 0; i < _lockupPeriods.length; i++) {
            if (_lockupPeriods[i] == 0) {
                revert InvalidLockupPeriodSet();
            }
        }

        pools[_poolId] = Pool({
            poolId: _poolId,
            amountLimit: _amountLimit,
            lockupPeriods: _lockupPeriods,
            amount: 0,
            paused: false,
            terminated: false
        });
        emit PoolCreated(_poolId, _amountLimit);
    }

    /// @notice Pause a pool
    /// @param _poolId Pool ID
    function pausePool(uint256 _poolId) external onlyOwner {
        pools[_poolId].paused = true;
        emit PoolPaused(_poolId);
    }

    /// @notice Unpause a pool
    /// @param _poolId Pool ID
    function unpausePool(uint256 _poolId) external onlyOwner {
        pools[_poolId].paused = false;
        emit PoolUnpaused(_poolId);
    }

    /// @notice Terminate a pool
    /// @param _poolId Pool ID
    function terminatePool(uint256 _poolId) external onlyOwner {
        pools[_poolId].terminated = true;
        emit PoolTerminated(_poolId);
    }

    /*==============================================================
                      INTERNAL FUNCTIONS
    ==============================================================*/

    /// @notice Check if a lockup period exists
    /// @param _periods Lockup periods
    /// @param _period Lockup period
    function _exists(
        uint256[] memory _periods,
        uint256 _period
    ) internal pure returns (bool) {
        for (uint256 i = 0; i < _periods.length; i++) {
            if (_periods[i] == _period) {
                return true;
            }
        }
        return false;
    }

    /*==============================================================
                            EVENTS
    ==============================================================*/

    /// @notice Emitted when a pool is created
    /// @param poolId Pool ID
    /// @param amountLimit Total limit of the pool
    event PoolCreated(uint256 indexed poolId, uint256 indexed amountLimit);

    /// @notice Emitted when a pool is paused
    /// @param poolId Pool ID
    event PoolPaused(uint256 indexed poolId);

    /// @notice Emitted when a pool is unpaused
    /// @param poolId Pool ID
    event PoolUnpaused(uint256 indexed poolId);

    /// @notice Emitted when a pool is terminated
    /// @param poolId Pool ID
    event PoolTerminated(uint256 indexed poolId);

    /// @notice Emitted when a user stakes to a pool
    /// @param walletAddress Address of staker
    /// @param poolId Pool ID
    /// @param amount Amount of $BLOCK tokens staked
    /// @param lockupPeriod Lockup period
    event Staked(
        address indexed walletAddress,
        uint256 indexed poolId,
        uint256 amount,
        uint256 indexed lockupPeriod
    );

    /// @notice Emitted when a user unstakes from a pool
    /// @param stakeIds Stake IDs
    event Unstaked(uint256[] indexed stakeIds);

    /*==============================================================
                            ERRORS
    ==============================================================*/

    /// @notice Error when pool does not exist
    error PoolDoesNotExist();

    /// @notice Error when pool already exists
    error PoolAlreadyExists();

    /// @notice Error when pool is paused
    error PoolIsPaused();

    /// @notice Error when pool is terminated
    error PoolIsTerminated();

    /// @notice Error when pool amount limit is exceeded
    error ExceedsLimit();

    /// @notice Error when lockup period is invalid
    error InvalidLockupPeriod();

    /// @notice Error when stake is already unstaked
    error TransferFailed();

    /// @notice Error when stake is already unstaked
    error AlreadyUnstaked();

    /// @notice Error when stake is not expired
    error StakeNotExpired();

    /// @notice Error when stake does not exist
    error StakeDoesNotExist();

    /// @notice Error when adding invalid token address
    error InvalidTokenAddressSet();

    /// @notice Error when setting invalid amount limit
    error InvalidAmountLimitSet();

    /// @notice Error when setting invalid lockup period
    error InvalidLockupPeriodSet();
}
Context.sol 28 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

/**
 * @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;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}
Ownable.sol 100 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;

import {Context} from "../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.
 *
 * The initial owner is set to the address provided by the deployer. 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;

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(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 {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}
IERC20.sol 79 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the value of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 value) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 value) external returns (bool);
}
Ownable2Step.sol 59 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable2Step.sol)

pragma solidity ^0.8.20;

import {Ownable} from "./Ownable.sol";

/**
 * @dev Contract module which provides access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * The initial owner is specified at deployment time in the constructor for `Ownable`. This
 * can later be changed with {transferOwnership} and {acceptOwnership}.
 *
 * This module is used through inheritance. It will make available all functions
 * from parent (Ownable).
 */
abstract contract Ownable2Step is Ownable {
    address private _pendingOwner;

    event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Returns the address of the pending owner.
     */
    function pendingOwner() public view virtual returns (address) {
        return _pendingOwner;
    }

    /**
     * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual override onlyOwner {
        _pendingOwner = newOwner;
        emit OwnershipTransferStarted(owner(), newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual override {
        delete _pendingOwner;
        super._transferOwnership(newOwner);
    }

    /**
     * @dev The new owner accepts the ownership transfer.
     */
    function acceptOwnership() public virtual {
        address sender = _msgSender();
        if (pendingOwner() != sender) {
            revert OwnableUnauthorizedAccount(sender);
        }
        _transferOwnership(sender);
    }
}
ReentrancyGuard.sol 84 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)

pragma solidity ^0.8.20;

/**
 * @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;

    /**
     * @dev Unauthorized reentrant call.
     */
    error ReentrancyGuardReentrantCall();

    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 making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be NOT_ENTERED
        if (_status == ENTERED) {
            revert ReentrancyGuardReentrantCall();
        }

        // Any calls to nonReentrant after this point will fail
        _status = ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = NOT_ENTERED;
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return _status == ENTERED;
    }
}

Read Contract

owner 0x8da5cb5b → address
pendingOwner 0xe30c3978 → address
pools 0xac4afa38 → uint256, uint256, uint256, bool, bool
stakes 0x584b62a1 → uint256, uint256, uint256, uint256, bool
stakesCount 0x0e36e355 → uint256
token 0xfc0c546a → address

Write Contract 9 functions

These functions modify contract state and require a wallet transaction to execute.

acceptOwnership 0x79ba5097
No parameters
createPool 0x80abfb66
uint256 _poolId
uint256 _amountLimit
uint256[] _lockupPeriods
pausePool 0x5e8ead77
uint256 _poolId
renounceOwnership 0x715018a6
No parameters
stake 0xa638f2e2
uint256 _poolId
uint256 _amount
uint256 _lockupPeriod
terminatePool 0xd790366a
uint256 _poolId
transferOwnership 0xf2fde38b
address newOwner
unpausePool 0xb13ae804
uint256 _poolId
unstake 0xe449f341
uint256[] _stakeIds

Recent Transactions

No transactions found for this address