ETH Price: $2,375.57 (+8.58%)
 

More Info

Private Name Tags

Multichain Info

1 address found via
Transaction Hash
Block
From
To
Stake446868002026-04-14 10:35:471 hr ago1776162947IN
0x38AE5d95...e975a9150
0 ETH0.000000430.006
Stake446835532026-04-14 8:47:333 hrs ago1776156453IN
0x38AE5d95...e975a9150
0 ETH0.000000430.006
Stake446830522026-04-14 8:30:513 hrs ago1776155451IN
0x38AE5d95...e975a9150
0 ETH0.000000430.006
Stake446830232026-04-14 8:29:533 hrs ago1776155393IN
0x38AE5d95...e975a9150
0 ETH0.000000550.006
Stake446777272026-04-14 5:33:216 hrs ago1776144801IN
0x38AE5d95...e975a9150
0 ETH0.000000430.006
Stake446769492026-04-14 5:07:256 hrs ago1776143245IN
0x38AE5d95...e975a9150
0 ETH0.000000460.006
Stake446766172026-04-14 4:56:217 hrs ago1776142581IN
0x38AE5d95...e975a9150
0 ETH0.000000460.006
Stake446765952026-04-14 4:55:377 hrs ago1776142537IN
0x38AE5d95...e975a9150
0 ETH0.000000580.006
Stake446763552026-04-14 4:47:377 hrs ago1776142057IN
0x38AE5d95...e975a9150
0 ETH0.000000460.006
Stake446743992026-04-14 3:42:258 hrs ago1776138145IN
0x38AE5d95...e975a9150
0 ETH0.000000460.006
Stake446718302026-04-14 2:16:479 hrs ago1776133007IN
0x38AE5d95...e975a9150
0 ETH0.000000430.006
Stake446718062026-04-14 2:15:599 hrs ago1776132959IN
0x38AE5d95...e975a9150
0 ETH0.000000550.006
Stake446715782026-04-14 2:08:239 hrs ago1776132503IN
0x38AE5d95...e975a9150
0 ETH0.000000460.006
Stake446714532026-04-14 2:04:139 hrs ago1776132253IN
0x38AE5d95...e975a9150
0 ETH0.000000430.006
Stake446713742026-04-14 2:01:359 hrs ago1776132095IN
0x38AE5d95...e975a9150
0 ETH0.000000430.006
Stake446705112026-04-14 1:32:4910 hrs ago1776130369IN
0x38AE5d95...e975a9150
0 ETH0.000000430.006
Stake446703142026-04-14 1:26:1510 hrs ago1776129975IN
0x38AE5d95...e975a9150
0 ETH0.000000430.006
Stake446702692026-04-14 1:24:4510 hrs ago1776129885IN
0x38AE5d95...e975a9150
0 ETH0.000000430.006
Stake446692062026-04-14 0:49:1911 hrs ago1776127759IN
0x38AE5d95...e975a9150
0 ETH0.000000460.006
Stake446686292026-04-14 0:30:0511 hrs ago1776126605IN
0x38AE5d95...e975a9150
0 ETH0.000000430.006
Stake446679342026-04-14 0:06:5511 hrs ago1776125215IN
0x38AE5d95...e975a9150
0 ETH0.000000430.006
Stake446675192026-04-13 23:53:0512 hrs ago1776124385IN
0x38AE5d95...e975a9150
0 ETH0.000000430.006
Stake446672262026-04-13 23:43:1912 hrs ago1776123799IN
0x38AE5d95...e975a9150
0 ETH0.000000530.00695536
Stake446653442026-04-13 22:40:3513 hrs ago1776120035IN
0x38AE5d95...e975a9150
0 ETH0.000000430.006
Stake446651572026-04-13 22:34:2113 hrs ago1776119661IN
0x38AE5d95...e975a9150
0 ETH0.000000430.006
View all transactions

Parent Transaction Hash Block From To
View All Internal Transactions

Cross-Chain Transactions
Loading...
Loading

Similar Match Source Code
This contract matches the deployed Bytecode of the Source Code for Contract 0x808a1276...DFC7482f1
The constructor portion of the code might be different and could alter the actual behaviour of the contract

Contract Name:
BETRStaking

Compiler Version
v0.8.28+commit.7893614a

Optimization Enabled:
Yes with 200 runs

Other Settings:
cancun EvmVersion, MIT license

Contract Source Code (Solidity Standard Json-Input format)

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {InvalidInput, TokensTransferError} from "./common/error.sol";
import {Ownable} from "./common/Ownable.sol";
import {IBETRStakingEventHandler} from "./interfaces/IBETRStakingEventHandler.sol";
import {IBETRStakingStateProvider} from "./interfaces/IBETRStakingStateProvider.sol";

/*
 * @title BETRStaking
 * @author Mirko Nosenzo (@netnose)
 * @notice This contract is used to stake an ERC20 token
 */
