ETH Price: $3,252.74 (-0.68%)
Gas: 2 Gwei

Contract

0xE8cfBDd1B2EF0643d1c239fF38d936903b5c84d8
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
0x60806040165721392023-02-06 20:29:23538 days ago1675715363IN
 Create: BaseV2GaugeFactory
0 ETH0.0259742333.30833555

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
BaseV2GaugeFactory

Compiler Version
v0.8.11+commit.d7f03943

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, BSL 1.1 license
File 1 of 7 : BaseV2-gauges.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.11;

import "./ProxyPattern/SolidlyFactory.sol";
import "./ProxyPattern/SolidlyChildImplementation.sol";

library Math {
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a >= b ? a : b;
    }

    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }
}

interface erc20 {
    function totalSupply() external view returns (uint256);

    function transfer(address recipient, uint256 amount)
        external
        returns (bool);

    function balanceOf(address) external view returns (uint256);

    function transferFrom(
        address sender,
        address recipient,
        uint256 amount
    ) external returns (bool);

    function approve(address spender, uint256 value) external returns (bool);
}

interface IVeV2 {
    function token() external view returns (address);

    function balanceOfNFT(uint256) external view returns (uint256);

    function isApprovedOrOwner(address, uint256) external view returns (bool);

    function ownerOf(uint256) external view returns (address);

    function transferFrom(
        address,
        address,
        uint256
    ) external;
}

interface IBaseV2Factory {
    function isPair(address) external view returns (bool);
}

interface IBaseV2Pair {
    function claimFees() external returns (uint256, uint256);

    function tokens() external returns (address, address);
}

interface IBribeV2 {
    function notifyRewardAmount(address token, uint256 amount) external;

    function left(address token) external view returns (uint256);
}

interface IVoterV2 {
    function attachTokenToGauge(uint256 _tokenId, address account) external;

    function detachTokenFromGauge(uint256 _tokenId, address account) external;

    function generalFees() external view returns (address);

    function emitDeposit(
        uint256 _tokenId,
        address account,
        uint256 amount
    ) external;

    function emitWithdraw(
        uint256 _tokenId,
        address account,
        uint256 amount
    ) external;

    function distribute(address _gauge) external;

    function feeDists(address _pool) external view returns (address _feeDist);
}

interface IFeeDistV2 {
    function claimFees() external;
}

interface IBaseV2GeneralFees {
    function notifyRewardAmount(address token, uint256 amount) external;
}

// Gauges are used to incentivize pools, they emit reward tokens over 7 days for staked LP tokens
/**
 * @dev Changelog:
 *      - Deprecate constructor with initialize()
 *      - Deprecate checkpoint and indexing system, replaced with opt-in multirewards like system
 *      - Uses RewardRatePerWeek instead of RewardRate for reward calculations (better precision)
 *      - Adapt _claimFees() to support transfer tax tokens
 *      - Immutable storage slots became mutable but made sure nothing changes them after initialize()
 *      - No longer calls voter to emit deposit and withdrawal
 */
contract GaugeV2 is SolidlyChildImplementation {
    uint256 internal constant DURATION = 7 days; // rewards are released over 7 days
    uint256 internal constant PRECISION = 10**44;
    /**
     * @dev storage slots start here
     */

    // simple re-entrancy check
    uint256 internal _unlocked = 1;

    address public stake; // the LP token that needs to be staked for rewards
    address public _ve; // the ve token used for gauges
    address public solid;
    address public bribe;
    address public voter;

    uint256 public derivedSupply;
    mapping(address => uint128) public derivedBalances;
    mapping(address => uint256) public tokenIds;
    mapping(address => uint256) public balanceOf;
    mapping(address => mapping(address => bool)) public isOptIn; // userAddress => rewardAddress => bool
    mapping(address => address[]) public userOptIns; // array of rewards the user is opted into
    mapping(address => mapping(address => uint256)) public userOptInsIndex; // index of pools within userOptIns userAddress =>rewardAddress => index

    // default snx staking contract implementation
    mapping(address => RewardData) public rewardData;

    struct RewardData {
        uint128 rewardRatePerWeek;
        uint128 derivedSupply;
        uint256 rewardPerTokenStored;
        uint40 periodFinish;
        uint40 lastUpdateTime;
    }
    struct UserRewardData {
        uint256 userRewardPerTokenPaid;
        uint256 userEarnedStored;
    }

    mapping(address => mapping(address => UserRewardData))
        public userRewardData; // userAddress => tokenAddress => userRewardData

    uint256 public totalSupply;

    address[] public rewards;
    mapping(address => bool) public isReward;

    uint256 public fees0;
    uint256 public fees1;

    event Deposit(address indexed from, uint256 tokenId, uint256 amount);
    event OptIn(address indexed from, address indexed reward);
    event OptOut(address indexed from, address indexed reward);
    event Withdraw(address indexed from, uint256 tokenId, uint256 amount);
    event NotifyReward(
        address indexed from,
        address indexed reward,
        uint256 amount
    );
    event ClawbackRewards(address indexed reward, uint256 amount);
    event ClaimFees(address indexed from, uint256 claimed0, uint256 claimed1);
    event ClaimRewards(
        address indexed from,
        address indexed reward,
        uint256 amount
    );

    // simple re-entrancy check
    modifier lock() {
        require(_unlocked == 1);
        _unlocked = 2;
        _;
        _unlocked = 1;
    }

    function initialize(
        address _stake,
        address _bribe,
        address __ve,
        address _voter
    ) external onlyFactory notInitialized {
        _unlocked = 1;
        stake = _stake;
        bribe = _bribe;
        _ve = __ve;
        voter = _voter;
        solid = IVeV2(_ve).token();
    }

    /**************************************** 
                View Methods
    ****************************************/
    /**
     * @notice Returns the balance derived based on veToken staked. Used to determine ratio of rewards streamed
     * @param account User address
     */
    function derivedBalance(address account) public view returns (uint256) {
        if (BaseV2GaugeFactory(factoryAddress()).isBoostPaused()) {
            return balanceOf[account];
        } else {
            uint256 _tokenId = tokenIds[account];
            uint256 _balance = balanceOf[account];
            uint256 _derived = (_balance * 40) / 100;
            uint256 _adjusted = 0;
            uint256 _supply = erc20(_ve).totalSupply();
            if (account == IVeV2(_ve).ownerOf(_tokenId) && _supply > 0) {
                _adjusted = IVeV2(_ve).balanceOfNFT(_tokenId);
                _adjusted = (((totalSupply * _adjusted) / _supply) * 60) / 100;
            }
            return Math.min((_derived + _adjusted), _balance);
        }
    }

    /**
     * @dev ATTENTION ordering is flipped to (token, account) instead of (account, token) for backwards compatibility
     */
    function earned(address token, address account)
        external
        view
        returns (uint256)
    {
        RewardData memory _rewardData = rewardData[token];
        UserRewardData memory _userRewardData = userRewardData[account][token];

        uint256 _earned = _userRewardData.userEarnedStored;
        if (isOptIn[account][token]) {
            _earned += ((derivedBalances[account] *
                (_rewardPerToken(_rewardData) -
                    _userRewardData.userRewardPerTokenPaid)) / PRECISION);
        }
        return _earned;
    }

    /**
     * @notice Internal view method does not call _rewardPerToken() since it's always updated just before this is called
     * @dev ATTENTION input orders are (account, token) to comform with RewardData structures
     */
    function _earnedFromStored(address account, address token)
        internal
        view
        returns (uint256)
    {
        UserRewardData memory _userRewardData = userRewardData[account][token];
        uint256 _earned = (_userRewardData.userEarnedStored) +
            ((derivedBalances[account] *
                (rewardData[token].rewardPerTokenStored -
                    _userRewardData.userRewardPerTokenPaid)) / PRECISION);

        return _earned;
    }

    /**
     * @notice Returns the last time the reward was modified or periodFinish if the reward has ended
     */
    function lastTimeRewardApplicable(address token)
        external
        view
        returns (uint256)
    {
        return Math.min(block.timestamp, rewardData[token].periodFinish);
    }

    /**
     * @notice View method for backwards compatibility
     * @dev Now part of RewardData struct
     * @param token Reward token
     */
    function lastUpdateTime(address token) external view returns (uint256) {
        return rewardData[token].lastUpdateTime;
    }

    /**
     * @notice Returns the amount of rewards left in the reward period
     * @param token Reward token
     */
    function left(address token) external view returns (uint256) {
        RewardData memory _rewardData = rewardData[token];
        if (block.timestamp >= _rewardData.periodFinish) {
            return 0;
        }
        uint256 _remaining = _rewardData.periodFinish - block.timestamp;
        return (_remaining * _rewardData.rewardRatePerWeek) / DURATION;
    }

    /**
     * @notice View method for backwards compatibility
     * @dev Now part of RewardData struct
     * @param token Reward token
     */
    function periodFinish(address token) external view returns (uint256) {
        return rewardData[token].periodFinish;
    }

    /**
     * @notice View method for backwards compatibility
     * @dev Now part of RewardData struct
     * @param token Reward token
     */
    function rewardPerTokenStored(address token)
        external
        view
        returns (uint256)
    {
        return rewardData[token].rewardPerTokenStored;
    }

    /**
     * @notice View method for backwards compatibility
     * @dev rewardRate decprecated in favour of rewardRatePerWeek since DURATION is constant
     * @param token Reward token
     */
    function rewardRate(address token) external view returns (uint256) {
        return rewardData[token].rewardRatePerWeek / DURATION;
    }

    /**
     * @notice Returns the rewardsList length
     */
    function rewardsListLength() external view returns (uint256) {
        return rewards.length;
    }

    /**
     * @notice Backwards compatible wiew method for rewardPerToken
     * @param token Reward token
     */
    function rewardPerToken(address token) external view returns (uint256) {
        RewardData memory _rewardData = rewardData[token];

        return _rewardPerToken(_rewardData);
    }

    /**
     * @notice view method for rewardPerToken
     * @dev passing RewardData instead of tokenAddress to save gas on SLOAD
     * @param _rewardData RewardData struct for the reward token
     */
    function _rewardPerToken(RewardData memory _rewardData)
        internal
        view
        returns (uint256)
    {
        if (_rewardData.derivedSupply == 0) {
            return _rewardData.rewardPerTokenStored;
        }

        uint256 timeElapsed = (Math.min(
            block.timestamp,
            _rewardData.periodFinish
        ) - Math.min(_rewardData.lastUpdateTime, _rewardData.periodFinish));

        return
            _rewardData.rewardPerTokenStored +
            uint256(
                ((((PRECISION / DURATION) * _rewardData.rewardRatePerWeek) /
                    _rewardData.derivedSupply) * timeElapsed)
            );
    }

    /**
     * @notice Backwards compatible wiew method for userRewardPerTokenStored
     * @dev ATTENTION input ordering is (token, account) for backwards compatibility
     * @param token Reward token
     * @param account User address
     */
    function userRewardPerTokenStored(address token, address account)
        external
        view
        returns (uint256)
    {
        return userRewardData[account][token].userRewardPerTokenPaid;
    }

    /**************************************** 
                Protocol Interaction
    ****************************************/
    /**
     * @notice Calls the feeDist to claimFees from the pair
     * @dev Kept for backwards compatibility
     */
    function claimFees() external returns (uint256 claimed0, uint256 claimed1) {
        // Fetch addresses
        address _feeDist = IVoterV2(voter).feeDists(stake);

        address[] memory tokens = new address[](2);
        (tokens[0], tokens[1]) = IBaseV2Pair(stake).tokens();

        // Fetch current status
        uint256[] memory balancesBefore = new uint256[](2);
        balancesBefore[0] = erc20(tokens[0]).balanceOf(_feeDist);
        balancesBefore[1] = erc20(tokens[1]).balanceOf(_feeDist);

        // Call feeDist to claim fees
        IFeeDistV2(_feeDist).claimFees();

        // Compute claimed amounts
        claimed0 = erc20(tokens[0]).balanceOf(_feeDist) - balancesBefore[0];
        claimed1 = erc20(tokens[1]).balanceOf(_feeDist) - balancesBefore[1];

        return (claimed0, claimed1);
    }

    /**************************************** 
                User Interaction
    ****************************************/

    modifier updateReward(address account) {
        uint128 _derivedBalance = derivedBalances[account];
        uint256 _balanceOf = balanceOf[account];
        for (uint256 i; i < userOptIns[account].length; i++) {
            address token = userOptIns[account][i];
            RewardData memory _rewardData = rewardData[token]; // gas savings

            _rewardData.rewardPerTokenStored = _rewardPerToken(_rewardData);
            _rewardData.lastUpdateTime = uint40(
                Math.min(block.timestamp, _rewardData.periodFinish)
            );
            // reduce derivedBalance for opted in pools, readjust them later
            rewardData[token] = _rewardData;

            UserRewardData memory _userRewardData = userRewardData[account][
                token
            ];
            uint256 _earnedBefore = _userRewardData.userEarnedStored;
            uint256 _earnedAfter = _earnedFromStored(account, token);

            // only update userRewardPerTokenPaid if earned goes up,
            // but if derivedBalance changes, update regardless (code at the end of modifier)
            if (_earnedAfter > _earnedBefore) {
                userRewardData[account][token].userEarnedStored = _earnedAfter;
                userRewardData[account][token]
                    .userRewardPerTokenPaid = rewardData[token]
                    .rewardPerTokenStored;
            }
        }

        _;

        // update balance
        uint128 _derivedBalanceBefore = _derivedBalance;
        uint256 _derivedSupply = derivedSupply;
        _derivedSupply -= _derivedBalanceBefore;
        _derivedBalance = uint128(derivedBalance(account));
        derivedBalances[account] = _derivedBalance;
        _derivedSupply += _derivedBalance;
        derivedSupply = _derivedSupply;

        // Update derivedBalances for the opted-in pools
        for (uint256 i; i < userOptIns[account].length; i++) {
            address token = userOptIns[account][i];
            uint128 _derivedSupply = rewardData[token].derivedSupply;
            _derivedSupply -= _derivedBalanceBefore;
            _derivedSupply += _derivedBalance;
            rewardData[token].derivedSupply = _derivedSupply;
        }

        // update userRewardPerTokenPaid anyways if derivedBalance changes
        if (_derivedBalanceBefore != _derivedBalance) {
            for (uint256 i; i < userOptIns[account].length; i++) {
                address token = userOptIns[account][i];
                userRewardData[account][token]
                    .userRewardPerTokenPaid = rewardData[token]
                    .rewardPerTokenStored;
            }
        }
    }

    /**
     * @notice Deposits all LP tokens into the gauge, opts into solid pool by default if not already opted-in
     * @param tokenId The veNFT tokenId to associate with the user
     */
    function depositAll(uint256 tokenId) external {
        deposit(erc20(stake).balanceOf(msg.sender), tokenId);
    }

    /**
     * @notice Deposits LP tokens into the gauge, opts into solid pool by default if not already opted-in
     * @param amount Amount to deposit
     * @param tokenId The veNFT tokenId to associate with the user
     */
    function deposit(uint256 amount, uint256 tokenId) public {
        address _solid = solid;

        // opt-in to solid and the 2 base tokens if not already opted into solid
        if (!isOptIn[msg.sender][_solid]) {
            address[] memory _optInPools = new address[](3);
            (address _token0, address _token1) = IBaseV2Pair(stake).tokens();
            _optInPools[0] = _solid;
            _optInPools[1] = _token0;
            _optInPools[2] = _token1;
            depositAndOptIn(amount, tokenId, _optInPools);
        } else {
            depositAndOptIn(amount, tokenId, new address[](0));
        }
    }

    /**
     * @notice Deposits LP tokens into the gauge, opts into pools specified if not already opted-in
     * @param amount Amount to deposit
     * @param tokenId The veNFT tokenId to associate with the user
     * @param optInPools The reward pools to opt-in to
     */
    function depositAndOptIn(
        uint256 amount,
        uint256 tokenId,
        address[] memory optInPools
    ) public lock updateReward(msg.sender) {
        require(amount > 0, "Cannot deposit 0");

        _safeTransferFrom(stake, msg.sender, address(this), amount);
        totalSupply += amount;
        balanceOf[msg.sender] += amount;

        if (tokenId > 0) {
            require(IVeV2(_ve).ownerOf(tokenId) == msg.sender, "tokenId auth");
            if (tokenIds[msg.sender] == 0) {
                tokenIds[msg.sender] = tokenId;
                IVoterV2(voter).attachTokenToGauge(tokenId, msg.sender);
            }
            require(
                tokenIds[msg.sender] == tokenId,
                "Different tokenId already attached"
            );
        } else {
            tokenId = tokenIds[msg.sender];
        }

        for (uint256 i = 0; i < optInPools.length; i++) {
            if (!isOptIn[msg.sender][optInPools[i]]) {
                _optIn(optInPools[i]);
            }
        }

        emit Deposit(msg.sender, tokenId, amount);
    }

    /**
     * @notice Opt-in to the specified reward pools
     * @dev Updates reward pools before hand because this is like a balance change for the pool
     * @param tokens The reward pools to opt-in to
     */
    function optIn(address[] calldata tokens)
        external
        lock
        updateReward(msg.sender)
    {
        for (uint256 i = 0; i < tokens.length; i++) {
            // Taking out checks for isReward allows people to opt-into pools before they start,
            // which might be benefitial if projects announce rewards in advance,
            // makes things fairer too.
            if (!isOptIn[msg.sender][tokens[i]]) {
                _optIn(tokens[i]);
            }
        }
    }

    /**
     * @notice Internal function for optIn()
     * @param token The reward pool to opt-in to
     */
    function _optIn(address token) internal {
        RewardData memory _rewardData = rewardData[token];

        _rewardData.derivedSupply += derivedBalances[msg.sender];
        _rewardData.rewardPerTokenStored = _rewardPerToken(_rewardData);
        _rewardData.lastUpdateTime = uint40(
            Math.min(block.timestamp, _rewardData.periodFinish)
        );
        rewardData[token] = _rewardData;

        UserRewardData memory _userRewardData = UserRewardData({
            userRewardPerTokenPaid: _rewardData.rewardPerTokenStored,
            userEarnedStored: 0
        });
        userRewardData[msg.sender][token] = _userRewardData;
        isOptIn[msg.sender][token] = true;
        userOptInsIndex[msg.sender][token] = userOptIns[msg.sender].length;

        userOptIns[msg.sender].push(token);

        emit OptIn(msg.sender, token);
    }

    /**
     * @notice Opt-out of the specified reward pools
     * @dev This method updates the reward pools beforehand, storing all user earned amounts for later claiming
     * @param tokens The reward pools to opt-out of
     */
    function optOut(address[] calldata tokens)
        external
        lock
        updateReward(msg.sender)
    {
        // Actually doesn't really matter if the user has unclaimed rewards
        // since it updates all rewards in the modifier and users can claim
        // stored rewards even after opting out
        for (uint256 i = 0; i < tokens.length; i++) {
            if (isOptIn[msg.sender][tokens[i]]) {
                _optOut(tokens[i]);
            }
        }
    }

    /**
     * @notice skips updateReward(). Forfeits all unstored accrued rewards for the selected pools. Only useful when a user enters too many pools
     */
    function emergencyOptOut(address[] calldata tokens) external lock {
        for (uint256 i = 0; i < tokens.length; i++) {
            uint128 _derivedBalance = derivedBalances[msg.sender];
            if (isOptIn[msg.sender][tokens[i]]) {
                rewardData[tokens[i]].derivedSupply -= _derivedBalance;
                _optOut(tokens[i]);
            }
        }
    }

    /**
     * @notice Internal function for optOut() and emergencyOptOut()
     * @param token The reward pool to opt-in to
     */
    function _optOut(address token) internal {
        isOptIn[msg.sender][token] = false;
        uint256 index = userOptInsIndex[msg.sender][token];
        delete userOptInsIndex[msg.sender][token]; // Delete index for tokenId

        // Fetch last opt-in in array
        address lastOptIn = userOptIns[msg.sender][
            userOptIns[msg.sender].length - 1
        ];

        userOptIns[msg.sender][index] = lastOptIn; // Update userOptIns
        userOptInsIndex[msg.sender][lastOptIn] = index; // Update index by token ID
        userOptIns[msg.sender].pop(); // Remove last userOptIn

        emit OptOut(msg.sender, token);
    }

    function withdrawAll() external {
        withdraw(balanceOf[msg.sender]);
    }

    /**
     * @notice Withdraws LP tokens, and detaches veNFT from the gauge final balance becomes 0
     * @param amount The amount of LP to withdraw
     */
    function withdraw(uint256 amount) public {
        uint256 tokenId = 0;
        if (amount == balanceOf[msg.sender]) {
            tokenId = tokenIds[msg.sender];
        }
        withdrawToken(amount, tokenId);
    }

    /**
     * @notice Withdraws LP tokens, and detaches veNFT from the gauge if specified
     * @param amount The amount of LP to withdraw
     * @param tokenId The veNFT to detach, input 0 to skip detachment
     */
    function withdrawToken(uint256 amount, uint256 tokenId)
        public
        lock
        updateReward(msg.sender)
    {
        totalSupply -= amount;
        balanceOf[msg.sender] -= amount;
        _safeTransfer(stake, msg.sender, amount);

        if (tokenId > 0) {
            require(tokenId == tokenIds[msg.sender], "tokenId auth");
            tokenIds[msg.sender] = 0;
            IVoterV2(voter).detachTokenFromGauge(tokenId, msg.sender);
        } else {
            tokenId = tokenIds[msg.sender];
        }

        emit Withdraw(msg.sender, tokenId, amount);
    }

    function getReward(address account, address[] memory tokens)
        external
        lock
        updateReward(account)
    {
        require(
            msg.sender == account || msg.sender == voter,
            "msg.sender not account"
        );
        _unlocked = 1;
        IVoterV2(voter).distribute(address(this));
        _unlocked = 2;

        for (uint256 i = 0; i < tokens.length; i++) {
            uint256 _reward = userRewardData[account][tokens[i]]
                .userEarnedStored;

            if (_reward > 0) {
                // only need to look at stored amounts because updateReward() is called beforehand
                userRewardData[account][tokens[i]].userEarnedStored = 0;

                _safeTransfer(tokens[i], account, _reward);
            }

            emit ClaimRewards(msg.sender, tokens[i], _reward);
        }
    }

    function notifyRewardAmount(address token, uint256 amount) external lock {
        require(token != stake, "Invalid reward token");
        require(amount > 0, "Cannot notify 0");
        require(amount < type(uint128).max, "too much amount");
        uint128 amount = uint128(amount);

        RewardData memory _rewardData = rewardData[token]; // gas savings

        // update pool first
        _rewardData.rewardPerTokenStored = _rewardPerToken(_rewardData);
        _rewardData.lastUpdateTime = uint40(
            Math.min(block.timestamp, _rewardData.periodFinish)
        );

        // fetch current balance
        uint256 balanceBefore = erc20(token).balanceOf(address(this));

        // transfer tokens, recalculate amount in case of transfer-tax
        _safeTransferFrom(token, msg.sender, address(this), amount);
        amount = uint128(erc20(token).balanceOf(address(this)) - balanceBefore);

        if (block.timestamp >= _rewardData.periodFinish) {
            _rewardData.rewardRatePerWeek = amount;
        } else {
            uint40 _remaining = _rewardData.periodFinish -
                uint40(block.timestamp);
            uint128 _left = uint128(
                (_remaining * _rewardData.rewardRatePerWeek) / DURATION
            );
            require(amount > _left || msg.sender == voter, "amount < left");
            _rewardData.rewardRatePerWeek = amount + _left;
        }
        require(_rewardData.rewardRatePerWeek > 0, "rewardRate too low");
        uint256 balance = erc20(token).balanceOf(address(this));
        require(
            _rewardData.rewardRatePerWeek <= balance,
            "Not enough tokens provided"
        );
        _rewardData.periodFinish = uint40(block.timestamp + DURATION);
        _rewardData.lastUpdateTime = uint40(block.timestamp);

        rewardData[token] = _rewardData;
        if (!isReward[token]) {
            isReward[token] = true;
            rewards.push(token);
        }

        emit NotifyReward(msg.sender, token, amount);
    }

    // Be VERY CAREFUL when using this, gauge does not track how much reward
    // is supposed to be in the contract, since it'll take too much gas
    // to record balance changes on every interaction just for the next to
    // 0 possibility that this function is used
    // Off-chain calculations should be double-checked before using this function
    function clawbackRewards(address token, uint256 amount)
        external
        onlyGovernance
    {
        require(token != stake, "Cannot clawback LP");

        require(amount > 0, "Cannot clawback 0");
        address generalFeesAddress = IVoterV2(voter).generalFees();

        // Approve amount and notifyReward for generalFees
        _safeApprove(token, generalFeesAddress, amount);
        IBaseV2GeneralFees(generalFeesAddress).notifyRewardAmount(
            token,
            amount
        );

        emit ClawbackRewards(token, amount);
    }

    /****************************************
                    SafeERC20
     ****************************************/

    function _safeTransfer(
        address token,
        address to,
        uint256 value
    ) internal {
        require(token.code.length > 0, "!contract");
        (bool success, bytes memory data) = token.call(
            abi.encodeWithSelector(erc20.transfer.selector, to, value)
        );
        require(
            success && (data.length == 0 || abi.decode(data, (bool))),
            "SafeERC20: safeTransfer low-level call failed"
        );
    }

    function _safeTransferFrom(
        address token,
        address from,
        address to,
        uint256 value
    ) internal {
        require(token.code.length > 0, "!contract");
        (bool success, bytes memory data) = token.call(
            abi.encodeWithSelector(erc20.transferFrom.selector, from, to, value)
        );
        require(
            success && (data.length == 0 || abi.decode(data, (bool))),
            "SafeERC20: safeTransferFrom low-level call failed"
        );
    }

    function _safeApprove(
        address token,
        address spender,
        uint256 value
    ) internal {
        require(token.code.length > 0, "!contract");
        (bool success, bytes memory data) = token.call(
            abi.encodeWithSelector(erc20.approve.selector, spender, value)
        );
        require(
            success && (data.length == 0 || abi.decode(data, (bool))),
            "SafeERC20: approve low-level call failed"
        );
    }
}