contract BETRStaking is IBETRStakingStateProvider, Ownable {
    IERC20 public immutable stakingToken;
    uint256 public totalStakedAmount;
    mapping(address => uint256) public stakedAmount;
    bool public isStakingPaused;

    IBETRStakingEventHandler[] public rewarders;

    /*
     * @notice Constructor
     * @param _owner The owner of the contract
     * @param _stakingToken The ERC20 token to stake
     */
    constructor(address _owner, address _stakingToken) Ownable(_owner) {
        if (_stakingToken == address(0)) revert InvalidInput();
        
        stakingToken = IERC20(_stakingToken);
        isStakingPaused = false;
    }

    /*
     * @title NotEnoughStakedAmount
     * @notice Error to check if the staked amount is less than the amount to unstake
     * @param available The available amount
     * @param requested The requested amount
     */
    error NotEnoughStakedAmount(uint256 available, uint256 requested);

    /*
     * @title StakingPaused
     * @notice Error to check if the staking is paused
     */
    error StakingPaused();

    /*
     * @title RewarderAdded
     * @notice Event to notify when a rewarder is added
     * @param rewarder The address of the rewarder
     */
    event RewarderAdded(address indexed rewarder);

    /*
     * @title RewarderRemoved
     * @notice Event to notify when a rewarder is removed
     * @param rewarder The address of the rewarder
     */
    event RewarderRemoved(address indexed rewarder);

    /*
     * @title Staked
     * @notice Event to notify when an address has staked
     * @param staker The address that staked
     * @param amount The amount of tokens staked
     */
    event Staked(address indexed staker, uint256 indexed amount);

    /*
     * @title Unstaked
     * @notice Event to notify when an address has unstaked
     * @param staker The address that unstaked
     * @param amount The amount of tokens unstaked
     */
    event Unstaked(address indexed staker, uint256 indexed amount);

    /*
     * @title StakingPausedSet
     * @notice Event to notify when the staking paused state is set
     * @param isStakingPaused The new staking paused state
     */
    event StakingPausedSet(bool indexed isStakingPaused);

    /*
     * @title _unstake
     * @notice Internal function to unstake tokens for a user
     * @param _user The user to unstake tokens for
     * @param _amount The amount to unstake (0 for all)
     * @return The amount actually unstaked
     */
    function _unstake(address _user, uint256 _amount) internal returns (uint256) {
        if (_user == address(0)) revert InvalidInput();
        
        uint256 userStaked = stakedAmount[_user];
        uint256 amountToUnstake = _amount == 0 ? userStaked : _amount;
        if (amountToUnstake == 0) return 0;

        if (amountToUnstake > userStaked) {
            revert NotEnoughStakedAmount(userStaked, amountToUnstake);
        }
        
        uint256 oldStakedAmount = stakedAmount[_user];
        stakedAmount[_user] -= amountToUnstake;
        uint256 newStakedAmount = stakedAmount[_user];
        for (uint256 i = 0; i < rewarders.length; i++) {
            rewarders[i].onStakeChanged(_user, oldStakedAmount, newStakedAmount);
        }

        try stakingToken.transfer(_user, amountToUnstake) returns (bool success) {
            if (!success) revert TokensTransferError();
        } catch {
            revert TokensTransferError();
        }

        emit Unstaked(_user, amountToUnstake);
        
        return amountToUnstake;
    }

    /*
     * @title stake
     * @notice Stake an ERC20 token
     * @param _amount The amount of ERC20 tokens to stake
     */
    function stake(uint256 _amount) public {
        if (isStakingPaused) revert StakingPaused();
        if (_amount == 0) revert InvalidInput();

        uint256 oldStakedAmount = stakedAmount[msg.sender];
        stakedAmount[msg.sender] += _amount;
        totalStakedAmount += _amount;
        uint256 newStakedAmount = stakedAmount[msg.sender];
        for (uint256 i = 0; i < rewarders.length; i++) {
            rewarders[i].onStakeChanged(msg.sender, oldStakedAmount, newStakedAmount);
        }

        try stakingToken.transferFrom(msg.sender, address(this), _amount) returns (bool success) {
            if (!success) revert TokensTransferError();
        } catch {
            revert TokensTransferError();
        }

        emit Staked(msg.sender, _amount);
    }

    /*
     * @title stakeFor
     * @notice Function to stake tokens for a user
     * @param _user The user to stake tokens for
     * @param _amount The amount of tokens to stake
     */
    function stakeFor(address _user, uint256 _amount) public {
        if (isStakingPaused) revert StakingPaused();
        if (_user == address(0)) revert InvalidInput();
        if (_amount == 0) revert InvalidInput();
        
        uint256 oldStakedAmount = stakedAmount[_user];
        stakedAmount[_user] += _amount;
        totalStakedAmount += _amount;
        uint256 newStakedAmount = stakedAmount[_user];
        for (uint256 i = 0; i < rewarders.length; i++) {
            rewarders[i].onStakeChanged(_user, oldStakedAmount, newStakedAmount);
        }

        try stakingToken.transferFrom(msg.sender, address(this), _amount) returns (bool success) {
            if (!success) revert TokensTransferError();
        } catch {
            revert TokensTransferError();
        }

        emit Staked(_user, _amount);
    }

    /*
     * @title unstake
     * @notice Unstake an ERC20 token
     * @param _amount The amount of ERC20 tokens to unstake
     */
    function unstake(uint256 _amount) public {
        if (isStakingPaused) revert StakingPaused();
        if (_amount == 0) revert InvalidInput();
        
        uint256 unstakedAmount = _unstake(msg.sender, _amount);
        totalStakedAmount -= unstakedAmount;
    }

    /*
     * @title batchUnstake
     * @notice Admin function to unstake tokens for multiple users (owner only)
     * @param _users Array of users to unstake tokens for
     * @param _amounts Array of amounts to unstake (0 for all, must match _users length)
     * @dev This function bypasses the staking pause for emergency situations
     */
    function batchUnstake(address[] calldata _users, uint256[] calldata _amounts) public onlyOwner {
        if (_users.length != _amounts.length) revert InvalidInput();
        if (_users.length == 0) revert InvalidInput();
        
        uint256 totalUnstaked = 0;
        
        for (uint256 i = 0; i < _users.length; i++) {
            address user = _users[i];
            uint256 amount = _amounts[i];
            
            uint256 unstakedAmount = _unstake(user, amount);
            totalUnstaked += unstakedAmount;
        }
        
        totalStakedAmount -= totalUnstaked;
    }

    /*
     * @title setStakingPaused
     * @notice Function to set the staking paused state
     * @param _isStakingPaused The new staking paused state
     */
    function setStakingPaused(bool _isStakingPaused) public onlyOwner {
        isStakingPaused = _isStakingPaused;
        emit StakingPausedSet(_isStakingPaused);
    }

    /*
     * @title isRewarder
     * @notice Function to check if an address is a rewarder
     * @param _rewarder The address of the rewarder
     * @return True if the address is a rewarder, false otherwise
     */
    function isRewarder(address _rewarder) public view returns (bool) {
        for (uint256 i = 0; i < rewarders.length; i++) {
            if (address(rewarders[i]) == _rewarder) {
                return true;
            }
        }
        return false;
    }

    /*
     * @title addRewarder
     * @notice Function to add a rewarder
     * @param _rewarder The address of the rewarder
     */
    function addRewarder(address _rewarder) public onlyOwner {
        if (_rewarder == address(0)) revert InvalidInput();
        if (isRewarder(_rewarder)) revert InvalidInput();
        rewarders.push(IBETRStakingEventHandler(_rewarder));
        emit RewarderAdded(_rewarder);
    }

    /*
     * @title removeRewarder
     * @notice Function to remove a rewarder
     * @param _rewarder The address of the rewarder
     */
    function removeRewarder(address _rewarder) public onlyOwner {
        for (uint256 i = 0; i < rewarders.length; i++) {
            if (address(rewarders[i]) == _rewarder) {
                rewarders[i] = rewarders[rewarders.length - 1];
                rewarders.pop();
                emit RewarderRemoved(_rewarder);
                return;
            }
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC-20 standard as defined in the ERC.
 */
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);
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {Ownable} from "./common/Ownable.sol";
import {IBETRStakingEventHandler} from "./interfaces/IBETRStakingEventHandler.sol";
import {IBETRStakingStateProvider} from "./interfaces/IBETRStakingStateProvider.sol";
import {InvalidInput, TokensTransferError} from "./common/error.sol";

/*
 * @title BETRRewards
 * @author Mirko Nosenzo (@netnose)
 * @notice This contract is used to manage rewards for the staking contract
 */
contract BETRRewards is IBETRStakingEventHandler, Ownable {
    mapping(address => uint256) private _debts;
    mapping(address => uint256) private _credits;

    uint256 public constant PRECISION = 1e18;

    IBETRStakingStateProvider public stakingContract;
    IERC20 public rewardToken;
    uint256 public rewardAccumulatedPerStakedToken;
    uint256 public totalRewardsClaimed;
    uint256 public totalRewardsClaimable;
    bool public isRewardingPaused;

    /*
     * @notice Constructor
     * @param _owner The owner of the contract
     * @param _stakingContract The address of the staking contract
     * @param _rewardToken The address of the reward token
     */
    constructor(address _owner, address _stakingContract, address _rewardToken) Ownable(_owner) {
        if (_stakingContract == address(0)) revert InvalidInput();
        if (_rewardToken == address(0)) revert InvalidInput();

        stakingContract = IBETRStakingStateProvider(_stakingContract);
        rewardToken = IERC20(_rewardToken);
    }

    /*
     * @title RewardingPaused
     * @notice Error to check if the rewarding is paused
     */
    error RewardingPaused();

    /*
     * @title NoClaimableReward
     * @notice Error to check if there is no claimable reward
     * @param _staker The address of the staker
     */
    error NoClaimableReward(address _staker);

    /*
     * @title NoStakedAmount
     * @notice Error to check if there is no staked amount
     */
    error NoStakedAmount();

    /*
     * @title NotStakingContract
     * @notice Error to check if the caller is not the staking contract
     */
    error NotStakingContract();

    /*
     * @title StakingContractNotRewarder
     * @notice Error to check if the caller is not a rewarder
     */
    error StakingContractNotRewarder();

    /*
     * @title RewardingPausedSet
     * @notice Event to notify when the rewarding is paused
     * @param _isRewardingPaused The new rewarding paused state
     */
    event RewardingPausedSet(bool indexed _isRewardingPaused);

    /*
     * @title RewardAdded
     * @notice Event to notify when a reward is added
     * @param _amount The amount of the reward
     */
    event RewardAdded(uint256 _amount);

    /*
     * @title RewardClaimed
     * @notice Event to notify when a reward is claimed
     * @param _staker The address of the staker
     * @param _amount The amount of the reward
     */
    event RewardClaimed(address indexed _staker, uint256 _amount);

    /*
     * @title onlyStakingContract
     * @notice Modifier to check if the caller is the staking contract
     */
    modifier onlyStakingContract() {
        if (msg.sender != address(stakingContract)) revert NotStakingContract();
        _;
    }

    /*
     * @title _claim
     * @notice Function to claim a reward
     * @param _user The address of the user
     */
    function _claim(address _user, uint256 _stakedAmount) internal {
        if (_user == address(0)) revert InvalidInput();

        uint256 rewardAmount = rewardAccumulatedPerStakedToken * _stakedAmount / PRECISION;
        uint256 actualRewardAmount = rewardAmount - _debts[_user] + _credits[_user];
        if (actualRewardAmount == 0) revert NoClaimableReward(_user);

        _debts[_user] = rewardAmount;
        _credits[_user] = 0;
        totalRewardsClaimed += actualRewardAmount;
        totalRewardsClaimable -= actualRewardAmount;

        try rewardToken.transfer(_user, actualRewardAmount) returns (bool success) {
            if (!success) revert TokensTransferError();
        } catch {
            revert TokensTransferError();
        }
        
        emit RewardClaimed(_user, actualRewardAmount);
    }

    /*
     * @title claimable
     * @notice Function to get the claimable rewards for a staker
     * @param _staker The address of the staker
     * @return _amount The amount of the claimable rewards
     */
    function claimable(address _staker) public view returns (uint256 _amount) {
        uint256 rewardAmount = rewardAccumulatedPerStakedToken * stakingContract.stakedAmount(_staker) / PRECISION;
        uint256 actualRewardAmount = rewardAmount - _debts[_staker] + _credits[_staker];
        return actualRewardAmount;
    }

    /*
     * @title claimable
     * @notice Function to get the claimable rewards for the caller
     * @return _amount The amount of the claimable rewards
     */
    function claimable() public view returns (uint256 _amount) {
        return claimable(msg.sender);
    }

    /*
     * @title addReward
     * @notice Function to add a reward
     * @param _amount The amount of the reward
     */
    function addReward(uint256 _amount) public {
        if (isRewardingPaused) revert RewardingPaused();
        if (_amount == 0) revert InvalidInput();
        if (!stakingContract.isRewarder(address(this))) revert StakingContractNotRewarder();

        uint256 totalStakedAmount = stakingContract.totalStakedAmount();
        if (totalStakedAmount == 0) revert NoStakedAmount();

        rewardAccumulatedPerStakedToken += (_amount * PRECISION) / totalStakedAmount;
        totalRewardsClaimable += _amount;

        try rewardToken.transferFrom(msg.sender, address(this), _amount) returns (bool success) {
            if (!success) revert TokensTransferError();
        } catch {
            revert TokensTransferError();
        }

        emit RewardAdded(_amount);
    }

    /*
     * @title claim
     * @notice Function to claim a reward
     */
    function claim() public {
        if (isRewardingPaused) revert RewardingPaused();
        _claim(msg.sender, stakingContract.stakedAmount(msg.sender));
    }

    /*
     * @title batchClaim
     * @notice Admin function to claim all rewards for multiple users (owner only)
     * @param _users Array of addresses of the users to claim rewards for
     * @dev This function bypasses the rewarding pause for emergency situations
     */
    function batchClaim(address[] memory _users) public onlyOwner {
        for (uint256 i = 0; i < _users.length; i++) {
            _claim(_users[i], stakingContract.stakedAmount(_users[i]));
        }
    }

    /*
     * @title setStakingPaused
     * @notice Function to set the staking paused state
     * @param _isRewardingPaused The new rewarding paused state
     */
    function setRewardingPaused(bool _isRewardingPaused) public onlyOwner {
        isRewardingPaused = _isRewardingPaused;
        emit RewardingPausedSet(_isRewardingPaused);
    }

    /*
     * @title onStakeChanged
     * @notice Function to handle the stake changed event
     * @param _user The address of the user
     * @param _oldAmount The old amount of the stake
     * @param _newAmount The new amount of the stake
     */
    function onStakeChanged(address _user, uint256 _oldAmount, uint256 _newAmount) public onlyStakingContract {
        if (_user == address(0)) revert InvalidInput();
        if (_oldAmount == _newAmount) return;

        uint256 rewardAmount = rewardAccumulatedPerStakedToken * _oldAmount / PRECISION;
        uint256 actualRewardAmount = rewardAmount - _debts[_user] + _credits[_user];
        _credits[_user] = actualRewardAmount;
        _debts[_user] = rewardAccumulatedPerStakedToken * _newAmount / PRECISION;
    }
}

File 4 of 7 : error.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

/*
 * @title InvalidInput
 * @notice Error to check if the input is invalid
 */
error InvalidInput();

/*
 * @title TokensTransferError
 * @notice Error to check if the transfer of tokens fails
 */
error TokensTransferError();

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {InvalidInput} from "./error.sol";

/*
 * @title Ownable
 * @author Mirko Nosenzo (@netnose)
 * @notice This contract is used to manage the ownership of the contract
 */
abstract contract Ownable {
    address public owner;
    address public proposedOwner;

    /*
     * @notice Constructor
     * @param _owner The owner of the contract
     */
    constructor(address _owner) {
        if (_owner == address(0)) revert InvalidInput();
        owner = _owner;
    }

    /*
    * @title NotOwner
    * @notice Error to check if the caller is the owner
    */
    error NotOwner();

    /*
    * @title NotProposedOwner
    * @notice Error to check if the caller is the proposed owner
    */
    error NotProposedOwner();

    /*
     * @title OwnershipTransferred
     * @notice Event to notify when ownership is transferred
     * @param previousOwner The previous owner
     * @param newOwner The new owner
     */
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /*
     * @title onlyOwner
     * @notice Modifier to check if the caller is the owner
     */
    modifier onlyOwner() {
        if (msg.sender != owner) revert NotOwner();
        _;
    }

    /*
     * @title onlyProposedOwner
     * @notice Modifier to check if the caller is the proposed owner
     */
    modifier onlyProposedOwner() {
        if (msg.sender != proposedOwner) revert NotProposedOwner();
        _;
    }

    /*
     * @title setProposedOwner
     * @notice Function to set the proposed owner
     * @param _proposedOwner The proposed owner
     */
    function setProposedOwner(address _proposedOwner) public onlyOwner {
        if (_proposedOwner == address(0)) revert InvalidInput();
        proposedOwner = _proposedOwner;
    }

    /*
     * @title acceptOwnership
     * @notice Function to accept the ownership
     */
    function acceptOwnership() public onlyProposedOwner {
        emit OwnershipTransferred(owner, proposedOwner);
        owner = proposedOwner;
        proposedOwner = address(0);
    }

    /*
     * @title cancelProposedOwnership
     * @notice Function to cancel the proposed ownership
     */
    function cancelProposedOwnership() public onlyOwner {
        proposedOwner = address(0);
    }
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

/*
 * @title IBETRStakingEventHandler
 * @notice Interface for the staking event handler
 */
interface IBETRStakingEventHandler {
    /*
     * @title onStakeChanged
     * @notice Function to handle the stake changed event
     * @param _user The user who changed the stake
     * @param _oldAmount The old amount of stake
     * @param _newAmount The new amount of stake
     */
    function onStakeChanged(address _user, uint256 _oldAmount, uint256 _newAmount) external;
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

/*
 * @title IBETRStakingStateProvider
 * @notice Interface for the staking state provider
 */
interface IBETRStakingStateProvider {
    /*
     * @title isRewarder
     * @notice Function to check if an address is a rewarder
     * @param _contract The address to check
     * @return isRewarder True if the address is a rewarder, false otherwise
     */
    function isRewarder(address _contract) external view returns (bool);

    /*
     * @title stakingToken
     * @notice Function to get the staking token
     * @return stakingToken The staking token
     */
    function stakingToken() external view returns (IERC20);
    
    /*
     * @title totalStakedAmount
     * @notice Function to get the total amount of tokens staked
     * @return totalStakedAmount The total amount of tokens staked
     */
    function totalStakedAmount() external view returns (uint256);

    /*
     * @title stakedAmount
     * @notice Function to get the amount of tokens staked by a user
     * @param _user The address of the user
     * @return stakedAmount The amount of tokens staked by the user
     */
    function stakedAmount(address _user) external view returns (uint256);
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "evmVersion": "cancun",
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_stakingToken","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"InvalidInput","type":"error"},{"inputs":[{"internalType":"uint256","name":"available","type":"uint256"},{"internalType":"uint256","name":"requested","type":"uint256"}],"name":"NotEnoughStakedAmount","type":"error"},{"inputs":[],"name":"NotOwner","type":"error"},{"inputs":[],"name":"NotProposedOwner","type":"error"},{"inputs":[],"name":"StakingPaused","type":"error"},{"inputs":[],"name":"TokensTransferError","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"rewarder","type":"address"}],"name":"RewarderAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"rewarder","type":"address"}],"name":"RewarderRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Staked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bool","name":"isStakingPaused","type":"bool"}],"name":"StakingPausedSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Unstaked","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_rewarder","type":"address"}],"name":"addRewarder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_users","type":"address[]"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"}],"name":"batchUnstake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cancelProposedOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_rewarder","type":"address"}],"name":"isRewarder","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isStakingPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proposedOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_rewarder","type":"address"}],"name":"removeRewarder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rewarders","outputs":[{"internalType":"contract IBETRStakingEventHandler","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_proposedOwner","type":"address"}],"name":"setProposedOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_isStakingPaused","type":"bool"}],"name":"setStakingPaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"stakeFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"stakedAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stakingToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalStakedAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"unstake","outputs":[],"stateMutability":"nonpayable","type":"function"}]