/**
 * @dev Changelog:
 *      - Deprecate createGaugeSingle()
 *      - Deprecate last_gauge;
 *      - Refactored createGauge();
 */
contract BaseV2GaugeFactory is SolidlyFactory {

    bool public isBoostPaused;

    function createGauge(
        address _pool,
        address _bribe,
        address _ve
    ) external returns (address lastGauge) {
        lastGauge = _deployChildProxy();
        GaugeV2(lastGauge).initialize(_pool, _bribe, _ve, msg.sender);
        return lastGauge;
    }

    function setBoostPaused(bool _state) external onlyGovernance {
        isBoostPaused = _state;
    }
}

File 2 of 7 : SolidlyChildImplementation.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.11;
import "./SolidlyImplementation.sol";
import "./interfaces/IFactory.sol";

contract SolidlyChildImplementation is SolidlyImplementation {
    bytes32 constant FACTORY_SLOT =
        0x547b500e425d72fd0723933cceefc203cef652b4736fd04250c3369b3e1a0a72; // keccak256('FACTORY') - 1

    modifier onlyFactory() {
        require(msg.sender == factoryAddress(), "only Factory");
        _;
    }

    /****************************************
                  VIEW METHODS 
     ****************************************/

    /**
     * @notice Fetch current governance address from factory
     * @return _governanceAddress Returns current governance address
     */
    function governanceAddress()
        public
        view
        override
        returns (address _governanceAddress)
    {
        return IFactory(factoryAddress()).governanceAddress();
    }

    function factoryAddress() public view returns (address _factory) {
        assembly {
            _factory := sload(FACTORY_SLOT)
        }
    }
}