0x60a060405234801561000f575f5ffd5b506040516112ad3803806112ad83398101604081905261002e916100c7565b816001600160a01b0381166100565760405163b4fa3fb360e01b815260040160405180910390fd5b5f80546001600160a01b0319166001600160a01b0392831617905581166100905760405163b4fa3fb360e01b815260040160405180910390fd5b6001600160a01b0316608052506004805460ff191690556100f8565b80516001600160a01b03811681146100c2575f5ffd5b919050565b5f5f604083850312156100d8575f5ffd5b6100e1836100ac565b91506100ef602084016100ac565b90509250929050565b6080516111886101255f395f81816101c7015281816104f701528181610aad0152610e9d01526111885ff3fe608060405234801561000f575f5ffd5b5060043610610111575f3560e01c806379ba50971161009e578063a694fc3a1161006e578063a694fc3a14610236578063cb908b9d14610249578063d153b60c1461025c578063f99318551461026f578063fcf8770f1461028e575f5ffd5b806379ba5097146102015780637d9e6ca1146102095780638da5cb5b146102115780638e478cab14610223575f5ffd5b80633d564e49116100e45780633d564e49146101725780634666d35b14610185578063567e98f91461019857806356d3590b146101af57806372f702f3146101c2575f5ffd5b806315b31bbb146101155780631ea7ca891461012a5780632e17de781461014c5780632ee409081461015f575b5f5ffd5b610128610123366004610f8c565b6102a1565b005b6004546101379060ff1681565b60405190151581526020015b60405180910390f35b61012861015a366004610fae565b610307565b61012861016d366004610fe0565b610372565b610128610180366004611050565b6105da565b6101286101933660046110bc565b6106dc565b6101a160025481565b604051908152602001610143565b6101286101bd3660046110bc565b61074f565b6101e97f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610143565b61012861083e565b6101286108cb565b5f546101e9906001600160a01b031681565b6101376102313660046110bc565b610907565b610128610244366004610fae565b610963565b6101286102573660046110bc565b610b86565b6001546101e9906001600160a01b031681565b6101a161027d3660046110bc565b60036020525f908152604090205481565b6101e961029c366004610fae565b610cde565b5f546001600160a01b031633146102cb576040516330cd747160e01b815260040160405180910390fd5b6004805460ff19168215159081179091556040517f0205b3e5bce42c5f218291d233159653129761bd7d9e11218182e65253f3ae8b905f90a250565b60045460ff161561032b576040516326d1807b60e01b815260040160405180910390fd5b805f0361034b5760405163b4fa3fb360e01b815260040160405180910390fd5b5f6103563383610d06565b90508060025f82825461036991906110e9565b90915550505050565b60045460ff1615610396576040516326d1807b60e01b815260040160405180910390fd5b6001600160a01b0382166103bd5760405163b4fa3fb360e01b815260040160405180910390fd5b805f036103dd5760405163b4fa3fb360e01b815260040160405180910390fd5b6001600160a01b0382165f90815260036020526040812080549183919061040483856110fc565b925050819055508160025f82825461041c91906110fc565b90915550506001600160a01b0383165f90815260036020526040812054905b6005548110156104d457600581815481106104585761045861110f565b5f91825260209091200154604051630d7c9d9b60e41b81526001600160a01b03878116600483015260248201869052604482018590529091169063d7c9d9b0906064015f604051808303815f87803b1580156104b2575f5ffd5b505af11580156104c4573d5f5f3e3d5ffd5b50506001909201915061043b9050565b506040516323b872dd60e01b8152336004820152306024820152604481018490527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906323b872dd906064016020604051808303815f875af1925050508015610563575060408051601f3d908101601f1916820190925261056091810190611123565b60015b61058057604051630389c7a160e51b815260040160405180910390fd5b8061059e57604051630389c7a160e51b815260040160405180910390fd5b5060405183906001600160a01b038616907f9e71bc8eea02a63969f509818f2dafb9254532904319f9dbda79b67bd34a5f3d905f90a350505050565b5f546001600160a01b03163314610604576040516330cd747160e01b815260040160405180910390fd5b8281146106245760405163b4fa3fb360e01b815260040160405180910390fd5b5f8390036106455760405163b4fa3fb360e01b815260040160405180910390fd5b5f805b848110156106be575f8686838181106106635761066361110f565b905060200201602081019061067891906110bc565b90505f85858481811061068d5761068d61110f565b9050602002013590505f6106a18383610d06565b90506106ad81866110fc565b945050600190920191506106489050565b508060025f8282546106d091906110e9565b90915550505050505050565b5f546001600160a01b03163314610706576040516330cd747160e01b815260040160405180910390fd5b6001600160a01b03811661072d5760405163b4fa3fb360e01b815260040160405180910390fd5b600180546001600160a01b0319166001600160a01b0392909216919091179055565b5f546001600160a01b03163314610779576040516330cd747160e01b815260040160405180910390fd5b6001600160a01b0381166107a05760405163b4fa3fb360e01b815260040160405180910390fd5b6107a981610907565b156107c75760405163b4fa3fb360e01b815260040160405180910390fd5b600580546001810182555f9182527f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db00180546001600160a01b0319166001600160a01b03841690811790915560405190917f9dfd431959d2d3358e3eb909555ad574123ea5881ff0e05a80f66d4984710c1b91a250565b6001546001600160a01b0316331461086957604051630f22ca5f60e01b815260040160405180910390fd5b6001545f80546040516001600160a01b0393841693909116917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600180545f80546001600160a01b03199081166001600160a01b03841617909155169055565b5f546001600160a01b031633146108f5576040516330cd747160e01b815260040160405180910390fd5b600180546001600160a01b0319169055565b5f805b60055481101561095b57826001600160a01b0316600582815481106109315761093161110f565b5f918252602090912001546001600160a01b0316036109535750600192915050565b60010161090a565b505f92915050565b60045460ff1615610987576040516326d1807b60e01b815260040160405180910390fd5b805f036109a75760405163b4fa3fb360e01b815260040160405180910390fd5b335f9081526003602052604081208054918391906109c583856110fc565b925050819055508160025f8282546109dd91906110fc565b9091555050335f90815260036020526040812054905b600554811015610a8a5760058181548110610a1057610a1061110f565b5f91825260209091200154604051630d7c9d9b60e41b815233600482015260248101859052604481018490526001600160a01b039091169063d7c9d9b0906064015f604051808303815f87803b158015610a68575f5ffd5b505af1158015610a7a573d5f5f3e3d5ffd5b5050600190920191506109f39050565b506040516323b872dd60e01b8152336004820152306024820152604481018490527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906323b872dd906064016020604051808303815f875af1925050508015610b19575060408051601f3d908101601f19168201909252610b1691810190611123565b60015b610b3657604051630389c7a160e51b815260040160405180910390fd5b80610b5457604051630389c7a160e51b815260040160405180910390fd5b50604051839033907f9e71bc8eea02a63969f509818f2dafb9254532904319f9dbda79b67bd34a5f3d905f90a3505050565b5f546001600160a01b03163314610bb0576040516330cd747160e01b815260040160405180910390fd5b5f5b600554811015610cd957816001600160a01b031660058281548110610bd957610bd961110f565b5f918252602090912001546001600160a01b031603610cd15760058054610c02906001906110e9565b81548110610c1257610c1261110f565b5f91825260209091200154600580546001600160a01b039092169183908110610c3d57610c3d61110f565b905f5260205f20015f6101000a8154816001600160a01b0302191690836001600160a01b031602179055506005805480610c7957610c7961113e565b5f8281526020812082015f1990810180546001600160a01b03191690559091019091556040516001600160a01b038416917fce699c579f0b70ea4ccd6a4b38be26726a2c248b89c7102ccbc5d0f3060ef6d091a25050565b600101610bb2565b505b50565b60058181548110610ced575f80fd5b5f918252602090912001546001600160a01b0316905081565b5f6001600160a01b038316610d2e5760405163b4fa3fb360e01b815260040160405180910390fd5b6001600160a01b0383165f90815260036020526040812054908315610d535783610d55565b815b9050805f03610d68575f92505050610f79565b81811115610d97576040516388533e8360e01b8152600481018390526024810182905260440160405180910390fd5b6001600160a01b0385165f908152600360205260408120805491839190610dbe83856110e9565b90915550506001600160a01b0386165f90815260036020526040812054905b600554811015610e765760058181548110610dfa57610dfa61110f565b5f91825260209091200154604051630d7c9d9b60e41b81526001600160a01b038a8116600483015260248201869052604482018590529091169063d7c9d9b0906064015f604051808303815f87803b158015610e54575f5ffd5b505af1158015610e66573d5f5f3e3d5ffd5b505060019092019150610ddd9050565b5060405163a9059cbb60e01b81526001600160a01b038881166004830152602482018590527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016020604051808303815f875af1925050508015610f01575060408051601f3d908101601f19168201909252610efe91810190611123565b60015b610f1e57604051630389c7a160e51b815260040160405180910390fd5b80610f3c57604051630389c7a160e51b815260040160405180910390fd5b5060405183906001600160a01b038916907f0f5bb82176feb1b5e747e28471aa92156a04d9f3ab9f45f28e2d704232b93f75905f90a35090925050505b92915050565b8015158114610cdb575f5ffd5b5f60208284031215610f9c575f5ffd5b8135610fa781610f7f565b9392505050565b5f60208284031215610fbe575f5ffd5b5035919050565b80356001600160a01b0381168114610fdb575f5ffd5b919050565b5f5f60408385031215610ff1575f5ffd5b610ffa83610fc5565b946020939093013593505050565b5f5f83601f840112611018575f5ffd5b50813567ffffffffffffffff81111561102f575f5ffd5b6020830191508360208260051b8501011115611049575f5ffd5b9250929050565b5f5f5f5f60408587031215611063575f5ffd5b843567ffffffffffffffff811115611079575f5ffd5b61108587828801611008565b909550935050602085013567ffffffffffffffff8111156110a4575f5ffd5b6110b087828801611008565b95989497509550505050565b5f602082840312156110cc575f5ffd5b610fa782610fc5565b634e487b7160e01b5f52601160045260245ffd5b81810381811115610f7957610f796110d5565b80820180821115610f7957610f796110d5565b634e487b7160e01b5f52603260045260245ffd5b5f60208284031215611133575f5ffd5b8151610fa781610f7f565b634e487b7160e01b5f52603160045260245ffdfea2646970667358221220cedbb2e2eb2168153c9a2a3ebaf8a4292286c2df126f9ab103e2f3a7643d159a64736f6c634300081c0033000000000000000000000000cf965a96d55476e7345e948601921207549c0393000000000000000000000000774eaefe73df7959496ac92a77279a8d7d690b07