File 3 of 7 : SolidlyFactory.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.11;
import "./SolidlyImplementation.sol";
import "./SolidlyChildProxy.sol";

contract SolidlyFactory is SolidlyImplementation {
    bytes32 constant CHILD_SUBIMPLEMENTATION_SLOT =
        0xa7461aa7cde97eb2572f8234e341359c6baae47e1feeb3c235edffe5f0fc089d; // keccak256('CHILD_SUBIMPLEMENTATION') - 1
    bytes32 constant CHILD_INTERFACE_SLOT =
        0x23762bb6469fe7a7bd6609262f442817ed09ca1f07add24ef069610d59c90649; // keccak256('CHILD_INTERFACE') - 1
    bytes32 constant SUBIMPLEMENTATION_SLOT =
        0xa1056f3ed783ff191ada02861fcb19d9ae3a8f50b739813a127951ef5290458d; // keccak256('SUBIMPLEMENTATION') - 1
    bytes32 constant INTERFACE_SLOT =
        0x4a9bf2931aa5eae439c602abae4bd662e7919244decac463e2e35fc862c5fb98; // keccak256('INTERFACE') - 1

    address public interfaceSourceAddress;

    function _deployChildProxy() internal returns (address) {
        address addr = address(new SolidlyChildProxy());

        return addr;
    }

    function _deployChildProxyWithSalt(bytes32 salt)
        internal
        returns (address)
    {
        address addr = address(new SolidlyChildProxy{salt: salt}());

        return addr;
    }

    function updateChildSubImplementationAddress(
        address _childSubImplementationAddress
    ) external onlyGovernance {
        assembly {
            sstore(CHILD_SUBIMPLEMENTATION_SLOT, _childSubImplementationAddress)
        }
    }

    function updateChildInterfaceAddress(address _childInterfaceAddress)
        external
        onlyGovernance
    {
        assembly {
            sstore(CHILD_INTERFACE_SLOT, _childInterfaceAddress)
        }
    }

    function childSubImplementationAddress()
        external
        view
        returns (address _childSubImplementation)
    {
        assembly {
            _childSubImplementation := sload(CHILD_SUBIMPLEMENTATION_SLOT)
        }
    }

    function childInterfaceAddress()
        external
        view
        returns (address _childInterface)
    {
        assembly {
            _childInterface := sload(CHILD_INTERFACE_SLOT)
        }
    }
}

File 4 of 7 : SolidlyChildProxy.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.11;
import "./SolidlyProxy.sol";
import "./interfaces/IFactory.sol";

/**
 * @notice Child Proxy deployed by factories for pairs, fees, gauges, and bribes. Calls back to the factory to fetch proxy implementation.
 */
contract SolidlyChildProxy is SolidlyProxy {
    bytes32 constant FACTORY_SLOT =
        0x547b500e425d72fd0723933cceefc203cef652b4736fd04250c3369b3e1a0a72; // keccak256('FACTORY') - 1

    modifier onlyFactory() {
        require(msg.sender == factoryAddress(), "only Factory");
        _;
    }

    /**
     * @notice Records factory address and current interface implementation
     */
    constructor() {
        address _factory = msg.sender;
        address _interface = IFactory(msg.sender).childInterfaceAddress();
        assembly {
            sstore(FACTORY_SLOT, _factory)
            sstore(IMPLEMENTATION_SLOT, _interface) // Storing the interface into EIP-1967's implementation slot so Etherscan picks up the interface
        }
    }

    /****************************************
                    SETTINGS
     ****************************************/

    /**
     * @notice Governance callable method to update the Factory address
     */
    function updateFactoryAddress(address _factory) external onlyGovernance {
        assembly {
            sstore(FACTORY_SLOT, _factory)
        }
    }

    /**
     * @notice Publically callable function to sync proxy interface with the one recorded in the factory
     */
    function updateInterfaceAddress() external {
        address _newInterfaceAddress = IFactory(factoryAddress())
            .childInterfaceAddress();
        require(
            implementationAddress() != _newInterfaceAddress,
            "Nothing to update"
        );
        assembly {
            sstore(IMPLEMENTATION_SLOT, _newInterfaceAddress)
        }
    }

    /****************************************
                  VIEW METHODS 
     ****************************************/

    /**
     * @notice Fetch current governance address from factory
     * @return _governanceAddress Returns current governance address
     */
    function governanceAddress()
        public
        view
        override
        returns (address _governanceAddress)
    {
        return IFactory(factoryAddress()).governanceAddress();
    }

    function factoryAddress() public view returns (address _factory) {
        assembly {
            _factory := sload(FACTORY_SLOT)
        }
    }

    /**
     *@notice Fetch address where actual contract logic is at
     */
    function subImplementationAddress()
        public
        view
        returns (address _subimplementation)
    {
        return IFactory(factoryAddress()).childSubImplementationAddress();
    }

    /**
     * @notice Fetch address where the interface for the contract is
     */
    function interfaceAddress()
        public
        view
        override
        returns (address _interface)
    {
        assembly {
            _interface := sload(IMPLEMENTATION_SLOT)
        }
    }

    /****************************************
                  FALLBACK METHODS 
     ****************************************/

    /**
     * @notice Fallback function that delegatecalls the subimplementation instead of what's in the IMPLEMENTATION_SLOT
     */
    function _delegateCallSubimplmentation() internal override {
        address contractLogic = IFactory(factoryAddress())
            .childSubImplementationAddress();
        assembly {
            calldatacopy(0x0, 0x0, calldatasize())
            let success := delegatecall(
                gas(),
                contractLogic,
                0x0,
                calldatasize(),
                0,
                0
            )
            let returnDataSize := returndatasize()
            returndatacopy(0, 0, returnDataSize)
            switch success
            case 0 {
                revert(0, returnDataSize)
            }
            default {
                return(0, returnDataSize)
            }
        }
    }

    fallback() external payable override {
        _delegateCallSubimplmentation();
    }

    receive() external payable override {
        _delegateCallSubimplmentation();
    }
}

File 5 of 7 : SolidlyImplementation.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.11;

/**
 * @title Solidly+ Implementation
 * @author Solidly+
 * @notice Governable implementation that relies on governance slot to be set by the proxy
 */
contract SolidlyImplementation {
    bytes32 constant GOVERNANCE_SLOT =
        0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; // keccak256('eip1967.proxy.admin')
    bytes32 constant INITIALIZED_SLOT =
        0x834ce84547018237034401a09067277cdcbe7bbf7d7d30f6b382b0a102b7b4a3; // keccak256('eip1967.proxy.initialized')

    /**
     * @notice Reverts if msg.sender is not governance
     */
    modifier onlyGovernance() {
        require(msg.sender == governanceAddress(), "Only governance");
        _;
    }

    /**
     * @notice Reverts if contract is already initialized
     * @dev U4sed by implementations to ensure initialize() is only called once
     */
    modifier notInitialized() {
        bool initialized;
        assembly {
            initialized := sload(INITIALIZED_SLOT)
            if eq(initialized, 1) {
                revert(0, 0)
            }
            sstore(INITIALIZED_SLOT, 1)
        }
        _;
    }

    /**
     * @notice Fetch current governance address
     * @return _governanceAddress Returns current governance address
     */
    function governanceAddress()
        public
        view
        virtual
        returns (address _governanceAddress)
    {
        assembly {
            _governanceAddress := sload(GOVERNANCE_SLOT)
        }
    }
}

File 6 of 7 : IFactory.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.11;

interface IFactory {
    function governanceAddress() external view returns (address);

    function childSubImplementationAddress() external view returns (address);

    function childInterfaceAddress() external view returns (address);
}

File 7 of 7 : SolidlyProxy.sol
// SPDX-License-Identifier: BUSL
pragma solidity 0.8.11;

/**
 * @title Solidly+ governance killable proxy
 * @author Solidly+
 * @notice EIP-1967 upgradeable proxy with the ability to kill governance and render the contract immutable
 */