Deployed Bytecode

0x608060405234801561000f575f5ffd5b5060043610610111575f3560e01c806379ba50971161009e578063a694fc3a1161006e578063a694fc3a14610236578063cb908b9d14610249578063d153b60c1461025c578063f99318551461026f578063fcf8770f1461028e575f5ffd5b806379ba5097146102015780637d9e6ca1146102095780638da5cb5b146102115780638e478cab14610223575f5ffd5b80633d564e49116100e45780633d564e49146101725780634666d35b14610185578063567e98f91461019857806356d3590b146101af57806372f702f3146101c2575f5ffd5b806315b31bbb146101155780631ea7ca891461012a5780632e17de781461014c5780632ee409081461015f575b5f5ffd5b610128610123366004610f8c565b6102a1565b005b6004546101379060ff1681565b60405190151581526020015b60405180910390f35b61012861015a366004610fae565b610307565b61012861016d366004610fe0565b610372565b610128610180366004611050565b6105da565b6101286101933660046110bc565b6106dc565b6101a160025481565b604051908152602001610143565b6101286101bd3660046110bc565b61074f565b6101e97f000000000000000000000000774eaefe73df7959496ac92a77279a8d7d690b0781565b6040516001600160a01b039091168152602001610143565b61012861083e565b6101286108cb565b5f546101e9906001600160a01b031681565b6101376102313660046110bc565b610907565b610128610244366004610fae565b610963565b6101286102573660046110bc565b610b86565b6001546101e9906001600160a01b031681565b6101a161027d3660046110bc565b60036020525f908152604090205481565b6101e961029c366004610fae565b610cde565b5f546001600160a01b031633146102cb576040516330cd747160e01b815260040160405180910390fd5b6004805460ff19168215159081179091556040517f0205b3e5bce42c5f218291d233159653129761bd7d9e11218182e65253f3ae8b905f90a250565b60045460ff161561032b576040516326d1807b60e01b815260040160405180910390fd5b805f0361034b5760405163b4fa3fb360e01b815260040160405180910390fd5b5f6103563383610d06565b90508060025f82825461036991906110e9565b90915550505050565b60045460ff1615610396576040516326d1807b60e01b815260040160405180910390fd5b6001600160a01b0382166103bd5760405163b4fa3fb360e01b815260040160405180910390fd5b805f036103dd5760405163b4fa3fb360e01b815260040160405180910390fd5b6001600160a01b0382165f90815260036020526040812080549183919061040483856110fc565b925050819055508160025f82825461041c91906110fc565b90915550506001600160a01b0383165f90815260036020526040812054905b6005548110156104d457600581815481106104585761045861110f565b5f91825260209091200154604051630d7c9d9b60e41b81526001600160a01b03878116600483015260248201869052604482018590529091169063d7c9d9b0906064015f604051808303815f87803b1580156104b2575f5ffd5b505af11580156104c4573d5f5f3e3d5ffd5b50506001909201915061043b9050565b506040516323b872dd60e01b8152336004820152306024820152604481018490527f000000000000000000000000774eaefe73df7959496ac92a77279a8d7d690b076001600160a01b0316906323b872dd906064016020604051808303815f875af1925050508015610563575060408051601f3d908101601f1916820190925261056091810190611123565b60015b61058057604051630389c7a160e51b815260040160405180910390fd5b8061059e57604051630389c7a160e51b815260040160405180910390fd5b5060405183906001600160a01b038616907f9e71bc8eea02a63969f509818f2dafb9254532904319f9dbda79b67bd34a5f3d905f90a350505050565b5f546001600160a01b03163314610604576040516330cd747160e01b815260040160405180910390fd5b8281146106245760405163b4fa3fb360e01b815260040160405180910390fd5b5f8390036106455760405163b4fa3fb360e01b815260040160405180910390fd5b5f805b848110156106be575f8686838181106106635761066361110f565b905060200201602081019061067891906110bc565b90505f85858481811061068d5761068d61110f565b9050602002013590505f6106a18383610d06565b90506106ad81866110fc565b945050600190920191506106489050565b508060025f8282546106d091906110e9565b90915550505050505050565b5f546001600160a01b03163314610706576040516330cd747160e01b815260040160405180910390fd5b6001600160a01b03811661072d5760405163b4fa3fb360e01b815260040160405180910390fd5b600180546001600160a01b0319166001600160a01b0392909216919091179055565b5f546001600160a01b03163314610779576040516330cd747160e01b815260040160405180910390fd5b6001600160a01b0381166107a05760405163b4fa3fb360e01b815260040160405180910390fd5b6107a981610907565b156107c75760405163b4fa3fb360e01b815260040160405180910390fd5b600580546001810182555f9182527f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db00180546001600160a01b0319166001600160a01b03841690811790915560405190917f9dfd431959d2d3358e3eb909555ad574123ea5881ff0e05a80f66d4984710c1b91a250565b6001546001600160a01b0316331461086957604051630f22ca5f60e01b815260040160405180910390fd5b6001545f80546040516001600160a01b0393841693909116917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600180545f80546001600160a01b03199081166001600160a01b03841617909155169055565b5f546001600160a01b031633146108f5576040516330cd747160e01b815260040160405180910390fd5b600180546001600160a01b0319169055565b5f805b60055481101561095b57826001600160a01b0316600582815481106109315761093161110f565b5f918252602090912001546001600160a01b0316036109535750600192915050565b60010161090a565b505f92915050565b60045460ff1615610987576040516326d1807b60e01b815260040160405180910390fd5b805f036109a75760405163b4fa3fb360e01b815260040160405180910390fd5b335f9081526003602052604081208054918391906109c583856110fc565b925050819055508160025f8282546109dd91906110fc565b9091555050335f90815260036020526040812054905b600554811015610a8a5760058181548110610a1057610a1061110f565b5f91825260209091200154604051630d7c9d9b60e41b815233600482015260248101859052604481018490526001600160a01b039091169063d7c9d9b0906064015f604051808303815f87803b158015610a68575f5ffd5b505af1158015610a7a573d5f5f3e3d5ffd5b5050600190920191506109f39050565b506040516323b872dd60e01b8152336004820152306024820152604481018490527f000000000000000000000000774eaefe73df7959496ac92a77279a8d7d690b076001600160a01b0316906323b872dd906064016020604051808303815f875af1925050508015610b19575060408051601f3d908101601f19168201909252610b1691810190611123565b60015b610b3657604051630389c7a160e51b815260040160405180910390fd5b80610b5457604051630389c7a160e51b815260040160405180910390fd5b50604051839033907f9e71bc8eea02a63969f509818f2dafb9254532904319f9dbda79b67bd34a5f3d905f90a3505050565b5f546001600160a01b03163314610bb0576040516330cd747160e01b815260040160405180910390fd5b5f5b600554811015610cd957816001600160a01b031660058281548110610bd957610bd961110f565b5f918252602090912001546001600160a01b031603610cd15760058054610c02906001906110e9565b81548110610c1257610c1261110f565b5f91825260209091200154600580546001600160a01b039092169183908110610c3d57610c3d61110f565b905f5260205f20015f6101000a8154816001600160a01b0302191690836001600160a01b031602179055506005805480610c7957610c7961113e565b5f8281526020812082015f1990810180546001600160a01b03191690559091019091556040516001600160a01b038416917fce699c579f0b70ea4ccd6a4b38be26726a2c248b89c7102ccbc5d0f3060ef6d091a25050565b600101610bb2565b505b50565b60058181548110610ced575f80fd5b5f918252602090912001546001600160a01b0316905081565b5f6001600160a01b038316610d2e5760405163b4fa3fb360e01b815260040160405180910390fd5b6001600160a01b0383165f90815260036020526040812054908315610d535783610d55565b815b9050805f03610d68575f92505050610f79565b81811115610d97576040516388533e8360e01b8152600481018390526024810182905260440160405180910390fd5b6001600160a01b0385165f908152600360205260408120805491839190610dbe83856110e9565b90915550506001600160a01b0386165f90815260036020526040812054905b600554811015610e765760058181548110610dfa57610dfa61110f565b5f91825260209091200154604051630d7c9d9b60e41b81526001600160a01b038a8116600483015260248201869052604482018590529091169063d7c9d9b0906064015f604051808303815f87803b158015610e54575f5ffd5b505af1158015610e66573d5f5f3e3d5ffd5b505060019092019150610ddd9050565b5060405163a9059cbb60e01b81526001600160a01b038881166004830152602482018590527f000000000000000000000000774eaefe73df7959496ac92a77279a8d7d690b07169063a9059cbb906044016020604051808303815f875af1925050508015610f01575060408051601f3d908101601f19168201909252610efe91810190611123565b60015b610f1e57604051630389c7a160e51b815260040160405180910390fd5b80610f3c57604051630389c7a160e51b815260040160405180910390fd5b5060405183906001600160a01b038916907f0f5bb82176feb1b5e747e28471aa92156a04d9f3ab9f45f28e2d704232b93f75905f90a35090925050505b92915050565b8015158114610cdb575f5ffd5b5f60208284031215610f9c575f5ffd5b8135610fa781610f7f565b9392505050565b5f60208284031215610fbe575f5ffd5b5035919050565b80356001600160a01b0381168114610fdb575f5ffd5b919050565b5f5f60408385031215610ff1575f5ffd5b610ffa83610fc5565b946020939093013593505050565b5f5f83601f840112611018575f5ffd5b50813567ffffffffffffffff81111561102f575f5ffd5b6020830191508360208260051b8501011115611049575f5ffd5b9250929050565b5f5f5f5f60408587031215611063575f5ffd5b843567ffffffffffffffff811115611079575f5ffd5b61108587828801611008565b909550935050602085013567ffffffffffffffff8111156110a4575f5ffd5b6110b087828801611008565b95989497509550505050565b5f602082840312156110cc575f5ffd5b610fa782610fc5565b634e487b7160e01b5f52601160045260245ffd5b81810381811115610f7957610f796110d5565b80820180821115610f7957610f796110d5565b634e487b7160e01b5f52603260045260245ffd5b5f60208284031215611133575f5ffd5b8151610fa781610f7f565b634e487b7160e01b5f52603160045260245ffdfea2646970667358221220cedbb2e2eb2168153c9a2a3ebaf8a4292286c2df126f9ab103e2f3a7643d159a64736f6c634300081c0033