contract SolidlyProxy {
    bytes32 constant IMPLEMENTATION_SLOT =
        0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; // keccak256('eip1967.proxy.implementation'), actually used for interface so etherscan picks up the interface
    bytes32 constant LOGIC_SLOT =
        0x5942be825425c77e56e4bce97986794ab0f100954e40fc1390ae0e003710a3ab; // keccak256('LOGIC') - 1, actual logic implementation
    bytes32 constant GOVERNANCE_SLOT =
        0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; // keccak256('eip1967.proxy.admin')
    bytes32 constant INITIALIZED_SLOT =
        0x834ce84547018237034401a09067277cdcbe7bbf7d7d30f6b382b0a102b7b4a3; // keccak256('eip1967.proxy.initialized')

    /**
     * @notice Reverts if msg.sender is not governance
     */
    modifier onlyGovernance() {
        require(msg.sender == governanceAddress(), "Only governance");
        _;
    }

    /**
     * @notice Reverts if contract is already initialized
     * @dev Used by implementations to ensure initialize() is only called once
     */
    modifier notInitialized() {
        bool initialized;
        assembly {
            initialized := sload(INITIALIZED_SLOT)
            if eq(initialized, 1) {
                revert(0, 0)
            }
            sstore(INITIALIZED_SLOT, 1)
        }
        _;
    }

    /**
     * @notice Sets up deployer as a proxy governance
     */
    constructor() {
        address _governanceAddress = msg.sender;
        assembly {
            sstore(GOVERNANCE_SLOT, _governanceAddress)
        }
    }

    /**
     * @notice Detect whether or not governance is killed
     * @return Return true if governance is killed, false if not
     * @dev If governance is killed this contract becomes immutable
     */
    function governanceIsKilled() public view returns (bool) {
        return governanceAddress() == address(0);
    }

    /**
     * @notice Kill governance, making this contract immutable
     * @dev Only governance can kil governance
     */
    function killGovernance() external onlyGovernance {
        updateGovernanceAddress(address(0));
    }

    /**
     * @notice Update implementation address
     * @param _interfaceAddress Address of the new interface
     * @dev Only governance can update implementation
     */
    function updateInterfaceAddress(address _interfaceAddress)
        external
        onlyGovernance
    {
        assembly {
            sstore(IMPLEMENTATION_SLOT, _interfaceAddress)
        }
    }

    /**
     * @notice Actually updates interface, kept for etherscan pattern recognition
     * @param _implementationAddress Address of the new implementation
     * @dev Only governance can update implementation
     */
    function updateImplementationAddress(address _implementationAddress)
        external
        onlyGovernance
    {
        assembly {
            sstore(IMPLEMENTATION_SLOT, _implementationAddress)
        }
    }

    /**
     * @notice Update implementation address
     * @param _logicAddress Address of the new implementation
     * @dev Only governance can update implementation
     */
    function updateLogicAddress(address _logicAddress) external onlyGovernance {
        assembly {
            sstore(LOGIC_SLOT, _logicAddress)
        }
    }

    /**
     * @notice Update governance address
     * @param _governanceAddress New governance address
     * @dev Only governance can update governance
     */
    function updateGovernanceAddress(address _governanceAddress)
        public
        onlyGovernance
    {
        assembly {
            sstore(GOVERNANCE_SLOT, _governanceAddress)
        }
    }

    /**
     * @notice Fetch the current implementation address
     * @return _implementationAddress Returns the current implementation address
     */
    function implementationAddress()
        public
        view
        returns (address _implementationAddress)
    {
        assembly {
            _implementationAddress := sload(IMPLEMENTATION_SLOT)
        }
    }

    /**
     * @notice Fetch the current implementation address
     * @return _interfaceAddress Returns the current implementation address
     */
    function interfaceAddress()
        public
        view
        virtual
        returns (address _interfaceAddress)
    {
        assembly {
            _interfaceAddress := sload(IMPLEMENTATION_SLOT)
        }
    }

    /**
     * @notice Fetch the current implementation address
     * @return _logicAddress Returns the current implementation address
     */
    function logicAddress()
        public
        view
        virtual
        returns (address _logicAddress)
    {
        assembly {
            _logicAddress := sload(LOGIC_SLOT)
        }
    }

    /**
     * @notice Fetch current governance address
     * @return _governanceAddress Returns current governance address
     */
    function governanceAddress()
        public
        view
        virtual
        returns (address _governanceAddress)
    {
        assembly {
            _governanceAddress := sload(GOVERNANCE_SLOT)
        }
    }

    /**
     * @notice Fallback function that delegatecalls the subimplementation instead of what's in the IMPLEMENTATION_SLOT
     */
    function _delegateCallSubimplmentation() internal virtual {
        assembly {
            let contractLogic := sload(LOGIC_SLOT)
            calldatacopy(0x0, 0x0, calldatasize())
            let success := delegatecall(
                gas(),
                contractLogic,
                0x0,
                calldatasize(),
                0,
                0
            )
            let returnDataSize := returndatasize()
            returndatacopy(0, 0, returnDataSize)
            switch success
            case 0 {
                revert(0, returnDataSize)
            }
            default {
                return(0, returnDataSize)
            }
        }
    }

    /**
     * @notice Delegatecall fallback proxy
     */
    fallback() external payable virtual {
        _delegateCallSubimplmentation();
    }

    receive() external payable virtual {
        _delegateCallSubimplmentation();
    }
}

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

Contract Security Audit

Contract ABI

[{"inputs":[],"name":"childInterfaceAddress","outputs":[{"internalType":"address","name":"_childInterface","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"childSubImplementationAddress","outputs":[{"internalType":"address","name":"_childSubImplementation","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_pool","type":"address"},{"internalType":"address","name":"_bribe","type":"address"},{"internalType":"address","name":"_ve","type":"address"}],"name":"createGauge","outputs":[{"internalType":"address","name":"lastGauge","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"governanceAddress","outputs":[{"internalType":"address","name":"_governanceAddress","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"interfaceSourceAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isBoostPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_state","type":"bool"}],"name":"setBoostPaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_childInterfaceAddress","type":"address"}],"name":"updateChildInterfaceAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_childSubImplementationAddress","type":"address"}],"name":"updateChildSubImplementationAddress","outputs":[],"stateMutability":"nonpayable","type":"function"}]

608060405234801561001057600080fd5b50610d27806100206000396000f3fe608060405234801561001057600080fd5b50600436106100935760003560e01c8063713561ae11610066578063713561ae14610103578063795053d3146101275780638c1a02171461013c5780638f5ffb8814610163578063bf4b5d361461017657600080fd5b80630dba8acb146100985780631c48e0fa146100c8578063294b4b60146100db5780635ae35d14146100f0575b600080fd5b6000546100ab906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6100ab6100d63660046103ad565b61019d565b6100ee6100e93660046103f0565b610223565b005b6100ee6100fe366004610419565b61028a565b60005461011790600160a01b900460ff1681565b60405190151581526020016100bf565b600080516020610cfb833981519152546100ab565b7f23762bb6469fe7a7bd6609262f442817ed09ca1f07add24ef069610d59c90649546100ab565b6100ee610171366004610419565b6102ee565b7fa7461aa7cde97eb2572f8234e341359c6baae47e1feeb3c235edffe5f0fc089d546100ab565b60006101a7610352565b604051637c643b2f60e11b81526001600160a01b038681166004830152858116602483015284811660448301523360648301529192509082169063f8c8765e90608401600060405180830381600087803b15801561020457600080fd5b505af1158015610218573d6000803e3d6000fd5b505050509392505050565b600080516020610cfb833981519152546001600160a01b0316336001600160a01b03161461026c5760405162461bcd60e51b815260040161026390610434565b60405180910390fd5b60008054911515600160a01b0260ff60a01b19909216919091179055565b600080516020610cfb833981519152546001600160a01b0316336001600160a01b0316146102ca5760405162461bcd60e51b815260040161026390610434565b7f23762bb6469fe7a7bd6609262f442817ed09ca1f07add24ef069610d59c9064955565b600080516020610cfb833981519152546001600160a01b0316336001600160a01b03161461032e5760405162461bcd60e51b815260040161026390610434565b7fa7461aa7cde97eb2572f8234e341359c6baae47e1feeb3c235edffe5f0fc089d55565b60008060405161036190610384565b604051809103906000f08015801561037d573d6000803e3d6000fd5b5092915050565b61089d8061045e83390190565b80356001600160a01b03811681146103a857600080fd5b919050565b6000806000606084860312156103c257600080fd5b6103cb84610391565b92506103d960208501610391565b91506103e760408501610391565b90509250925092565b60006020828403121561040257600080fd5b8135801515811461041257600080fd5b9392505050565b60006020828403121561042b57600080fd5b61041282610391565b6020808252600f908201526e4f6e6c7920676f7665726e616e636560881b60408201526060019056fe608060405234801561001057600080fd5b50337fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d610381905560408051638c1a021760e01b815290516000918391638c1a0217916004808201926020929091908290030181865afa158015610076573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061009a91906100e7565b7f547b500e425d72fd0723933cceefc203cef652b4736fd04250c3369b3e1a0a7292909255507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc55610117565b6000602082840312156100f957600080fd5b81516001600160a01b038116811461011057600080fd5b9392505050565b610777806101266000396000f3fe6080604052600436106100e15760003560e01c8063a99f141f1161007f578063b90d893011610059578063b90d893014610258578063b97a231914610204578063cf6126ed14610278578063eb5ee83a14610278576100f0565b8063a99f141f146101ef578063aa8a675414610204578063b56fbb9714610238576100f0565b8063654ea5e7116100bb578063654ea5e71461016f578063795053d314610184578063966dae0e146101995780639c1fcc4c146101bb576100f0565b8063179781c4146100f85780633c2b053a14610122578063551ee5701461014f576100f0565b366100f0576100ee610298565b005b6100ee610298565b34801561010457600080fd5b5061010d610338565b60405190151581526020015b60405180910390f35b34801561012e57600080fd5b50610137610352565b6040516001600160a01b039091168152602001610119565b34801561015b57600080fd5b506100ee61016a3660046106e0565b6103d0565b34801561017b57600080fd5b506100ee610423565b34801561019057600080fd5b50610137610467565b3480156101a557600080fd5b5060008051602061074b83398151915254610137565b3480156101c757600080fd5b507f5942be825425c77e56e4bce97986794ab0f100954e40fc1390ae0e003710a3ab54610137565b3480156101fb57600080fd5b506100ee6104bc565b34801561021057600080fd5b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc54610137565b34801561024457600080fd5b506100ee6102533660046106e0565b6105d8565b34801561026457600080fd5b506100ee6102733660046106e0565b610634565b34801561028457600080fd5b506100ee6102933660046106e0565b610690565b60006102b060008051602061074b8339815191525490565b6001600160a01b031663bf4b5d366040518163ffffffff1660e01b8152600401602060405180830381865afa1580156102ed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103119190610704565b90503660008037600080366000845af43d806000803e81801561033357816000f35b816000fd5b600080610343610467565b6001600160a01b031614905090565b600061036a60008051602061074b8339815191525490565b6001600160a01b031663bf4b5d366040518163ffffffff1660e01b8152600401602060405180830381865afa1580156103a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103cb9190610704565b905090565b6103d8610467565b6001600160a01b0316336001600160a01b0316146104115760405162461bcd60e51b815260040161040890610721565b60405180910390fd5b60008051602061074b83398151915255565b61042b610467565b6001600160a01b0316336001600160a01b03161461045b5760405162461bcd60e51b815260040161040890610721565b6104656000610634565b565b600061047f60008051602061074b8339815191525490565b6001600160a01b031663795053d36040518163ffffffff1660e01b8152600401602060405180830381865afa1580156103a7573d6000803e3d6000fd5b60006104d460008051602061074b8339815191525490565b6001600160a01b0316638c1a02176040518163ffffffff1660e01b8152600401602060405180830381865afa158015610511573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105359190610704565b9050806001600160a01b03166105697f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b6001600160a01b031614156105b45760405162461bcd60e51b81526020600482015260116024820152704e6f7468696e6720746f2075706461746560781b6044820152606401610408565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc55565b6105e0610467565b6001600160a01b0316336001600160a01b0316146106105760405162461bcd60e51b815260040161040890610721565b7f5942be825425c77e56e4bce97986794ab0f100954e40fc1390ae0e003710a3ab55565b61063c610467565b6001600160a01b0316336001600160a01b03161461066c5760405162461bcd60e51b815260040161040890610721565b7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d610355565b610698610467565b6001600160a01b0316336001600160a01b0316146105b45760405162461bcd60e51b815260040161040890610721565b6001600160a01b03811681146106dd57600080fd5b50565b6000602082840312156106f257600080fd5b81356106fd816106c8565b9392505050565b60006020828403121561071657600080fd5b81516106fd816106c8565b6020808252600f908201526e4f6e6c7920676f7665726e616e636560881b60408201526060019056fe547b500e425d72fd0723933cceefc203cef652b4736fd04250c3369b3e1a0a72a164736f6c634300080b000ab53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103a164736f6c634300080b000a

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106100935760003560e01c8063713561ae11610066578063713561ae14610103578063795053d3146101275780638c1a02171461013c5780638f5ffb8814610163578063bf4b5d361461017657600080fd5b80630dba8acb146100985780631c48e0fa146100c8578063294b4b60146100db5780635ae35d14146100f0575b600080fd5b6000546100ab906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6100ab6100d63660046103ad565b61019d565b6100ee6100e93660046103f0565b610223565b005b6100ee6100fe366004610419565b61028a565b60005461011790600160a01b900460ff1681565b60405190151581526020016100bf565b600080516020610cfb833981519152546100ab565b7f23762bb6469fe7a7bd6609262f442817ed09ca1f07add24ef069610d59c90649546100ab565b6100ee610171366004610419565b6102ee565b7fa7461aa7cde97eb2572f8234e341359c6baae47e1feeb3c235edffe5f0fc089d546100ab565b60006101a7610352565b604051637c643b2f60e11b81526001600160a01b038681166004830152858116602483015284811660448301523360648301529192509082169063f8c8765e90608401600060405180830381600087803b15801561020457600080fd5b505af1158015610218573d6000803e3d6000fd5b505050509392505050565b600080516020610cfb833981519152546001600160a01b0316336001600160a01b03161461026c5760405162461bcd60e51b815260040161026390610434565b60405180910390fd5b60008054911515600160a01b0260ff60a01b19909216919091179055565b600080516020610cfb833981519152546001600160a01b0316336001600160a01b0316146102ca5760405162461bcd60e51b815260040161026390610434565b7f23762bb6469fe7a7bd6609262f442817ed09ca1f07add24ef069610d59c9064955565b600080516020610cfb833981519152546001600160a01b0316336001600160a01b03161461032e5760405162461bcd60e51b815260040161026390610434565b7fa7461aa7cde97eb2572f8234e341359c6baae47e1feeb3c235edffe5f0fc089d55565b60008060405161036190610384565b604051809103906000f08015801561037d573d6000803e3d6000fd5b5092915050565b61089d8061045e83390190565b80356001600160a01b03811681146103a857600080fd5b919050565b6000806000606084860312156103c257600080fd5b6103cb84610391565b92506103d960208501610391565b91506103e760408501610391565b90509250925092565b60006020828403121561040257600080fd5b8135801515811461041257600080fd5b9392505050565b60006020828403121561042b57600080fd5b61041282610391565b6020808252600f908201526e4f6e6c7920676f7665726e616e636560881b60408201526060019056fe608060405234801561001057600080fd5b50337fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d610381905560408051638c1a021760e01b815290516000918391638c1a0217916004808201926020929091908290030181865afa158015610076573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061009a91906100e7565b7f547b500e425d72fd0723933cceefc203cef652b4736fd04250c3369b3e1a0a7292909255507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc55610117565b6000602082840312156100f957600080fd5b81516001600160a01b038116811461011057600080fd5b9392505050565b610777806101266000396000f3fe6080604052600436106100e15760003560e01c8063a99f141f1161007f578063b90d893011610059578063b90d893014610258578063b97a231914610204578063cf6126ed14610278578063eb5ee83a14610278576100f0565b8063a99f141f146101ef578063aa8a675414610204578063b56fbb9714610238576100f0565b8063654ea5e7116100bb578063654ea5e71461016f578063795053d314610184578063966dae0e146101995780639c1fcc4c146101bb576100f0565b8063179781c4146100f85780633c2b053a14610122578063551ee5701461014f576100f0565b366100f0576100ee610298565b005b6100ee610298565b34801561010457600080fd5b5061010d610338565b60405190151581526020015b60405180910390f35b34801561012e57600080fd5b50610137610352565b6040516001600160a01b039091168152602001610119565b34801561015b57600080fd5b506100ee61016a3660046106e0565b6103d0565b34801561017b57600080fd5b506100ee610423565b34801561019057600080fd5b50610137610467565b3480156101a557600080fd5b5060008051602061074b83398151915254610137565b3480156101c757600080fd5b507f5942be825425c77e56e4bce97986794ab0f100954e40fc1390ae0e003710a3ab54610137565b3480156101fb57600080fd5b506100ee6104bc565b34801561021057600080fd5b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc54610137565b34801561024457600080fd5b506100ee6102533660046106e0565b6105d8565b34801561026457600080fd5b506100ee6102733660046106e0565b610634565b34801561028457600080fd5b506100ee6102933660046106e0565b610690565b60006102b060008051602061074b8339815191525490565b6001600160a01b031663bf4b5d366040518163ffffffff1660e01b8152600401602060405180830381865afa1580156102ed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103119190610704565b90503660008037600080366000845af43d806000803e81801561033357816000f35b816000fd5b600080610343610467565b6001600160a01b031614905090565b600061036a60008051602061074b8339815191525490565b6001600160a01b031663bf4b5d366040518163ffffffff1660e01b8152600401602060405180830381865afa1580156103a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103cb9190610704565b905090565b6103d8610467565b6001600160a01b0316336001600160a01b0316146104115760405162461bcd60e51b815260040161040890610721565b60405180910390fd5b60008051602061074b83398151915255565b61042b610467565b6001600160a01b0316336001600160a01b03161461045b5760405162461bcd60e51b815260040161040890610721565b6104656000610634565b565b600061047f60008051602061074b8339815191525490565b6001600160a01b031663795053d36040518163ffffffff1660e01b8152600401602060405180830381865afa1580156103a7573d6000803e3d6000fd5b60006104d460008051602061074b8339815191525490565b6001600160a01b0316638c1a02176040518163ffffffff1660e01b8152600401602060405180830381865afa158015610511573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105359190610704565b9050806001600160a01b03166105697f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b6001600160a01b031614156105b45760405162461bcd60e51b81526020600482015260116024820152704e6f7468696e6720746f2075706461746560781b6044820152606401610408565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc55565b6105e0610467565b6001600160a01b0316336001600160a01b0316146106105760405162461bcd60e51b815260040161040890610721565b7f5942be825425c77e56e4bce97986794ab0f100954e40fc1390ae0e003710a3ab55565b61063c610467565b6001600160a01b0316336001600160a01b03161461066c5760405162461bcd60e51b815260040161040890610721565b7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d610355565b610698610467565b6001600160a01b0316336001600160a01b0316146105b45760405162461bcd60e51b815260040161040890610721565b6001600160a01b03811681146106dd57600080fd5b50565b6000602082840312156106f257600080fd5b81356106fd816106c8565b9392505050565b60006020828403121561071657600080fd5b81516106fd816106c8565b6020808252600f908201526e4f6e6c7920676f7665726e616e636560881b60408201526060019056fe547b500e425d72fd0723933cceefc203cef652b4736fd04250c3369b3e1a0a72a164736f6c634300080b000ab53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103a164736f6c634300080b000a

Deployed Bytecode Sourcemap

29075:470:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;822:37:3;;;;;-1:-1:-1;;;;;822:37:3;;;;;;-1:-1:-1;;;;;178:32:7;;;160:51;;148:2;133:18;822:37:3;;;;;;;;29160:277:0;;;;;;:::i;:::-;;:::i;29443:100::-;;;;;;:::i;:::-;;:::i;:::-;;1460:214:3;;;;;;:::i;:::-;;:::i;29128:25:0:-;;;;;-1:-1:-1;;;29128:25:0;;;;;;;;;1373:14:7;;1366:22;1348:41;;1336:2;1321:18;29128:25:0;1208:187:7;1316:215:4;-1:-1:-1;;;;;;;;;;;1493:22:4;1316:215;;1922:204:3;2089:20;2083:27;1922:204;;1214:240;;;;;;:::i;:::-;;:::i;1680:236::-;1871:28;1865:35;1680:236;;29160:277:0;29273:17;29314:19;:17;:19::i;:::-;29343:61;;-1:-1:-1;;;29343:61:0;;-1:-1:-1;;;;;1687:15:7;;;29343:61:0;;;1669:34:7;1739:15;;;1719:18;;;1712:43;1791:15;;;1771:18;;;1764:43;29393:10:0;1823:18:7;;;1816:43;29302:31:0;;-1:-1:-1;29343:29:0;;;;;;1603:19:7;;29343:61:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;29160:277;;;;;:::o;29443:100::-;-1:-1:-1;;;;;;;;;;;1493:22:4;-1:-1:-1;;;;;677:33:4;:10;-1:-1:-1;;;;;677:33:4;;669:61;;;;-1:-1:-1;;;669:61:4;;;;;;;:::i;:::-;;;;;;;;;29514:13:0::1;:22:::0;;;::::1;;-1:-1:-1::0;;;29514:22:0::1;-1:-1:-1::0;;;;29514:22:0;;::::1;::::0;;;::::1;::::0;;29443:100::o;1460:214:3:-;-1:-1:-1;;;;;;;;;;;1493:22:4;-1:-1:-1;;;;;677:33:4;:10;-1:-1:-1;;;;;677:33:4;;669:61;;;;-1:-1:-1;;;669:61:4;;;;;;;:::i;:::-;1613:20:3::1;1606:52:::0;1460:214::o;1214:240::-;-1:-1:-1;;;;;;;;;;;1493:22:4;-1:-1:-1;;;;;677:33:4;:10;-1:-1:-1;;;;;677:33:4;;669:61;;;;-1:-1:-1;;;669:61:4;;;;;;;:::i;:::-;1377:28:3::1;1370:68:::0;1214:240::o;866:142::-;913:7;932:12;955:23;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;932:47:3;866:142;-1:-1:-1;;866:142:3:o;-1:-1:-1:-;;;;;;;;:::o;222:173:7:-;290:20;;-1:-1:-1;;;;;339:31:7;;329:42;;319:70;;385:1;382;375:12;319:70;222:173;;;:::o;400:334::-;477:6;485;493;546:2;534:9;525:7;521:23;517:32;514:52;;;562:1;559;552:12;514:52;585:29;604:9;585:29;:::i;:::-;575:39;;633:38;667:2;656:9;652:18;633:38;:::i;:::-;623:48;;690:38;724:2;713:9;709:18;690:38;:::i;:::-;680:48;;400:334;;;;;:::o;739:273::-;795:6;848:2;836:9;827:7;823:23;819:32;816:52;;;864:1;861;854:12;816:52;903:9;890:23;956:5;949:13;942:21;935:5;932:32;922:60;;978:1;975;968:12;922:60;1001:5;739:273;-1:-1:-1;;;739:273:7:o;1017:186::-;1076:6;1129:2;1117:9;1108:7;1104:23;1100:32;1097:52;;;1145:1;1142;1135:12;1097:52;1168:29;1187:9;1168:29;:::i;1870:339::-;2072:2;2054:21;;;2111:2;2091:18;;;2084:30;-1:-1:-1;;;2145:2:7;2130:18;;2123:45;2200:2;2185:18;;1870:339::o

Swarm Source

none

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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