Deployed Bytecode Sourcemap

538:8606:2:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7550:166;;;;;;:::i;:::-;;:::i;:::-;;736:27;;;;;;;;;;;;548:14:7;;541:22;523:41;;511:2;496:18;736:27:2;;;;;;;;6166:268;;;;;;:::i;:::-;;:::i;5193:832::-;;;;;;:::i;:::-;;:::i;6787:595::-;;;;;;:::i;:::-;;:::i;1656:179:3:-;;;;;;:::i;:::-;;:::i;645:32:2:-;;;;;;;;;2771:25:7;;;2759:2;2744:18;645:32:2;2625:177:7;8341:282:2;;;;;;:::i;:::-;;:::i;603:36::-;;;;;;;;-1:-1:-1;;;;;2984:32:7;;;2966:51;;2954:2;2939:18;603:36:2;2807:216:7;1934:183:3;;;:::i;2233:95::-;;;:::i;267:20::-;;;;;-1:-1:-1;;;;;267:20:3;;;7941:259:2;;;;;;:::i;:::-;;:::i;4222:775::-;;;;;;:::i;:::-;;:::i;8770:372::-;;;;;;:::i;:::-;;:::i;293:28:3:-;;;;;-1:-1:-1;;;;;293:28:3;;;683:47:2;;;;;;:::i;:::-;;;;;;;;;;;;;;770:43;;;;;;:::i;:::-;;:::i;7550:166::-;1227:5:3;;-1:-1:-1;;;;;1227:5:3;1213:10;:19;1209:42;;1241:10;;-1:-1:-1;;;1241:10:3;;;;;;;;;;;1209:42;7626:15:2::1;:34:::0;;-1:-1:-1;;7626:34:2::1;::::0;::::1;;::::0;;::::1;::::0;;;7675::::1;::::0;::::1;::::0;-1:-1:-1;;7675:34:2::1;7550:166:::0;:::o;6166:268::-;6221:15;;;;6217:43;;;6245:15;;-1:-1:-1;;;6245:15:2;;;;;;;;;;;6217:43;6274:7;6285:1;6274:12;6270:39;;6295:14;;-1:-1:-1;;;6295:14:2;;;;;;;;;;;6270:39;6328:22;6353:29;6362:10;6374:7;6353:8;:29::i;:::-;6328:54;;6413:14;6392:17;;:35;;;;;;;:::i;:::-;;;;-1:-1:-1;;;;6166:268:2:o;5193:832::-;5264:15;;;;5260:43;;;5288:15;;-1:-1:-1;;;5288:15:2;;;;;;;;;;;5260:43;-1:-1:-1;;;;;5317:19:2;;5313:46;;5345:14;;-1:-1:-1;;;5345:14:2;;;;;;;;;;;5313:46;5373:7;5384:1;5373:12;5369:39;;5394:14;;-1:-1:-1;;;5394:14:2;;;;;;;;;;;5369:39;-1:-1:-1;;;;;5453:19:2;;5427:23;5453:19;;;:12;:19;;;;;;;;5505:7;;5453:19;5482:30;5505:7;5453:19;5482:30;:::i;:::-;;;;;;;;5543:7;5522:17;;:28;;;;;;;:::i;:::-;;;;-1:-1:-1;;;;;;;5586:19:2;;5560:23;5586:19;;;:12;:19;;;;;;;5615:140;5639:9;:16;5635:20;;5615:140;;;5676:9;5686:1;5676:12;;;;;;;;:::i;:::-;;;;;;;;;;;:68;;-1:-1:-1;;;5676:68:2;;-1:-1:-1;;;;;4224:32:7;;;5676:68:2;;;4206:51:7;4273:18;;;4266:34;;;4316:18;;;4309:34;;;5676:12:2;;;;:27;;4179:18:7;;5676:68:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;5657:3:2;;;;;-1:-1:-1;5615:140:2;;-1:-1:-1;5615:140:2;;-1:-1:-1;5769:61:2;;-1:-1:-1;;;5769:61:2;;5795:10;5769:61;;;4556:51:7;5815:4:2;4623:18:7;;;4616:60;4692:18;;;4685:34;;;5769:12:2;-1:-1:-1;;;;;5769:25:2;;;;4529:18:7;;5769:61:2;;;;;;;;;;;;;;;;;;;-1:-1:-1;5769:61:2;;;;;;;;-1:-1:-1;;5769:61:2;;;;;;;;;;;;:::i;:::-;;;5765:216;;5949:21;;-1:-1:-1;;;5949:21:2;;;;;;;;;;;5765:216;5873:7;5868:42;;5889:21;;-1:-1:-1;;;5889:21:2;;;;;;;;;;;5868:42;5831:90;5996:22;;6010:7;;-1:-1:-1;;;;;5996:22:2;;;;;;;;5250:775;;5193:832;;:::o;6787:595::-;1227:5:3;;-1:-1:-1;;;;;1227:5:3;1213:10;:19;1209:42;;1241:10;;-1:-1:-1;;;1241:10:3;;;;;;;;;;;1209:42;6896:32:2;;::::1;6892:59;;6937:14;;-1:-1:-1::0;;;6937:14:2::1;;;;;;;;;;;6892:59;6982:1;6965:18:::0;;;6961:45:::1;;6992:14;;-1:-1:-1::0;;;6992:14:2::1;;;;;;;;;;;6961:45;7025:21;::::0;7069:254:::1;7089:17:::0;;::::1;7069:254;;;7127:12;7142:6;;7149:1;7142:9;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;7127:24;;7165:14;7182:8;;7191:1;7182:11;;;;;;;:::i;:::-;;;;;;;7165:28;;7220:22;7245;7254:4;7260:6;7245:8;:22::i;:::-;7220:47:::0;-1:-1:-1;7281:31:2::1;7220:47:::0;7281:31;::::1;:::i;:::-;::::0;-1:-1:-1;;7108:3:2::1;::::0;;::::1;::::0;-1:-1:-1;7069:254:2::1;::::0;-1:-1:-1;7069:254:2::1;;;7362:13;7341:17;;:34;;;;;;;:::i;:::-;::::0;;;-1:-1:-1;;;;;;;6787:595:2:o;1656:179:3:-;1227:5;;-1:-1:-1;;;;;1227:5:3;1213:10;:19;1209:42;;1241:10;;-1:-1:-1;;;1241:10:3;;;;;;;;;;;1209:42;-1:-1:-1;;;;;1737:28:3;::::1;1733:55;;1774:14;;-1:-1:-1::0;;;1774:14:3::1;;;;;;;;;;;1733:55;1798:13;:30:::0;;-1:-1:-1;;;;;;1798:30:3::1;-1:-1:-1::0;;;;;1798:30:3;;;::::1;::::0;;;::::1;::::0;;1656:179::o;8341:282:2:-;1227:5:3;;-1:-1:-1;;;;;1227:5:3;1213:10;:19;1209:42;;1241:10;;-1:-1:-1;;;1241:10:3;;;;;;;;;;;1209:42;-1:-1:-1;;;;;8412:23:2;::::1;8408:50;;8444:14;;-1:-1:-1::0;;;8444:14:2::1;;;;;;;;;;;8408:50;8472:21;8483:9;8472:10;:21::i;:::-;8468:48;;;8502:14;;-1:-1:-1::0;;;8502:14:2::1;;;;;;;;;;;8468:48;8526:9;:51:::0;;::::1;::::0;::::1;::::0;;-1:-1:-1;8526:51:2;;;;::::1;::::0;;-1:-1:-1;;;;;;8526:51:2::1;-1:-1:-1::0;;;;;8526:51:2;::::1;::::0;;::::1;::::0;;;8592:24:::1;::::0;8526:51;;8592:24:::1;::::0;::::1;8341:282:::0;:::o;1934:183:3:-;1448:13;;-1:-1:-1;;;;;1448:13:3;1434:10;:27;1430:58;;1470:18;;-1:-1:-1;;;1470:18:3;;;;;;;;;;;1430:58;2029:13:::1;::::0;::::1;2022:5:::0;;2001:42:::1;::::0;-1:-1:-1;;;;;2029:13:3;;::::1;::::0;2022:5;;::::1;::::0;2001:42:::1;::::0;::::1;2061:13;::::0;;::::1;2053:21:::0;;-1:-1:-1;;;;;;2053:21:3;;::::1;-1:-1:-1::0;;;;;2061:13:3;::::1;2053:21;::::0;;;2084:26:::1;::::0;;1934:183::o;2233:95::-;1227:5;;-1:-1:-1;;;;;1227:5:3;1213:10;:19;1209:42;;1241:10;;-1:-1:-1;;;1241:10:3;;;;;;;;;;;1209:42;2295:13:::1;:26:::0;;-1:-1:-1;;;;;;2295:26:3::1;::::0;;2233:95::o;7941:259:2:-;8001:4;;8017:155;8041:9;:16;8037:20;;8017:155;;;8107:9;-1:-1:-1;;;;;8082:34:2;8090:9;8100:1;8090:12;;;;;;;;:::i;:::-;;;;;;;;;;;-1:-1:-1;;;;;8090:12:2;8082:34;8078:84;;-1:-1:-1;8143:4:2;;7941:259;-1:-1:-1;;7941:259:2:o;8078:84::-;8059:3;;8017:155;;;-1:-1:-1;8188:5:2;;7941:259;-1:-1:-1;;7941:259:2:o;4222:775::-;4275:15;;;;4271:43;;;4299:15;;-1:-1:-1;;;4299:15:2;;;;;;;;;;;4271:43;4328:7;4339:1;4328:12;4324:39;;4349:14;;-1:-1:-1;;;4349:14:2;;;;;;;;;;;4324:39;4413:10;4374:23;4400:24;;;:12;:24;;;;;;;;4462:7;;4400:24;4434:35;4462:7;4400:24;4434:35;:::i;:::-;;;;;;;;4500:7;4479:17;;:28;;;;;;;:::i;:::-;;;;-1:-1:-1;;4556:10:2;4517:23;4543:24;;;:12;:24;;;;;;;4577:145;4601:9;:16;4597:20;;4577:145;;;4638:9;4648:1;4638:12;;;;;;;;:::i;:::-;;;;;;;;;;;:73;;-1:-1:-1;;;4638:73:2;;4666:10;4638:73;;;4206:51:7;4273:18;;;4266:34;;;4316:18;;;4309:34;;;-1:-1:-1;;;;;4638:12:2;;;;:27;;4179:18:7;;4638:73:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;4619:3:2;;;;;-1:-1:-1;4577:145:2;;-1:-1:-1;4577:145:2;;-1:-1:-1;4736:61:2;;-1:-1:-1;;;4736:61:2;;4762:10;4736:61;;;4556:51:7;4782:4:2;4623:18:7;;;4616:60;4692:18;;;4685:34;;;4736:12:2;-1:-1:-1;;;;;4736:25:2;;;;4529:18:7;;4736:61:2;;;;;;;;;;;;;;;;;;;-1:-1:-1;4736:61:2;;;;;;;;-1:-1:-1;;4736:61:2;;;;;;;;;;;;:::i;:::-;;;4732:216;;4916:21;;-1:-1:-1;;;4916:21:2;;;;;;;;;;;4732:216;4840:7;4835:42;;4856:21;;-1:-1:-1;;;4856:21:2;;;;;;;;;;;4835:42;4798:90;4963:27;;4982:7;;4970:10;;4963:27;;;;;4261:736;;4222:775;:::o;8770:372::-;1227:5:3;;-1:-1:-1;;;;;1227:5:3;1213:10;:19;1209:42;;1241:10;;-1:-1:-1;;;1241:10:3;;;;;;;;;;;1209:42;8845:9:2::1;8840:296;8864:9;:16:::0;8860:20;::::1;8840:296;;;8930:9;-1:-1:-1::0;;;;;8905:34:2::1;8913:9;8923:1;8913:12;;;;;;;;:::i;:::-;;::::0;;;::::1;::::0;;;::::1;::::0;-1:-1:-1;;;;;8913:12:2::1;8905:34:::0;8901:225:::1;;8974:9;8984:16:::0;;:20:::1;::::0;9003:1:::1;::::0;8984:20:::1;:::i;:::-;8974:31;;;;;;;;:::i;:::-;;::::0;;;::::1;::::0;;;::::1;::::0;8959:9:::1;:12:::0;;-1:-1:-1;;;;;8974:31:2;;::::1;::::0;8969:1;;8959:12;::::1;;;;;:::i;:::-;;;;;;;;;:46;;;;;-1:-1:-1::0;;;;;8959:46:2::1;;;;;-1:-1:-1::0;;;;;8959:46:2::1;;;;;;9023:9;:15;;;;;;;:::i;:::-;;::::0;;;::::1;::::0;;;;-1:-1:-1;;9023:15:2;;;;;-1:-1:-1;;;;;;9023:15:2::1;::::0;;;;;;;;9061:26:::1;::::0;-1:-1:-1;;;;;9061:26:2;::::1;::::0;::::1;::::0;::::1;9105:7;8770:372:::0;:::o;8901:225::-:1;8882:3;;8840:296;;;;1261:1:3;8770:372:2::0;:::o;770:43::-;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;770:43:2;;-1:-1:-1;770:43:2;:::o;3032:1055::-;3100:7;-1:-1:-1;;;;;3123:19:2;;3119:46;;3151:14;;-1:-1:-1;;;3151:14:2;;;;;;;;;;;3119:46;-1:-1:-1;;;;;3205:19:2;;3184:18;3205:19;;;:12;:19;;;;;;;3260:12;;:35;;3288:7;3260:35;;;3275:10;3260:35;3234:61;;3309:15;3328:1;3309:20;3305:34;;3338:1;3331:8;;;;;;3305:34;3372:10;3354:15;:28;3350:116;;;3405:50;;-1:-1:-1;;;3405:50:2;;;;;5286:25:7;;;5327:18;;;5320:34;;;5259:18;;3405:50:2;;;;;;;3350:116;-1:-1:-1;;;;;3510:19:2;;3484:23;3510:19;;;:12;:19;;;;;;;;3562:15;;3510:19;3539:38;3562:15;3510:19;3539:38;:::i;:::-;;;;-1:-1:-1;;;;;;;3613:19:2;;3587:23;3613:19;;;:12;:19;;;;;;;3642:140;3666:9;:16;3662:20;;3642:140;;;3703:9;3713:1;3703:12;;;;;;;;:::i;:::-;;;;;;;;;;;:68;;-1:-1:-1;;;3703:68:2;;-1:-1:-1;;;;;4224:32:7;;;3703:68:2;;;4206:51:7;4273:18;;;4266:34;;;4316:18;;;4309:34;;;3703:12:2;;;;:27;;4179:18:7;;3703:68:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;3684:3:2;;;;;-1:-1:-1;3642:140:2;;-1:-1:-1;3642:140:2;;-1:-1:-1;3796:45:2;;-1:-1:-1;;;3796:45:2;;-1:-1:-1;;;;;5557:32:7;;;3796:45:2;;;5539:51:7;5606:18;;;5599:34;;;3796:12:2;:21;;;;5512:18:7;;3796:45:2;;;;;;;;;;;;;;;;;;;-1:-1:-1;3796:45:2;;;;;;;;-1:-1:-1;;3796:45:2;;;;;;;;;;;;:::i;:::-;;;3792:200;;3960:21;;-1:-1:-1;;;3960:21:2;;;;;;;;;;;3792:200;3884:7;3879:42;;3900:21;;-1:-1:-1;;;3900:21:2;;;;;;;;;;;3879:42;3842:90;4007:32;;4023:15;;-1:-1:-1;;;;;4007:32:2;;;;;;;;-1:-1:-1;4065:15:2;;-1:-1:-1;;;3032:1055:2;;;;;:::o;14:118:7:-;100:5;93:13;86:21;79:5;76:32;66:60;;122:1;119;112:12;137:241;193:6;246:2;234:9;225:7;221:23;217:32;214:52;;;262:1;259;252:12;214:52;301:9;288:23;320:28;342:5;320:28;:::i;:::-;367:5;137:241;-1:-1:-1;;;137:241:7:o;575:226::-;634:6;687:2;675:9;666:7;662:23;658:32;655:52;;;703:1;700;693:12;655:52;-1:-1:-1;748:23:7;;575:226;-1:-1:-1;575:226:7:o;806:173::-;874:20;;-1:-1:-1;;;;;923:31:7;;913:42;;903:70;;969:1;966;959:12;903:70;806:173;;;:::o;984:300::-;1052:6;1060;1113:2;1101:9;1092:7;1088:23;1084:32;1081:52;;;1129:1;1126;1119:12;1081:52;1152:29;1171:9;1152:29;:::i;:::-;1142:39;1250:2;1235:18;;;;1222:32;;-1:-1:-1;;;984:300:7:o;1289:367::-;1352:8;1362:6;1416:3;1409:4;1401:6;1397:17;1393:27;1383:55;;1434:1;1431;1424:12;1383:55;-1:-1:-1;1457:20:7;;1500:18;1489:30;;1486:50;;;1532:1;1529;1522:12;1486:50;1569:4;1561:6;1557:17;1545:29;;1629:3;1622:4;1612:6;1609:1;1605:14;1597:6;1593:27;1589:38;1586:47;1583:67;;;1646:1;1643;1636:12;1583:67;1289:367;;;;;:::o;1661:768::-;1783:6;1791;1799;1807;1860:2;1848:9;1839:7;1835:23;1831:32;1828:52;;;1876:1;1873;1866:12;1828:52;1916:9;1903:23;1949:18;1941:6;1938:30;1935:50;;;1981:1;1978;1971:12;1935:50;2020:70;2082:7;2073:6;2062:9;2058:22;2020:70;:::i;:::-;2109:8;;-1:-1:-1;1994:96:7;-1:-1:-1;;2197:2:7;2182:18;;2169:32;2226:18;2213:32;;2210:52;;;2258:1;2255;2248:12;2210:52;2297:72;2361:7;2350:8;2339:9;2335:24;2297:72;:::i;:::-;1661:768;;;;-1:-1:-1;2388:8:7;-1:-1:-1;;;;1661:768:7:o;2434:186::-;2493:6;2546:2;2534:9;2525:7;2521:23;2517:32;2514:52;;;2562:1;2559;2552:12;2514:52;2585:29;2604:9;2585:29;:::i;3477:127::-;3538:10;3533:3;3529:20;3526:1;3519:31;3569:4;3566:1;3559:15;3593:4;3590:1;3583:15;3609:128;3676:9;;;3697:11;;;3694:37;;;3711:18;;:::i;3742:125::-;3807:9;;;3828:10;;;3825:36;;;3841:18;;:::i;3872:127::-;3933:10;3928:3;3924:20;3921:1;3914:31;3964:4;3961:1;3954:15;3988:4;3985:1;3978:15;4730:245;4797:6;4850:2;4838:9;4829:7;4825:23;4821:32;4818:52;;;4866:1;4863;4856:12;4818:52;4898:9;4892:16;4917:28;4939:5;4917:28;:::i;4980:127::-;5041:10;5036:3;5032:20;5029:1;5022:31;5072:4;5069:1;5062:15;5096:4;5093:1;5086:15

Swarm Source

ipfs://cedbb2e2eb2168153c9a2a3ebaf8a4292286c2df126f9ab103e2f3a7643d159a

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
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.