Contract 0xA84EA94Aa705F7d009CDDF2a60f65c0d446b748E 1

 
Txn Hash Method
Index
From
To
Value
0x0ec412db322134db6666b45835621a6407e66847e324443992baf50e40cea9d80x60806040100786782022-06-01 20:01:38121 days 3 hrs agoVelodrome Finance: Deployer IN  Create: BribeFactory0 Ether0.0354477752280.001
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0x01201a4a92906d697f5375633399778eebd218df7bdd083cbc5b1093e4ad9ea7263351552022-09-29 20:53:321 day 2 hrs ago 0xa84ea94aa705f7d009cddf2a60f65c0d446b748e  Contract Creation0 Ether
0x01201a4a92906d697f5375633399778eebd218df7bdd083cbc5b1093e4ad9ea7263351552022-09-29 20:53:321 day 2 hrs ago 0x09236cff45047dbee6b921e00704bed6d6b8cf7e 0xa84ea94aa705f7d009cddf2a60f65c0d446b748e0 Ether
0x01201a4a92906d697f5375633399778eebd218df7bdd083cbc5b1093e4ad9ea7263351552022-09-29 20:53:321 day 2 hrs ago 0xa84ea94aa705f7d009cddf2a60f65c0d446b748e  Contract Creation0 Ether
0x01201a4a92906d697f5375633399778eebd218df7bdd083cbc5b1093e4ad9ea7263351552022-09-29 20:53:321 day 2 hrs ago 0x09236cff45047dbee6b921e00704bed6d6b8cf7e 0xa84ea94aa705f7d009cddf2a60f65c0d446b748e0 Ether
0x5dbaafd6eb7cb5a510f473bf67c110a3032196bde37a30b9c32095fce6535f40259155922022-09-28 6:27:412 days 16 hrs ago 0xa84ea94aa705f7d009cddf2a60f65c0d446b748e  Contract Creation0 Ether
0x5dbaafd6eb7cb5a510f473bf67c110a3032196bde37a30b9c32095fce6535f40259155922022-09-28 6:27:412 days 16 hrs ago 0x09236cff45047dbee6b921e00704bed6d6b8cf7e 0xa84ea94aa705f7d009cddf2a60f65c0d446b748e0 Ether
0x5dbaafd6eb7cb5a510f473bf67c110a3032196bde37a30b9c32095fce6535f40259155922022-09-28 6:27:412 days 16 hrs ago 0xa84ea94aa705f7d009cddf2a60f65c0d446b748e  Contract Creation0 Ether
0x5dbaafd6eb7cb5a510f473bf67c110a3032196bde37a30b9c32095fce6535f40259155922022-09-28 6:27:412 days 16 hrs ago 0x09236cff45047dbee6b921e00704bed6d6b8cf7e 0xa84ea94aa705f7d009cddf2a60f65c0d446b748e0 Ether
0x571f894cf57ba4cb1adbb5141c2fc757f354077128c4b3a1f45f0813b3d82a75257442822022-09-27 11:43:063 days 11 hrs ago 0xa84ea94aa705f7d009cddf2a60f65c0d446b748e  Contract Creation0 Ether
0x571f894cf57ba4cb1adbb5141c2fc757f354077128c4b3a1f45f0813b3d82a75257442822022-09-27 11:43:063 days 11 hrs ago 0x09236cff45047dbee6b921e00704bed6d6b8cf7e 0xa84ea94aa705f7d009cddf2a60f65c0d446b748e0 Ether
0x571f894cf57ba4cb1adbb5141c2fc757f354077128c4b3a1f45f0813b3d82a75257442822022-09-27 11:43:063 days 11 hrs ago 0xa84ea94aa705f7d009cddf2a60f65c0d446b748e  Contract Creation0 Ether
0x571f894cf57ba4cb1adbb5141c2fc757f354077128c4b3a1f45f0813b3d82a75257442822022-09-27 11:43:063 days 11 hrs ago 0x09236cff45047dbee6b921e00704bed6d6b8cf7e 0xa84ea94aa705f7d009cddf2a60f65c0d446b748e0 Ether
0x13375016c59f88af8366686426afe877c54d104839a3066c9da0711355c2f840257082382022-09-27 7:40:433 days 15 hrs ago 0xa84ea94aa705f7d009cddf2a60f65c0d446b748e  Contract Creation0 Ether
0x13375016c59f88af8366686426afe877c54d104839a3066c9da0711355c2f840257082382022-09-27 7:40:433 days 15 hrs ago 0x09236cff45047dbee6b921e00704bed6d6b8cf7e 0xa84ea94aa705f7d009cddf2a60f65c0d446b748e0 Ether
0x13375016c59f88af8366686426afe877c54d104839a3066c9da0711355c2f840257082382022-09-27 7:40:433 days 15 hrs ago 0xa84ea94aa705f7d009cddf2a60f65c0d446b748e  Contract Creation0 Ether
0x13375016c59f88af8366686426afe877c54d104839a3066c9da0711355c2f840257082382022-09-27 7:40:433 days 15 hrs ago 0x09236cff45047dbee6b921e00704bed6d6b8cf7e 0xa84ea94aa705f7d009cddf2a60f65c0d446b748e0 Ether
0x7f3c1c1f516ecd94df679c5635f517aef17e78e6d01f7f7b4243e989006a8cca256098622022-09-26 17:24:234 days 5 hrs ago 0xa84ea94aa705f7d009cddf2a60f65c0d446b748e  Contract Creation0 Ether
0x7f3c1c1f516ecd94df679c5635f517aef17e78e6d01f7f7b4243e989006a8cca256098622022-09-26 17:24:234 days 5 hrs ago 0x09236cff45047dbee6b921e00704bed6d6b8cf7e 0xa84ea94aa705f7d009cddf2a60f65c0d446b748e0 Ether
0x7f3c1c1f516ecd94df679c5635f517aef17e78e6d01f7f7b4243e989006a8cca256098622022-09-26 17:24:234 days 5 hrs ago 0xa84ea94aa705f7d009cddf2a60f65c0d446b748e  Contract Creation0 Ether
0x7f3c1c1f516ecd94df679c5635f517aef17e78e6d01f7f7b4243e989006a8cca256098622022-09-26 17:24:234 days 5 hrs ago 0x09236cff45047dbee6b921e00704bed6d6b8cf7e 0xa84ea94aa705f7d009cddf2a60f65c0d446b748e0 Ether
0x96dcab4171bb6a83972b2655722b58df9381036206f6a74ee033abed6f5ed890255728862022-09-26 13:51:134 days 9 hrs ago 0xa84ea94aa705f7d009cddf2a60f65c0d446b748e  Contract Creation0 Ether
0x96dcab4171bb6a83972b2655722b58df9381036206f6a74ee033abed6f5ed890255728862022-09-26 13:51:134 days 9 hrs ago 0x09236cff45047dbee6b921e00704bed6d6b8cf7e 0xa84ea94aa705f7d009cddf2a60f65c0d446b748e0 Ether
0x96dcab4171bb6a83972b2655722b58df9381036206f6a74ee033abed6f5ed890255728862022-09-26 13:51:134 days 9 hrs ago 0xa84ea94aa705f7d009cddf2a60f65c0d446b748e  Contract Creation0 Ether
0x96dcab4171bb6a83972b2655722b58df9381036206f6a74ee033abed6f5ed890255728862022-09-26 13:51:134 days 9 hrs ago 0x09236cff45047dbee6b921e00704bed6d6b8cf7e 0xa84ea94aa705f7d009cddf2a60f65c0d446b748e0 Ether
0xb8b751b1840b1217a61cc136c90a9f20c5433a43fd84dcb0e4f27dfa0fe88b66253577502022-09-25 15:49:075 days 7 hrs ago 0xa84ea94aa705f7d009cddf2a60f65c0d446b748e  Contract Creation0 Ether
[ Download CSV Export 
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
BribeFactory

Compiler Version
v0.8.13+commit.abaa5c0e

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 10 : BribeFactory.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.13;

import "contracts/interfaces/IBribeFactory.sol";
import 'contracts/InternalBribe.sol';
import 'contracts/ExternalBribe.sol';

contract BribeFactory is IBribeFactory {
    address public last_internal_bribe;
    address public last_external_bribe;

    function createInternalBribe(address[] memory allowedRewards) external returns (address) {
        last_internal_bribe = address(new InternalBribe(msg.sender, allowedRewards));
        return last_internal_bribe;
    }

    function createExternalBribe(address[] memory allowedRewards) external returns (address) {
        last_external_bribe = address(new ExternalBribe(msg.sender, allowedRewards));
        return last_external_bribe;
    }
}

File 2 of 10 : IBribeFactory.sol
pragma solidity 0.8.13;

interface IBribeFactory {
    function createInternalBribe(address[] memory) external returns (address);
    function createExternalBribe(address[] memory) external returns (address);
}

File 3 of 10 : InternalBribe.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.13;

import 'contracts/libraries/Math.sol';
import 'contracts/interfaces/IBribe.sol';
import 'contracts/interfaces/IERC20.sol';
import 'contracts/interfaces/IVoter.sol';
import 'contracts/interfaces/IVotingEscrow.sol';

// Bribes pay out rewards for a given pool based on the votes that were received from the user (goes hand in hand with Voter.vote())
contract InternalBribe is IBribe {

    address public immutable voter; // only voter can modify balances (since it only happens on vote())
    address public immutable _ve;

    uint public constant DURATION = 7 days; // rewards are released over 7 days
    uint public constant PRECISION = 10 ** 18;
    uint internal constant MAX_REWARD_TOKENS = 16;

    // default snx staking contract implementation
    mapping(address => uint) public rewardRate;
    mapping(address => uint) public periodFinish;
    mapping(address => uint) public lastUpdateTime;
    mapping(address => uint) public rewardPerTokenStored;

    mapping(address => mapping(uint => uint)) public lastEarn;
    mapping(address => mapping(uint => uint)) public userRewardPerTokenStored;

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

    uint public totalSupply;
    mapping(uint => uint) public balanceOf;

    /// @notice A checkpoint for marking balance
    struct Checkpoint {
        uint timestamp;
        uint balanceOf;
    }

    /// @notice A checkpoint for marking reward rate
    struct RewardPerTokenCheckpoint {
        uint timestamp;
        uint rewardPerToken;
    }

    /// @notice A checkpoint for marking supply
    struct SupplyCheckpoint {
        uint timestamp;
        uint supply;
    }

    /// @notice A record of balance checkpoints for each account, by index
    mapping (uint => mapping (uint => Checkpoint)) public checkpoints;
    /// @notice The number of checkpoints for each account
    mapping (uint => uint) public numCheckpoints;
    /// @notice A record of balance checkpoints for each token, by index
    mapping (uint => SupplyCheckpoint) public supplyCheckpoints;
    /// @notice The number of checkpoints
    uint public supplyNumCheckpoints;
    /// @notice A record of balance checkpoints for each token, by index
    mapping (address => mapping (uint => RewardPerTokenCheckpoint)) public rewardPerTokenCheckpoints;
    /// @notice The number of checkpoints for each token
    mapping (address => uint) public rewardPerTokenNumCheckpoints;

    event Deposit(address indexed from, uint tokenId, uint amount);
    event Withdraw(address indexed from, uint tokenId, uint amount);
    event NotifyReward(address indexed from, address indexed reward, uint amount);
    event ClaimRewards(address indexed from, address indexed reward, uint amount);

    constructor(address _voter, address[] memory _allowedRewardTokens) {
        voter = _voter;
        _ve = IVoter(_voter)._ve();

        for (uint i; i < _allowedRewardTokens.length; i++) {
            if (_allowedRewardTokens[i] != address(0)) {
                isReward[_allowedRewardTokens[i]] = true;
                rewards.push(_allowedRewardTokens[i]);
            }
        }
    }

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

    /**
    * @notice Determine the prior balance for an account as of a block number
    * @dev Block number must be a finalized block or else this function will revert to prevent misinformation.
    * @param tokenId The token of the NFT to check
    * @param timestamp The timestamp to get the balance at
    * @return The balance the account had as of the given block
    */
    function getPriorBalanceIndex(uint tokenId, uint timestamp) public view returns (uint) {
        uint nCheckpoints = numCheckpoints[tokenId];
        if (nCheckpoints == 0) {
            return 0;
        }

        // First check most recent balance
        if (checkpoints[tokenId][nCheckpoints - 1].timestamp <= timestamp) {
            return (nCheckpoints - 1);
        }

        // Next check implicit zero balance
        if (checkpoints[tokenId][0].timestamp > timestamp) {
            return 0;
        }

        uint lower = 0;
        uint upper = nCheckpoints - 1;
        while (upper > lower) {
            uint center = upper - (upper - lower) / 2; // ceil, avoiding overflow
            Checkpoint memory cp = checkpoints[tokenId][center];
            if (cp.timestamp == timestamp) {
                return center;
            } else if (cp.timestamp < timestamp) {
                lower = center;
            } else {
                upper = center - 1;
            }
        }
        return lower;
    }

    function getPriorSupplyIndex(uint timestamp) public view returns (uint) {
        uint nCheckpoints = supplyNumCheckpoints;
        if (nCheckpoints == 0) {
            return 0;
        }

        // First check most recent balance
        if (supplyCheckpoints[nCheckpoints - 1].timestamp <= timestamp) {
            return (nCheckpoints - 1);
        }

        // Next check implicit zero balance
        if (supplyCheckpoints[0].timestamp > timestamp) {
            return 0;
        }

        uint lower = 0;
        uint upper = nCheckpoints - 1;
        while (upper > lower) {
            uint center = upper - (upper - lower) / 2; // ceil, avoiding overflow
            SupplyCheckpoint memory cp = supplyCheckpoints[center];
            if (cp.timestamp == timestamp) {
                return center;
            } else if (cp.timestamp < timestamp) {
                lower = center;
            } else {
                upper = center - 1;
            }
        }
        return lower;
    }

    function getPriorRewardPerToken(address token, uint timestamp) public view returns (uint, uint) {
        uint nCheckpoints = rewardPerTokenNumCheckpoints[token];
        if (nCheckpoints == 0) {
            return (0,0);
        }

        // First check most recent balance
        if (rewardPerTokenCheckpoints[token][nCheckpoints - 1].timestamp <= timestamp) {
            return (rewardPerTokenCheckpoints[token][nCheckpoints - 1].rewardPerToken, rewardPerTokenCheckpoints[token][nCheckpoints - 1].timestamp);
        }

        // Next check implicit zero balance
        if (rewardPerTokenCheckpoints[token][0].timestamp > timestamp) {
            return (0,0);
        }

        uint lower = 0;
        uint upper = nCheckpoints - 1;
        while (upper > lower) {
            uint center = upper - (upper - lower) / 2; // ceil, avoiding overflow
            RewardPerTokenCheckpoint memory cp = rewardPerTokenCheckpoints[token][center];
            if (cp.timestamp == timestamp) {
                return (cp.rewardPerToken, cp.timestamp);
            } else if (cp.timestamp < timestamp) {
                lower = center;
            } else {
                upper = center - 1;
            }
        }
        return (rewardPerTokenCheckpoints[token][lower].rewardPerToken, rewardPerTokenCheckpoints[token][lower].timestamp);
    }

    function _writeCheckpoint(uint tokenId, uint balance) internal {
        uint _timestamp = block.timestamp;
        uint _nCheckPoints = numCheckpoints[tokenId];

        if (_nCheckPoints > 0 && checkpoints[tokenId][_nCheckPoints - 1].timestamp == _timestamp) {
            checkpoints[tokenId][_nCheckPoints - 1].balanceOf = balance;
        } else {
            checkpoints[tokenId][_nCheckPoints] = Checkpoint(_timestamp, balance);
            numCheckpoints[tokenId] = _nCheckPoints + 1;
        }
    }

    function _writeRewardPerTokenCheckpoint(address token, uint reward, uint timestamp) internal {
        uint _nCheckPoints = rewardPerTokenNumCheckpoints[token];

        if (_nCheckPoints > 0 && rewardPerTokenCheckpoints[token][_nCheckPoints - 1].timestamp == timestamp) {
            rewardPerTokenCheckpoints[token][_nCheckPoints - 1].rewardPerToken = reward;
        } else {
            rewardPerTokenCheckpoints[token][_nCheckPoints] = RewardPerTokenCheckpoint(timestamp, reward);
            rewardPerTokenNumCheckpoints[token] = _nCheckPoints + 1;
        }
    }

    function _writeSupplyCheckpoint() internal {
        uint _nCheckPoints = supplyNumCheckpoints;
        uint _timestamp = block.timestamp;

        if (_nCheckPoints > 0 && supplyCheckpoints[_nCheckPoints - 1].timestamp == _timestamp) {
            supplyCheckpoints[_nCheckPoints - 1].supply = totalSupply;
        } else {
            supplyCheckpoints[_nCheckPoints] = SupplyCheckpoint(_timestamp, totalSupply);
            supplyNumCheckpoints = _nCheckPoints + 1;
        }
    }

    function rewardsListLength() external view returns (uint) {
        return rewards.length;
    }

    // returns the last time the reward was modified or periodFinish if the reward has ended
    function lastTimeRewardApplicable(address token) public view returns (uint) {
        return Math.min(block.timestamp, periodFinish[token]);
    }

    // allows a user to claim rewards for a given token
    function getReward(uint tokenId, address[] memory tokens) external lock  {
        require(IVotingEscrow(_ve).isApprovedOrOwner(msg.sender, tokenId));
        for (uint i = 0; i < tokens.length; i++) {
            (rewardPerTokenStored[tokens[i]], lastUpdateTime[tokens[i]]) = _updateRewardPerToken(tokens[i], type(uint).max, true);

            uint _reward = earned(tokens[i], tokenId);
            lastEarn[tokens[i]][tokenId] = block.timestamp;
            userRewardPerTokenStored[tokens[i]][tokenId] = rewardPerTokenStored[tokens[i]];
            if (_reward > 0) _safeTransfer(tokens[i], msg.sender, _reward);

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

    // used by Voter to allow batched reward claims
    function getRewardForOwner(uint tokenId, address[] memory tokens) external lock  {
        require(msg.sender == voter);
        address _owner = IVotingEscrow(_ve).ownerOf(tokenId);
        for (uint i = 0; i < tokens.length; i++) {
            (rewardPerTokenStored[tokens[i]], lastUpdateTime[tokens[i]]) = _updateRewardPerToken(tokens[i], type(uint).max, true);

            uint _reward = earned(tokens[i], tokenId);
            lastEarn[tokens[i]][tokenId] = block.timestamp;
            userRewardPerTokenStored[tokens[i]][tokenId] = rewardPerTokenStored[tokens[i]];
            if (_reward > 0) _safeTransfer(tokens[i], _owner, _reward);

            emit ClaimRewards(_owner, tokens[i], _reward);
        }
    }

    function rewardPerToken(address token) public view returns (uint) {
        if (totalSupply == 0) {
            return rewardPerTokenStored[token];
        }
        return rewardPerTokenStored[token] + ((lastTimeRewardApplicable(token) - Math.min(lastUpdateTime[token], periodFinish[token])) * rewardRate[token] * PRECISION / totalSupply);
    }

    function batchRewardPerToken(address token, uint maxRuns) external {
        (rewardPerTokenStored[token], lastUpdateTime[token])  = _batchRewardPerToken(token, maxRuns);
    }

    function _batchRewardPerToken(address token, uint maxRuns) internal returns (uint, uint) {
        uint _startTimestamp = lastUpdateTime[token];
        uint reward = rewardPerTokenStored[token];

        if (supplyNumCheckpoints == 0) {
            return (reward, _startTimestamp);
        }

        if (rewardRate[token] == 0) {
            return (reward, block.timestamp);
        }

        uint _startIndex = getPriorSupplyIndex(_startTimestamp);
        uint _endIndex = Math.min(supplyNumCheckpoints-1, maxRuns);

        for (uint i = _startIndex; i < _endIndex; i++) {
            SupplyCheckpoint memory sp0 = supplyCheckpoints[i];
            if (sp0.supply > 0) {
                SupplyCheckpoint memory sp1 = supplyCheckpoints[i+1];
                (uint _reward, uint endTime) = _calcRewardPerToken(token, sp1.timestamp, sp0.timestamp, sp0.supply, _startTimestamp);
                reward += _reward;
                _writeRewardPerTokenCheckpoint(token, reward, endTime);
                _startTimestamp = endTime;
            }
        }

        return (reward, _startTimestamp);
    }

    function _calcRewardPerToken(address token, uint timestamp1, uint timestamp0, uint supply, uint startTimestamp) internal view returns (uint, uint) {
        uint endTime = Math.max(timestamp1, startTimestamp);
        return (((Math.min(endTime, periodFinish[token]) - Math.min(Math.max(timestamp0, startTimestamp), periodFinish[token])) * rewardRate[token] * PRECISION / supply), endTime);
    }

    /// @dev Update stored rewardPerToken values without the last one snapshot
    ///      If the contract will get "out of gas" error on users actions this will be helpful
    function batchUpdateRewardPerToken(address token, uint maxRuns) external {
      (rewardPerTokenStored[token], lastUpdateTime[token]) = _updateRewardPerToken(token, maxRuns, false);
    }

    function _updateRewardForAllTokens() internal {
      uint length = rewards.length;
      for (uint i; i < length; i++) {
        address token = rewards[i];
        (rewardPerTokenStored[token], lastUpdateTime[token]) = _updateRewardPerToken(token, type(uint).max, true);
      }
    }

    function _updateRewardPerToken(address token, uint maxRuns, bool actualLast) internal returns (uint, uint) {
        uint _startTimestamp = lastUpdateTime[token];
        uint reward = rewardPerTokenStored[token];

        if (supplyNumCheckpoints == 0) {
            return (reward, _startTimestamp);
        }

        if (rewardRate[token] == 0) {
            return (reward, block.timestamp);
        }

        uint _startIndex = getPriorSupplyIndex(_startTimestamp);
        uint _endIndex = Math.min(supplyNumCheckpoints - 1, maxRuns);

        if (_endIndex > 0) {
            for (uint i = _startIndex; i <= _endIndex - 1; i++) {
                SupplyCheckpoint memory sp0 = supplyCheckpoints[i];
                if (sp0.supply > 0) {
                    SupplyCheckpoint memory sp1 = supplyCheckpoints[i+1];
                    (uint _reward, uint _endTime) = _calcRewardPerToken(token, sp1.timestamp, sp0.timestamp, sp0.supply, _startTimestamp);
                    reward += _reward;
                    _writeRewardPerTokenCheckpoint(token, reward, _endTime);
                    _startTimestamp = _endTime;
                }
            }
        }

        if (actualLast) {
            SupplyCheckpoint memory sp = supplyCheckpoints[_endIndex];
            if (sp.supply > 0) {
                (uint _reward,) = _calcRewardPerToken(token, lastTimeRewardApplicable(token), Math.max(sp.timestamp, _startTimestamp), sp.supply, _startTimestamp);
                reward += _reward;
                _writeRewardPerTokenCheckpoint(token, reward, block.timestamp);
                _startTimestamp = block.timestamp;
            }
        }

        return (reward, _startTimestamp);
    }

    function earned(address token, uint tokenId) public view returns (uint) {
        uint _startTimestamp = Math.max(lastEarn[token][tokenId], rewardPerTokenCheckpoints[token][0].timestamp);
        if (numCheckpoints[tokenId] == 0) {
            return 0;
        }

        uint _startIndex = getPriorBalanceIndex(tokenId, _startTimestamp);
        uint _endIndex = numCheckpoints[tokenId]-1;

        uint reward = 0;

        if (_endIndex > 0) {
            for (uint i = _startIndex; i <= _endIndex-1; i++) {
                Checkpoint memory cp0 = checkpoints[tokenId][i];
                Checkpoint memory cp1 = checkpoints[tokenId][i+1];
                (uint _rewardPerTokenStored0,) = getPriorRewardPerToken(token, cp0.timestamp);
                (uint _rewardPerTokenStored1,) = getPriorRewardPerToken(token, cp1.timestamp);
                reward += cp0.balanceOf * (_rewardPerTokenStored1 - _rewardPerTokenStored0) / PRECISION;
            }
        }

        Checkpoint memory cp = checkpoints[tokenId][_endIndex];
        (uint _rewardPerTokenStored,) = getPriorRewardPerToken(token, cp.timestamp);
        reward += cp.balanceOf * (rewardPerToken(token) - Math.max(_rewardPerTokenStored, userRewardPerTokenStored[token][tokenId])) / PRECISION;

        return reward;
    }

    // This is an external function, but internal notation is used since it can only be called "internally" from Gauges
    function _deposit(uint amount, uint tokenId) external {
        require(msg.sender == voter);
        _updateRewardForAllTokens();

        totalSupply += amount;
        balanceOf[tokenId] += amount;

        _writeCheckpoint(tokenId, balanceOf[tokenId]);
        _writeSupplyCheckpoint();

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

    function _withdraw(uint amount, uint tokenId) external {
        require(msg.sender == voter);
        _updateRewardForAllTokens();

        totalSupply -= amount;
        balanceOf[tokenId] -= amount;

        _writeCheckpoint(tokenId, balanceOf[tokenId]);
        _writeSupplyCheckpoint();

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

    function left(address token) external view returns (uint) {
        if (block.timestamp >= periodFinish[token]) return 0;
        uint _remaining = periodFinish[token] - block.timestamp;
        return _remaining * rewardRate[token];
    }

    // used to notify a gauge/bribe of a given reward, this can create griefing attacks by extending rewards
    function notifyRewardAmount(address token, uint amount) external lock {
        require(amount > 0);
        require(isReward[token]);

        if (rewardRate[token] == 0) _writeRewardPerTokenCheckpoint(token, 0, block.timestamp);
        (rewardPerTokenStored[token], lastUpdateTime[token]) = _updateRewardPerToken(token, type(uint).max, true);

        if (block.timestamp >= periodFinish[token]) {
            _safeTransferFrom(token, msg.sender, address(this), amount);
            rewardRate[token] = amount / DURATION;
        } else {
            uint _remaining = periodFinish[token] - block.timestamp;
            uint _left = _remaining * rewardRate[token];
            require(amount > _left);
            _safeTransferFrom(token, msg.sender, address(this), amount);
            rewardRate[token] = (amount + _left) / DURATION;
        }
        require(rewardRate[token] > 0);
        uint balance = IERC20(token).balanceOf(address(this));
        require(rewardRate[token] <= balance / DURATION, "Provided reward too high");
        periodFinish[token] = block.timestamp + DURATION;

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

    function swapOutRewardToken(uint i, address oldToken, address newToken) external {
        require(msg.sender == IVotingEscrow(_ve).team(), 'only team');
        require(rewards[i] == oldToken);
        isReward[oldToken] = false;
        isReward[newToken] = true;
        rewards[i] = newToken;
    }

    function _safeTransfer(address token, address to, uint256 value) internal {
        require(token.code.length > 0);
        (bool success, bytes memory data) =
        token.call(abi.encodeWithSelector(IERC20.transfer.selector, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))));
    }

    function _safeTransferFrom(address token, address from, address to, uint256 value) internal {
        require(token.code.length > 0);
        (bool success, bytes memory data) =
        token.call(abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))));
    }
}

File 4 of 10 : ExternalBribe.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.13;

import 'contracts/libraries/Math.sol';
import 'contracts/interfaces/IBribe.sol';
import 'contracts/interfaces/IERC20.sol';
import 'contracts/interfaces/IGauge.sol';
import 'contracts/interfaces/IVoter.sol';
import 'contracts/interfaces/IVotingEscrow.sol';

// Bribes pay out rewards for a given pool based on the votes that were received from the user (goes hand in hand with Voter.vote())
contract ExternalBribe is IBribe {
    address public immutable voter; // only voter can modify balances (since it only happens on vote())
    address public immutable _ve; // 天使のたまご

    uint internal constant DURATION = 7 days; // rewards are released over the voting period
    uint internal constant MAX_REWARD_TOKENS = 16;

    uint internal constant PRECISION = 10 ** 18;

    uint public totalSupply;
    mapping(uint => uint) public balanceOf;
    mapping(address => mapping(uint => uint)) public tokenRewardsPerEpoch;
    mapping(address => uint) public periodFinish;
    mapping(address => mapping(uint => uint)) public lastEarn;

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

    /// @notice A checkpoint for marking balance
    struct Checkpoint {
        uint timestamp;
        uint balanceOf;
    }

    /// @notice A checkpoint for marking supply
    struct SupplyCheckpoint {
        uint timestamp;
        uint supply;
    }

    /// @notice A record of balance checkpoints for each account, by index
    mapping (uint => mapping (uint => Checkpoint)) public checkpoints;
    /// @notice The number of checkpoints for each account
    mapping (uint => uint) public numCheckpoints;
    /// @notice A record of balance checkpoints for each token, by index
    mapping (uint => SupplyCheckpoint) public supplyCheckpoints;
    /// @notice The number of checkpoints
    uint public supplyNumCheckpoints;

    event Deposit(address indexed from, uint tokenId, uint amount);
    event Withdraw(address indexed from, uint tokenId, uint amount);
    event NotifyReward(address indexed from, address indexed reward, uint epoch, uint amount);
    event ClaimRewards(address indexed from, address indexed reward, uint amount);

    constructor(address _voter, address[] memory _allowedRewardTokens) {
        voter = _voter;
        _ve = IVoter(_voter)._ve();

        for (uint i; i < _allowedRewardTokens.length; i++) {
            if (_allowedRewardTokens[i] != address(0)) {
                isReward[_allowedRewardTokens[i]] = true;
                rewards.push(_allowedRewardTokens[i]);
            }
        }
    }

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

    function _bribeStart(uint timestamp) internal pure returns (uint) {
        return timestamp - (timestamp % (7 days));
    }

    function getEpochStart(uint timestamp) public pure returns (uint) {
        uint bribeStart = _bribeStart(timestamp);
        uint bribeEnd = bribeStart + DURATION;
        return timestamp < bribeEnd ? bribeStart : bribeStart + 7 days;
    }

    /**
    * @notice Determine the prior balance for an account as of a block number
    * @dev Block number must be a finalized block or else this function will revert to prevent misinformation.
    * @param tokenId The token of the NFT to check
    * @param timestamp The timestamp to get the balance at
    * @return The balance the account had as of the given block
    */
    function getPriorBalanceIndex(uint tokenId, uint timestamp) public view returns (uint) {
        uint nCheckpoints = numCheckpoints[tokenId];
        if (nCheckpoints == 0) {
            return 0;
        }
        // First check most recent balance
        if (checkpoints[tokenId][nCheckpoints - 1].timestamp <= timestamp) {
            return (nCheckpoints - 1);
        }
        // Next check implicit zero balance
        if (checkpoints[tokenId][0].timestamp > timestamp) {
            return 0;
        }

        uint lower = 0;
        uint upper = nCheckpoints - 1;
        while (upper > lower) {
            uint center = upper - (upper - lower) / 2; // ceil, avoiding overflow
            Checkpoint memory cp = checkpoints[tokenId][center];
            if (cp.timestamp == timestamp) {
                return center;
            } else if (cp.timestamp < timestamp) {
                lower = center;
            } else {
                upper = center - 1;
            }
        }
        return lower;
    }

    function getPriorSupplyIndex(uint timestamp) public view returns (uint) {
        uint nCheckpoints = supplyNumCheckpoints;
        if (nCheckpoints == 0) {
            return 0;
        }

        // First check most recent balance
        if (supplyCheckpoints[nCheckpoints - 1].timestamp <= timestamp) {
            return (nCheckpoints - 1);
        }

        // Next check implicit zero balance
        if (supplyCheckpoints[0].timestamp > timestamp) {
            return 0;
        }

        uint lower = 0;
        uint upper = nCheckpoints - 1;
        while (upper > lower) {
            uint center = upper - (upper - lower) / 2; // ceil, avoiding overflow
            SupplyCheckpoint memory cp = supplyCheckpoints[center];
            if (cp.timestamp == timestamp) {
                return center;
            } else if (cp.timestamp < timestamp) {
                lower = center;
            } else {
                upper = center - 1;
            }
        }
        return lower;
    }

    function _writeCheckpoint(uint tokenId, uint balance) internal {
        uint _timestamp = block.timestamp;
        uint _nCheckPoints = numCheckpoints[tokenId];
        if (_nCheckPoints > 0 && checkpoints[tokenId][_nCheckPoints - 1].timestamp == _timestamp) {
            checkpoints[tokenId][_nCheckPoints - 1].balanceOf = balance;
        } else {
            checkpoints[tokenId][_nCheckPoints] = Checkpoint(_timestamp, balance);
            numCheckpoints[tokenId] = _nCheckPoints + 1;
        }
    }

    function _writeSupplyCheckpoint() internal {
        uint _nCheckPoints = supplyNumCheckpoints;
        uint _timestamp = block.timestamp;

        if (_nCheckPoints > 0 && supplyCheckpoints[_nCheckPoints - 1].timestamp == _timestamp) {
            supplyCheckpoints[_nCheckPoints - 1].supply = totalSupply;
        } else {
            supplyCheckpoints[_nCheckPoints] = SupplyCheckpoint(_timestamp, totalSupply);
            supplyNumCheckpoints = _nCheckPoints + 1;
        }
    }

    function rewardsListLength() external view returns (uint) {
        return rewards.length;
    }

    // returns the last time the reward was modified or periodFinish if the reward has ended
    function lastTimeRewardApplicable(address token) public view returns (uint) {
        return Math.min(block.timestamp, periodFinish[token]);
    }

    // allows a user to claim rewards for a given token
    function getReward(uint tokenId, address[] memory tokens) external lock  {
        require(IVotingEscrow(_ve).isApprovedOrOwner(msg.sender, tokenId));
        for (uint i = 0; i < tokens.length; i++) {
            uint _reward = earned(tokens[i], tokenId);
            lastEarn[tokens[i]][tokenId] = block.timestamp;
            if (_reward > 0) _safeTransfer(tokens[i], msg.sender, _reward);

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

    // used by Voter to allow batched reward claims
    function getRewardForOwner(uint tokenId, address[] memory tokens) external lock  {
        require(msg.sender == voter);
        address _owner = IVotingEscrow(_ve).ownerOf(tokenId);
        for (uint i = 0; i < tokens.length; i++) {
            uint _reward = earned(tokens[i], tokenId);
            lastEarn[tokens[i]][tokenId] = block.timestamp;
            if (_reward > 0) _safeTransfer(tokens[i], _owner, _reward);

            emit ClaimRewards(_owner, tokens[i], _reward);
        }
    }

    function earned(address token, uint tokenId) public view returns (uint) {
        uint _startTimestamp = lastEarn[token][tokenId];
        if (numCheckpoints[tokenId] == 0) {
            return 0;
        }

        uint _startIndex = getPriorBalanceIndex(tokenId, _startTimestamp);
        uint _endIndex = numCheckpoints[tokenId]-1;

        uint reward = 0;
        // you only earn once per epoch (after it's over)
        Checkpoint memory prevRewards; // reuse struct to avoid stack too deep
        prevRewards.timestamp = _bribeStart(_startTimestamp);
        uint _prevSupply = 1;

        if (_endIndex > 0) {
            for (uint i = _startIndex; i <= _endIndex - 1; i++) {
                Checkpoint memory cp0 = checkpoints[tokenId][i];
                uint _nextEpochStart = _bribeStart(cp0.timestamp);
                // check that you've earned it
                // this won't happen until a week has passed
                if (_nextEpochStart > prevRewards.timestamp) {
                  reward += prevRewards.balanceOf;
                }

                prevRewards.timestamp = _nextEpochStart;
                _prevSupply = supplyCheckpoints[getPriorSupplyIndex(_nextEpochStart + DURATION)].supply;
                prevRewards.balanceOf = cp0.balanceOf * tokenRewardsPerEpoch[token][_nextEpochStart] / _prevSupply;
            }
        }

        Checkpoint memory cp = checkpoints[tokenId][_endIndex];
        uint _lastEpochStart = _bribeStart(cp.timestamp);
        uint _lastEpochEnd = _lastEpochStart + DURATION;

        if (block.timestamp > _lastEpochEnd) {
          reward += cp.balanceOf * tokenRewardsPerEpoch[token][_lastEpochStart] / supplyCheckpoints[getPriorSupplyIndex(_lastEpochEnd)].supply;
        }

        return reward;
    }

    // This is an external function, but internal notation is used since it can only be called "internally" from Gauges
    function _deposit(uint amount, uint tokenId) external {
        require(msg.sender == voter);

        totalSupply += amount;
        balanceOf[tokenId] += amount;

        _writeCheckpoint(tokenId, balanceOf[tokenId]);
        _writeSupplyCheckpoint();

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

    function _withdraw(uint amount, uint tokenId) external {
        require(msg.sender == voter);

        totalSupply -= amount;
        balanceOf[tokenId] -= amount;

        _writeCheckpoint(tokenId, balanceOf[tokenId]);
        _writeSupplyCheckpoint();

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

    function left(address token) external view returns (uint) {
        uint adjustedTstamp = getEpochStart(block.timestamp);
        return tokenRewardsPerEpoch[token][adjustedTstamp];
    }

    function notifyRewardAmount(address token, uint amount) external lock {
        require(amount > 0);
        if (!isReward[token]) {
          require(IVoter(voter).isWhitelisted(token), "bribe tokens must be whitelisted");
          require(rewards.length < MAX_REWARD_TOKENS, "too many rewards tokens");
        }
        // bribes kick in at the start of next bribe period
        uint adjustedTstamp = getEpochStart(block.timestamp);
        uint epochRewards = tokenRewardsPerEpoch[token][adjustedTstamp];

        _safeTransferFrom(token, msg.sender, address(this), amount);
        tokenRewardsPerEpoch[token][adjustedTstamp] = epochRewards + amount;

        periodFinish[token] = adjustedTstamp + DURATION;

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

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

    function swapOutRewardToken(uint i, address oldToken, address newToken) external {
        require(msg.sender == IVotingEscrow(_ve).team(), 'only team');
        require(rewards[i] == oldToken);
        isReward[oldToken] = false;
        isReward[newToken] = true;
        rewards[i] = newToken;
    }

    function _safeTransfer(address token, address to, uint256 value) internal {
        require(token.code.length > 0);
        (bool success, bytes memory data) =
        token.call(abi.encodeWithSelector(IERC20.transfer.selector, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))));
    }

    function _safeTransferFrom(address token, address from, address to, uint256 value) internal {
        require(token.code.length > 0);
        (bool success, bytes memory data) =
        token.call(abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))));
    }
}

File 5 of 10 : Math.sol
pragma solidity 0.8.13;

library Math {
    function max(uint a, uint b) internal pure returns (uint) {
        return a >= b ? a : b;
    }
    function min(uint a, uint b) internal pure returns (uint) {
        return a < b ? a : b;
    }
    function sqrt(uint y) internal pure returns (uint z) {
        if (y > 3) {
            z = y;
            uint x = y / 2 + 1;
            while (x < z) {
                z = x;
                x = (y / x + x) / 2;
            }
        } else if (y != 0) {
            z = 1;
        }
    }
    function cbrt(uint256 n) internal pure returns (uint256) { unchecked {
        uint256 x = 0;
        for (uint256 y = 1 << 255; y > 0; y >>= 3) {
            x <<= 1;
            uint256 z = 3 * x * (x + 1) + 1;
            if (n / y >= z) {
                n -= y * z;
                x += 1;
            }
        }
        return x;
    }}
}

File 6 of 10 : IBribe.sol
pragma solidity 0.8.13;

interface IBribe {
    function _deposit(uint amount, uint tokenId) external;
    function _withdraw(uint amount, uint tokenId) external;
    function getRewardForOwner(uint tokenId, address[] memory tokens) external;
    function notifyRewardAmount(address token, uint amount) external;
    function left(address token) external view returns (uint);
}

File 7 of 10 : IERC20.sol
pragma solidity 0.8.13;

interface IERC20 {
    function totalSupply() external view returns (uint256);
    function transfer(address recipient, uint amount) external returns (bool);
    function decimals() external view returns (uint8);
    function symbol() external view returns (string memory);
    function balanceOf(address) external view returns (uint);
    function transferFrom(address sender, address recipient, uint amount) external returns (bool);
    function allowance(address owner, address spender) external view returns (uint);
    function approve(address spender, uint value) external returns (bool);

    event Transfer(address indexed from, address indexed to, uint value);
    event Approval(address indexed owner, address indexed spender, uint value);
}

File 8 of 10 : IVoter.sol
pragma solidity 0.8.13;

interface IVoter {
    function _ve() external view returns (address);
    function governor() external view returns (address);
    function emergencyCouncil() external view returns (address);
    function attachTokenToGauge(uint _tokenId, address account) external;
    function detachTokenFromGauge(uint _tokenId, address account) external;
    function emitDeposit(uint _tokenId, address account, uint amount) external;
    function emitWithdraw(uint _tokenId, address account, uint amount) external;
    function isWhitelisted(address token) external view returns (bool);
    function notifyRewardAmount(uint amount) external;
    function distribute(address _gauge) external;
}

File 9 of 10 : IVotingEscrow.sol
pragma solidity 0.8.13;

interface IVotingEscrow {

    struct Point {
        int128 bias;
        int128 slope; // # -dweight / dt
        uint256 ts;
        uint256 blk; // block
    }

    function token() external view returns (address);
    function team() external returns (address);
    function epoch() external view returns (uint);
    function point_history(uint loc) external view returns (Point memory);
    function user_point_history(uint tokenId, uint loc) external view returns (Point memory);
    function user_point_epoch(uint tokenId) external view returns (uint);

    function ownerOf(uint) external view returns (address);
    function isApprovedOrOwner(address, uint) external view returns (bool);
    function transferFrom(address, address, uint) external;

    function voting(uint tokenId) external;
    function abstain(uint tokenId) external;
    function attach(uint tokenId) external;
    function detach(uint tokenId) external;

    function checkpoint() external;
    function deposit_for(uint tokenId, uint value) external;
    function create_lock_for(uint, uint, address) external returns (uint);

    function balanceOfNFT(uint) external view returns (uint);
    function totalSupply() external view returns (uint);
}

File 10 of 10 : IGauge.sol
pragma solidity 0.8.13;

interface IGauge {
    function notifyRewardAmount(address token, uint amount) external;
    function getReward(address account, address[] memory tokens) external;
    function claimFees() external returns (uint claimed0, uint claimed1);
    function left(address token) external view returns (uint);
    function isForPair() external view returns (bool);
}

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address[]","name":"allowedRewards","type":"address[]"}],"name":"createExternalBribe","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"allowedRewards","type":"address[]"}],"name":"createInternalBribe","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"last_external_bribe","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"last_internal_bribe","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

608060405234801561001057600080fd5b50614cca806100206000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c80632a26b9eb146100515780636485f0c414610080578063b0ad856f14610093578063eb57738c146100a6575b600080fd5b61006461005f3660046101bf565b6100b9565b6040516001600160a01b03909116815260200160405180910390f35b61006461008e3660046101bf565b610116565b600154610064906001600160a01b031681565b600054610064906001600160a01b031681565b600033826040516100c990610173565b6100d4929190610284565b604051809103906000f0801580156100f0573d6000803e3d6000fd5b50600080546001600160a01b0319166001600160a01b0392909216918217905592915050565b6000338260405161012690610180565b610131929190610284565b604051809103906000f08015801561014d573d6000803e3d6000fd5b50600180546001600160a01b0319166001600160a01b0392909216918217905592915050565b612b31806102e183390190565b611e8380612e1283390190565b634e487b7160e01b600052604160045260246000fd5b80356001600160a01b03811681146101ba57600080fd5b919050565b600060208083850312156101d257600080fd5b823567ffffffffffffffff808211156101ea57600080fd5b818501915085601f8301126101fe57600080fd5b8135818111156102105761021061018d565b8060051b604051601f19603f830116810181811085821117156102355761023561018d565b60405291825284820192508381018501918883111561025357600080fd5b938501935b8285101561027857610269856101a3565b84529385019392850192610258565b98975050505050505050565b6001600160a01b038381168252604060208084018290528451918401829052600092858201929091906060860190855b818110156102d25785518516835294830194918301916001016102b4565b50909897505050505050505056fe60c060405260016010553480156200001657600080fd5b5060405162002b3138038062002b318339810160408190526200003991620001f8565b6001600160a01b038216608081905260408051638dd598fb60e01b81529051638dd598fb916004808201926020929091908290030181865afa15801562000084573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000aa9190620002e1565b6001600160a01b031660a05260005b8151811015620001bc5760006001600160a01b0316828281518110620000e357620000e362000306565b60200260200101516001600160a01b031614620001a75760016007600084848151811062000115576200011562000306565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff02191690831515021790555060068282815181106200016b576200016b62000306565b60209081029190910181015182546001810184556000938452919092200180546001600160a01b0319166001600160a01b039092169190911790555b80620001b3816200031c565b915050620000b9565b50505062000344565b80516001600160a01b0381168114620001dd57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b600080604083850312156200020c57600080fd5b6200021783620001c5565b602084810151919350906001600160401b03808211156200023757600080fd5b818601915086601f8301126200024c57600080fd5b815181811115620002615762000261620001e2565b8060051b604051601f19603f83011681018181108582111715620002895762000289620001e2565b604052918252848201925083810185019189831115620002a857600080fd5b938501935b82851015620002d157620002c185620001c5565b84529385019392850192620002ad565b8096505050505050509250929050565b600060208284031215620002f457600080fd5b620002ff82620001c5565b9392505050565b634e487b7160e01b600052603260045260246000fd5b6000600182016200033d57634e487b7160e01b600052601160045260246000fd5b5060010190565b60805160a05161279d620003946000396000818161042301528181610a0201528181610e82015261164301526000818161031101528181610c0d01528181610e3f015261154d015261279d6000f3fe608060405234801561001057600080fd5b506004361061021c5760003560e01c80639cc7f70811610125578063e6886396116100ad578063f301af421161007c578063f301af4214610595578063f3207723146105a8578063f5f8d365146105bb578063f7412baf146105ce578063fd314098146105f557600080fd5b8063e688639614610546578063e8111a121461054e578063f122977714610557578063f25e55a51461056a57600080fd5b8063a7852afa116100f4578063a7852afa146104d1578063aa479652146104e4578063aaf5eb6814610504578063b66503cf14610513578063da09d19d1461052657600080fd5b80639cc7f7081461046b5780639ce43f901461048b5780639e2bf22c146104ab578063a28d4c9c146104be57600080fd5b80634d5ce038116101a857806368fcee1a1161017757806368fcee1a146103f857806376f4be361461040b5780638dd598fb1461041e5780639418f9391461044557806399bcc0521461045857600080fd5b80634d5ce0381461037d57806350589793146103b05780635a45d052146103d0578063638634ee146103e557600080fd5b80632ce9aead116101ef5780632ce9aead146102ae5780633b881999146102ce5780633e491d47146102f957806346c96aac1461030c57806349dcc2041461034b57600080fd5b806301316ddf1461022157806318160ddd1461026d5780631be0528914610284578063221ca18c1461028e575b600080fd5b61025361022f366004612472565b600e6020908152600092835260408084209091529082529020805460019091015482565b604080519283526020830191909152015b60405180910390f35b61027660085481565b604051908152602001610264565b61027662093a8081565b61027661029c36600461249e565b60006020819052908152604090205481565b6102766102bc36600461249e565b60026020526000908152604090205481565b6102766102dc366004612472565b600560209081526000928352604080842090915290825290205481565b610276610307366004612472565b610608565b6103337f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610264565b6102536103593660046124bb565b600a6020908152600092835260408084209091529082529020805460019091015482565b6103a061038b36600461249e565b60076020526000908152604090205460ff1681565b6040519015158152602001610264565b6102766103be3660046124dd565b600b6020526000908152604090205481565b6103e36103de366004612472565b610864565b005b6102766103f336600461249e565b61089c565b6103e3610406366004612472565b6108c0565b6102766104193660046124dd565b6108cc565b6103337f000000000000000000000000000000000000000000000000000000000000000081565b6103e36104533660046124f6565b610a00565b61027661046636600461249e565b610b91565b6102766104793660046124dd565b60096020526000908152604090205481565b61027661049936600461249e565b60036020526000908152604090205481565b6103e36104b93660046124bb565b610c02565b6102766104cc3660046124bb565b610cdb565b6103e36104df36600461254e565b610e20565b6102766104f236600461249e565b600f6020526000908152604090205481565b610276670de0b6b3a764000081565b6103e3610521366004612472565b611165565b61027661053436600461249e565b60016020526000908152604090205481565b600654610276565b610276600d5481565b61027661056536600461249e565b61145b565b610276610578366004612472565b600460209081526000928352604080842090915290825290205481565b6103336105a33660046124dd565b611518565b6103e36105b63660046124bb565b611542565b6103e36105c936600461254e565b611613565b6102536105dc3660046124dd565b600c602052600090815260409020805460019091015482565b610253610603366004612472565b61191a565b6001600160a01b0382166000818152600460209081526040808320858452825280832054938352600e82528083208380529091528120549091829161064d9190611b3b565b6000848152600b60205260408120549192500361066e57600091505061085e565b600061067a8483610cdb565b6000858152600b60205260408120549192509061069990600190612635565b9050600081156107a257825b6106b0600184612635565b81116107a0576000878152600a60208181526040808420858552808352818520825180840190935280548352600190810154838501528c865293909252929182906106fc90869061264c565b8152602001908152602001600020604051806040016040529081600082015481526020016001820154815250509050600061073b8b846000015161191a565b509050600061074e8c846000015161191a565b509050670de0b6b3a76400006107648383612635565b85602001516107739190612664565b61077d9190612683565b610787908761264c565b9550505050508080610798906126a5565b9150506106a5565b505b6000868152600a602090815260408083208584528252808320815180830190925280548083526001909101549282019290925291906107e2908a9061191a565b506001600160a01b038a1660009081526005602090815260408083208c8452909152902054909150670de0b6b3a76400009061081f908390611b3b565b6108288b61145b565b6108329190612635565b83602001516108419190612664565b61084b9190612683565b610855908461264c565b96505050505050505b92915050565b61086e8282611b52565b6001600160a01b03909316600090815260036020908152604080832060029092529091209390935590915550565b6001600160a01b03811660009081526001602052604081205461085e904290611cb5565b61086e82826000611cc4565b600d546000908082036108e25750600092915050565b82600c60006108f2600185612635565b8152602001908152602001600020600001541161091b57610914600182612635565b9392505050565b60008052600c6020527f13649b2456f1b42fef0f0040b3aaeabcd21a76a0f3f5defd4f583839455116e8548310156109565750600092915050565b600080610964600184612635565b90505b818111156109f8576000600261097d8484612635565b6109879190612683565b6109919083612635565b6000818152600c60209081526040918290208251808401909352805480845260019091015491830191909152919250908790036109d2575095945050505050565b80518711156109e3578193506109f1565b6109ee600183612635565b92505b5050610967565b509392505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166385f2aef26040518163ffffffff1660e01b81526004016020604051808303816000875af1158015610a60573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a8491906126be565b6001600160a01b0316336001600160a01b031614610ad55760405162461bcd60e51b81526020600482015260096024820152686f6e6c79207465616d60b81b60448201526064015b60405180910390fd5b816001600160a01b031660068481548110610af257610af26126db565b6000918252602090912001546001600160a01b031614610b1157600080fd5b6001600160a01b03808316600090815260076020526040808220805460ff1990811690915592841682529020805490911660011790556006805482919085908110610b5e57610b5e6126db565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550505050565b6001600160a01b0381166000908152600160205260408120544210610bb857506000919050565b6001600160a01b038216600090815260016020526040812054610bdc904290612635565b6001600160a01b0384166000908152602081905260409020549091506109149082612664565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610c3757600080fd5b610c3f611eb4565b8160086000828254610c519190612635565b909155505060008181526009602052604081208054849290610c74908490612635565b9091555050600081815260096020526040902054610c93908290611f3c565b610c9b612015565b604080518281526020810184905233917ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b56891015b60405180910390a25050565b6000828152600b6020526040812054808203610cfb57600091505061085e565b6000848152600a602052604081208491610d16600185612635565b81526020019081526020016000206000015411610d4057610d38600182612635565b91505061085e565b6000848152600a60209081526040808320838052909152902054831015610d6b57600091505061085e565b600080610d79600184612635565b90505b81811115610e175760006002610d928484612635565b610d9c9190612683565b610da69083612635565b6000888152600a60209081526040808320848452825291829020825180840190935280548084526001909101549183019190915291925090879003610df15750935061085e92505050565b8051871115610e0257819350610e10565b610e0d600183612635565b92505b5050610d7c565b50949350505050565b601054600114610e2f57600080fd5b6002601055336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610e6957600080fd5b6040516331a9108f60e11b8152600481018390526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636352211e90602401602060405180830381865afa158015610ed1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ef591906126be565b905060005b825181101561115a57610f2a838281518110610f1857610f186126db565b60200260200101516000196001611cc4565b60036000868581518110610f4057610f406126db565b60200260200101516001600160a01b03166001600160a01b03168152602001908152602001600020600060026000888781518110610f8057610f806126db565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060008491905055839190505550506000610fdb848381518110610fcd57610fcd6126db565b602002602001015186610608565b90504260046000868581518110610ff457610ff46126db565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060008781526020019081526020016000208190555060036000858481518110611047576110476126db565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000205460056000868581518110611086576110866126db565b6020908102919091018101516001600160a01b03168252818101929092526040908101600090812089825290925290205580156110e1576110e18483815181106110d2576110d26126db565b602002602001015184836120b9565b8382815181106110f3576110f36126db565b60200260200101516001600160a01b0316836001600160a01b03167f9aa05b3d70a9e3e2f004f039648839560576334fb45c81f91b6db03ad9e2efc98360405161113f91815260200190565b60405180910390a35080611152816126a5565b915050610efa565b505060016010555050565b60105460011461117457600080fd5b60026010558061118357600080fd5b6001600160a01b03821660009081526007602052604090205460ff166111a857600080fd5b6001600160a01b03821660009081526020819052604081205490036111d3576111d3826000426121a8565b6111e1826000196001611cc4565b6001600160a01b038416600090815260036020908152604080832060028352818420949094559390925560019091522054421061124f5761122482333084612297565b61123162093a8082612683565b6001600160a01b0383166000908152602081905260409020556112e8565b6001600160a01b038216600090815260016020526040812054611273904290612635565b6001600160a01b0384166000908152602081905260408120549192509061129a9083612664565b90508083116112a857600080fd5b6112b484333086612297565b62093a806112c2828561264c565b6112cc9190612683565b6001600160a01b03851660009081526020819052604090205550505b6001600160a01b03821660009081526020819052604090205461130a57600080fd5b6040516370a0823160e01b81523060048201526000906001600160a01b038416906370a0823190602401602060405180830381865afa158015611351573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061137591906126f1565b905061138462093a8082612683565b6001600160a01b03841660009081526020819052604090205411156113eb5760405162461bcd60e51b815260206004820152601860248201527f50726f76696465642072657761726420746f6f206869676800000000000000006044820152606401610acc565b6113f862093a804261264c565b6001600160a01b0384166000818152600160205260409081902092909255905133907ff70d5c697de7ea828df48e5c4573cb2194c659f1901f70110c52b066dcf50826906114499086815260200190565b60405180910390a35050600160105550565b600060085460000361148357506001600160a01b031660009081526003602052604090205490565b6008546001600160a01b0383166000908152602081815260408083205460028352818420546001909352922054670de0b6b3a764000092916114c491611cb5565b6114cd8661089c565b6114d79190612635565b6114e19190612664565b6114eb9190612664565b6114f59190612683565b6001600160a01b03831660009081526003602052604090205461085e919061264c565b6006818154811061152857600080fd5b6000918252602090912001546001600160a01b0316905081565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461157757600080fd5b61157f611eb4565b8160086000828254611591919061264c565b9091555050600081815260096020526040812080548492906115b490849061264c565b90915550506000818152600960205260409020546115d3908290611f3c565b6115db612015565b604080518281526020810184905233917f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a159101610ccf565b60105460011461162257600080fd5b600260105560405163430c208160e01b8152336004820152602481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063430c208190604401602060405180830381865afa158015611692573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116b6919061270a565b6116bf57600080fd5b60005b8151811015611910576116e0828281518110610f1857610f186126db565b600360008585815181106116f6576116f66126db565b60200260200101516001600160a01b03166001600160a01b03168152602001908152602001600020600060026000878781518110611736576117366126db565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060008491905055839190505550506000611791838381518110611783576117836126db565b602002602001015185610608565b905042600460008585815181106117aa576117aa6126db565b60200260200101516001600160a01b03166001600160a01b03168152602001908152602001600020600086815260200190815260200160002081905550600360008484815181106117fd576117fd6126db565b60200260200101516001600160a01b03166001600160a01b03168152602001908152602001600020546005600085858151811061183c5761183c6126db565b6020908102919091018101516001600160a01b031682528181019290925260409081016000908120888252909252902055801561189757611897838381518110611888576118886126db565b602002602001015133836120b9565b8282815181106118a9576118a96126db565b60200260200101516001600160a01b0316336001600160a01b03167f9aa05b3d70a9e3e2f004f039648839560576334fb45c81f91b6db03ad9e2efc9836040516118f591815260200190565b60405180910390a35080611908816126a5565b9150506116c2565b5050600160105550565b6001600160a01b0382166000908152600f60205260408120548190808203611949576000809250925050611b34565b6001600160a01b0385166000908152600e60205260408120859161196e600185612635565b81526020019081526020016000206000015411611a0b576001600160a01b0385166000908152600e60205260408120906119a9600184612635565b815260200190815260200160002060010154600e6000876001600160a01b03166001600160a01b0316815260200190815260200160002060006001846119ef9190612635565b8152602001908152602001600020600001549250925050611b34565b6001600160a01b0385166000908152600e60209081526040808320838052909152902054841015611a43576000809250925050611b34565b600080611a51600184612635565b90505b81811115611b035760006002611a6a8484612635565b611a749190612683565b611a7e9083612635565b6001600160a01b0389166000908152600e60209081526040808320848452825291829020825180840190935280548084526001909101549183019190915291925090889003611add57602081015190519096509450611b349350505050565b8051881115611aee57819350611afc565b611af9600183612635565b92505b5050611a54565b506001600160a01b0386166000908152600e6020908152604080832093835292905220600181015490549093509150505b9250929050565b600081831015611b4b5781610914565b5090919050565b6001600160a01b0382166000908152600260209081526040808320546003909252822054600d54839291908303611b8c5792509050611b34565b6001600160a01b0386166000908152602081905260408120549003611bb7579250429150611b349050565b6000611bc2836108cc565b90506000611bde6001600d54611bd89190612635565b88611cb5565b9050815b81811015611ca6576000818152600c60209081526040918290208251808401909352805483526001015490820181905215611c93576000600c81611c2785600161264c565b8152602001908152602001600020604051806040016040529081600082015481526020016001820154815250509050600080611c728d8460000151866000015187602001518d61238f565b9092509050611c81828961264c565b9750611c8e8d89836121a8565b975050505b5080611c9e816126a5565b915050611be2565b50919792965091945050505050565b6000818310611b4b5781610914565b6001600160a01b0383166000908152600260209081526040808320546003909252822054600d54839291908303611cfe5792509050611eac565b6001600160a01b0387166000908152602081905260408120549003611d29579250429150611eac9050565b6000611d34836108cc565b90506000611d506001600d54611d4a9190612635565b89611cb5565b90508015611e2957815b611d65600183612635565b8111611e27576000818152600c60209081526040918290208251808401909352805483526001015490820181905215611e14576000600c81611da885600161264c565b8152602001908152602001600020604051806040016040529081600082015481526020016001820154815250509050600080611df38e8460000151866000015187602001518d61238f565b9092509050611e02828961264c565b9750611e0f8e89836121a8565b975050505b5080611e1f816126a5565b915050611d5a565b505b8615611ea3576000818152600c60209081526040918290208251808401909352805483526001015490820181905215611ea1576000611e828b611e6b8d61089c565b8451611e77908a611b3b565b85602001518a61238f565b509050611e8f818661264c565b9450611e9c8b86426121a8565b429550505b505b50909350909150505b935093915050565b60065460005b81811015611f3857600060068281548110611ed757611ed76126db565b6000918252602090912001546001600160a01b03169050611efc816000196001611cc4565b6001600160a01b039092166000908152600360209081526040808320600290925290912092909255905580611f30816126a5565b915050611eba565b5050565b6000828152600b602052604090205442908015801590611f8657506000848152600a602052604081208391611f72600185612635565b815260200190815260200160002060000154145b15611fbf576000848152600a602052604081208491611fa6600185612635565b815260208101919091526040016000206001015561200f565b60408051808201825283815260208082018681526000888152600a8352848120868252909252929020905181559051600191820155611fff90829061264c565b6000858152600b60205260409020555b50505050565b600d54428115801590612047575080600c6000612033600186612635565b815260200190815260200160002060000154145b1561207657600854600c600061205e600186612635565b81526020810191909152604001600020600101555050565b60408051808201825282815260085460208083019182526000868152600c909152929092209051815590516001918201556120b290839061264c565b600d555050565b6000836001600160a01b03163b116120d057600080fd5b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b179052915160009283929087169161212c919061272c565b6000604051808303816000865af19150503d8060008114612169576040519150601f19603f3d011682016040523d82523d6000602084013e61216e565b606091505b5091509150818015612198575080511580612198575080806020019051810190612198919061270a565b6121a157600080fd5b5050505050565b6001600160a01b0383166000908152600f6020526040902054801580159061220457506001600160a01b0384166000908152600e6020526040812083916121f0600185612635565b815260200190815260200160002060000154145b1561222e576001600160a01b0384166000908152600e602052604081208491611fa6600185612635565b60408051808201825283815260208082018681526001600160a01b0388166000908152600e835284812086825290925292902090518155905160019182015561227890829061264c565b6001600160a01b0385166000908152600f602052604090205550505050565b6000846001600160a01b03163b116122ae57600080fd5b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b1790529151600092839290881691612312919061272c565b6000604051808303816000865af19150503d806000811461234f576040519150601f19603f3d011682016040523d82523d6000602084013e612354565b606091505b509150915081801561237e57508051158061237e57508080602001905181019061237e919061270a565b61238757600080fd5b505050505050565b600080600061239e8785611b3b565b6001600160a01b0389166000908152602081905260409020549091508590670de0b6b3a7640000906123f16123d38a89611b3b565b6001600160a01b038d16600090815260016020526040902054611cb5565b6001600160a01b038c16600090815260016020526040902054612415908690611cb5565b61241f9190612635565b6124299190612664565b6124339190612664565b61243d9190612683565b9890975095505050505050565b6001600160a01b038116811461245f57600080fd5b50565b803561246d8161244a565b919050565b6000806040838503121561248557600080fd5b82356124908161244a565b946020939093013593505050565b6000602082840312156124b057600080fd5b81356109148161244a565b600080604083850312156124ce57600080fd5b50508035926020909101359150565b6000602082840312156124ef57600080fd5b5035919050565b60008060006060848603121561250b57600080fd5b83359250602084013561251d8161244a565b9150604084013561252d8161244a565b809150509250925092565b634e487b7160e01b600052604160045260246000fd5b6000806040838503121561256157600080fd5b8235915060208084013567ffffffffffffffff8082111561258157600080fd5b818601915086601f83011261259557600080fd5b8135818111156125a7576125a7612538565b8060051b604051601f19603f830116810181811085821117156125cc576125cc612538565b6040529182528482019250838101850191898311156125ea57600080fd5b938501935b8285101561260f5761260085612462565b845293850193928501926125ef565b8096505050505050509250929050565b634e487b7160e01b600052601160045260246000fd5b6000828210156126475761264761261f565b500390565b6000821982111561265f5761265f61261f565b500190565b600081600019048311821515161561267e5761267e61261f565b500290565b6000826126a057634e487b7160e01b600052601260045260246000fd5b500490565b6000600182016126b7576126b761261f565b5060010190565b6000602082840312156126d057600080fd5b81516109148161244a565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561270357600080fd5b5051919050565b60006020828403121561271c57600080fd5b8151801515811461091457600080fd5b6000825160005b8181101561274d5760208186018101518583015201612733565b8181111561275c576000828501525b50919091019291505056fea26469706673582212207b2ae32cb0cc7f1784866eb8794bff2ef146b197b6937eb7799f41eb9c772ef564736f6c634300080d003360c06040526001600b553480156200001657600080fd5b5060405162001e8338038062001e838339810160408190526200003991620001f8565b6001600160a01b038216608081905260408051638dd598fb60e01b81529051638dd598fb916004808201926020929091908290030181865afa15801562000084573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000aa9190620002e1565b6001600160a01b031660a05260005b8151811015620001bc5760006001600160a01b0316828281518110620000e357620000e362000306565b60200260200101516001600160a01b031614620001a75760016006600084848151811062000115576200011562000306565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff02191690831515021790555060058282815181106200016b576200016b62000306565b60209081029190910181015182546001810184556000938452919092200180546001600160a01b0319166001600160a01b039092169190911790555b80620001b3816200031c565b915050620000b9565b50505062000344565b80516001600160a01b0381168114620001dd57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b600080604083850312156200020c57600080fd5b6200021783620001c5565b602084810151919350906001600160401b03808211156200023757600080fd5b818601915086601f8301126200024c57600080fd5b815181811115620002615762000261620001e2565b8060051b604051601f19603f83011681018181108582111715620002895762000289620001e2565b604052918252848201925083810185019189831115620002a857600080fd5b938501935b82851015620002d157620002c185620001c5565b84529385019392850192620002ad565b8096505050505050509250929050565b600060208284031215620002f457600080fd5b620002ff82620001c5565b9392505050565b634e487b7160e01b600052603260045260246000fd5b6000600182016200033d57634e487b7160e01b600052601160045260246000fd5b5060010190565b60805160a051611ae86200039b600039600081816102d90152818161089b01528181610cda015261125c0152600081816101da01528181610a6e01528181610c9701528181610ed5015261116f0152611ae86000f3fe608060405234801561001057600080fd5b506004361061018e5760003560e01c80639cc7f708116100de578063e688639611610097578063f301af4211610071578063f301af4214610416578063f320772314610429578063f5f8d3651461043c578063f7412baf1461044f57600080fd5b8063e6886396146103da578063e8111a12146103e2578063f25e55a5146103eb57600080fd5b80639cc7f7081461034e5780639e2bf22c1461036e578063a28d4c9c14610381578063a7852afa14610394578063b66503cf146103a7578063da09d19d146103ba57600080fd5b8063505897931161014b5780638dd598fb116101255780638dd598fb146102d457806392777b29146102fb5780639418f9391461032657806399bcc0521461033b57600080fd5b8063505897931461028e578063638634ee146102ae57806376f4be36146102c157600080fd5b80630175e23b1461019357806318160ddd146101b95780633e491d47146101c257806346c96aac146101d557806349dcc204146102145780634d5ce0381461025b575b600080fd5b6101a66101a1366004611792565b610476565b6040519081526020015b60405180910390f35b6101a660005481565b6101a66101d03660046117d3565b6104b8565b6101fc7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016101b0565b6102466102223660046117ff565b60076020908152600092835260408084209091529082529020805460019091015482565b604080519283526020830191909152016101b0565b61027e610269366004611821565b60066020526000908152604090205460ff1681565b60405190151581526020016101b0565b6101a661029c366004611792565b60086020526000908152604090205481565b6101a66102bc366004611821565b610741565b6101a66102cf366004611792565b610765565b6101fc7f000000000000000000000000000000000000000000000000000000000000000081565b6101a66103093660046117d3565b600260209081526000928352604080842090915290825290205481565b61033961033436600461183e565b610899565b005b6101a6610349366004611821565b610a2a565b6101a661035c366004611792565b60016020526000908152604090205481565b61033961037c3660046117ff565b610a63565b6101a661038f3660046117ff565b610b33565b6103396103a2366004611896565b610c78565b6103396103b53660046117d3565b610e78565b6101a66103c8366004611821565b60036020526000908152604090205481565b6005546101a6565b6101a6600a5481565b6101a66103f93660046117d3565b600460209081526000928352604080842090915290825290205481565b6101fc610424366004611792565b61113a565b6103396104373660046117ff565b611164565b61033961044a366004611896565b61122c565b61024661045d366004611792565b6009602052600090815260409020805460019091015482565b60008061048283611400565b9050600061049362093a808361197d565b90508084106104ae576104a98262093a8061197d565b6104b0565b815b949350505050565b6001600160a01b0382166000908152600460209081526040808320848452825280832054600890925282205482036104f457600091505061073b565b60006105008483610b33565b6000858152600860205260408120549192509061051f90600190611995565b90506000610540604051806040016040528060008152602001600081525090565b61054985611400565b81526001831561065a57845b610560600186611995565b81116106585760008981526007602090815260408083208484528252808320815180830190925280548083526001909101549282019290925291906105a490611400565b85519091508111156105c25760208501516105bf908761197d565b95505b808552600960006105d96102cf62093a808561197d565b815260200190815260200160002060010154935083600260008e6001600160a01b03166001600160a01b03168152602001908152602001600020600083815260200190815260200160002054836020015161063491906119ac565b61063e91906119e1565b602086015250819050610650816119f5565b915050610555565b505b600088815260076020908152604080832087845282528083208151808301909252805480835260019091015492820192909252919061069890611400565b905060006106a962093a808361197d565b90508042111561072f57600960006106c083610765565b815260200190815260200160002060010154600260008e6001600160a01b03166001600160a01b03168152602001908152602001600020600084815260200190815260200160002054846020015161071891906119ac565b61072291906119e1565b61072c908761197d565b95505b50939750505050505050505b92915050565b6001600160a01b03811660009081526003602052604081205461073b904290611419565b600a5460009080820361077b5750600092915050565b826009600061078b600185611995565b815260200190815260200160002060000154116107b4576107ad600182611995565b9392505050565b6000805260096020527fec8156718a8372b1db44bb411437d0870f3e3790d4a08526d024ce1b0b668f6b548310156107ef5750600092915050565b6000806107fd600184611995565b90505b8181111561089157600060026108168484611995565b61082091906119e1565b61082a9083611995565b60008181526009602090815260409182902082518084019093528054808452600190910154918301919091529192509087900361086b575095945050505050565b805187111561087c5781935061088a565b610887600183611995565b92505b5050610800565b509392505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166385f2aef26040518163ffffffff1660e01b81526004016020604051808303816000875af11580156108f9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061091d9190611a0e565b6001600160a01b0316336001600160a01b03161461096e5760405162461bcd60e51b81526020600482015260096024820152686f6e6c79207465616d60b81b60448201526064015b60405180910390fd5b816001600160a01b03166005848154811061098b5761098b611a2b565b6000918252602090912001546001600160a01b0316146109aa57600080fd5b6001600160a01b03808316600090815260066020526040808220805460ff19908116909155928416825290208054909116600117905560058054829190859081106109f7576109f7611a2b565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550505050565b600080610a3642610476565b6001600160a01b039093166000908152600260209081526040808320958352949052929092205492915050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610a9857600080fd5b81600080828254610aa99190611995565b909155505060008181526001602052604081208054849290610acc908490611995565b9091555050600081815260016020526040902054610aeb90829061142f565b610af3611508565b604080518281526020810184905233917ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b56891015b60405180910390a25050565b600082815260086020526040812054808203610b5357600091505061073b565b60008481526007602052604081208491610b6e600185611995565b81526020019081526020016000206000015411610b9857610b90600182611995565b91505061073b565b6000848152600760209081526040808320838052909152902054831015610bc357600091505061073b565b600080610bd1600184611995565b90505b81811115610c6f5760006002610bea8484611995565b610bf491906119e1565b610bfe9083611995565b6000888152600760209081526040808320848452825291829020825180840190935280548084526001909101549183019190915291925090879003610c495750935061073b92505050565b8051871115610c5a57819350610c68565b610c65600183611995565b92505b5050610bd4565b50949350505050565b600b54600114610c8757600080fd5b6002600b55336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610cc157600080fd5b6040516331a9108f60e11b8152600481018390526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636352211e90602401602060405180830381865afa158015610d29573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d4d9190611a0e565b905060005b8251811015610e6d576000610d80848381518110610d7257610d72611a2b565b6020026020010151866104b8565b90504260046000868581518110610d9957610d99611a2b565b6020908102919091018101516001600160a01b0316825281810192909252604090810160009081208982529092529020558015610df457610df4848381518110610de557610de5611a2b565b602002602001015184836115ab565b838281518110610e0657610e06611a2b565b60200260200101516001600160a01b0316836001600160a01b03167f9aa05b3d70a9e3e2f004f039648839560576334fb45c81f91b6db03ad9e2efc983604051610e5291815260200190565b60405180910390a35080610e65816119f5565b915050610d52565b50506001600b555050565b600b54600114610e8757600080fd5b6002600b5580610e9657600080fd5b6001600160a01b03821660009081526006602052604090205460ff16610fde57604051633af32abf60e01b81526001600160a01b0383811660048301527f00000000000000000000000000000000000000000000000000000000000000001690633af32abf90602401602060405180830381865afa158015610f1c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f409190611a41565b610f8c5760405162461bcd60e51b815260206004820181905260248201527f627269626520746f6b656e73206d7573742062652077686974656c69737465646044820152606401610965565b600554601011610fde5760405162461bcd60e51b815260206004820152601760248201527f746f6f206d616e79207265776172647320746f6b656e730000000000000000006044820152606401610965565b6000610fe942610476565b6001600160a01b038416600090815260026020908152604080832084845290915290205490915061101c8433308661169a565b611026838261197d565b6001600160a01b038516600090815260026020908152604080832086845290915290205561105762093a808361197d565b6001600160a01b03851660009081526003602090815260408083209390935560069052205460ff166110e9576001600160a01b0384166000818152600660205260408120805460ff191660019081179091556005805491820181559091527f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db00180546001600160a01b03191690911790555b60408051838152602081018590526001600160a01b0386169133917f52977ea98a2220a03ee9ba5cb003ada08d394ea10155483c95dc2dc77a7eb24b910160405180910390a350506001600b555050565b6005818154811061114a57600080fd5b6000918252602090912001546001600160a01b0316905081565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461119957600080fd5b816000808282546111aa919061197d565b9091555050600081815260016020526040812080548492906111cd90849061197d565b90915550506000818152600160205260409020546111ec90829061142f565b6111f4611508565b604080518281526020810184905233917f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a159101610b27565b600b5460011461123b57600080fd5b6002600b5560405163430c208160e01b8152336004820152602481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063430c208190604401602060405180830381865afa1580156112ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112cf9190611a41565b6112d857600080fd5b60005b81518110156113f65760006113098383815181106112fb576112fb611a2b565b6020026020010151856104b8565b9050426004600085858151811061132257611322611a2b565b6020908102919091018101516001600160a01b031682528181019290925260409081016000908120888252909252902055801561137d5761137d83838151811061136e5761136e611a2b565b602002602001015133836115ab565b82828151811061138f5761138f611a2b565b60200260200101516001600160a01b0316336001600160a01b03167f9aa05b3d70a9e3e2f004f039648839560576334fb45c81f91b6db03ad9e2efc9836040516113db91815260200190565b60405180910390a350806113ee816119f5565b9150506112db565b50506001600b5550565b600061140f62093a8083611a63565b61073b9083611995565b600081831061142857816107ad565b5090919050565b60008281526008602052604090205442908015801590611479575060008481526007602052604081208391611465600185611995565b815260200190815260200160002060000154145b156114b25760008481526007602052604081208491611499600185611995565b8152602081019190915260400160002060010155611502565b60408051808201825283815260208082018681526000888152600783528481208682529092529290209051815590516001918201556114f290829061197d565b6000858152600860205260409020555b50505050565b600a5442811580159061153a57508060096000611526600186611995565b815260200190815260200160002060000154145b1561156b57600054600960006001856115539190611995565b81526020810191909152604001600020600101555050565b604080518082018252828152600080546020808401918252868352600990529290209051815590516001918201556115a490839061197d565b600a555050565b6000836001600160a01b03163b116115c257600080fd5b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b179052915160009283929087169161161e9190611a77565b6000604051808303816000865af19150503d806000811461165b576040519150601f19603f3d011682016040523d82523d6000602084013e611660565b606091505b509150915081801561168a57508051158061168a57508080602001905181019061168a9190611a41565b61169357600080fd5b5050505050565b6000846001600160a01b03163b116116b157600080fd5b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b17905291516000928392908816916117159190611a77565b6000604051808303816000865af19150503d8060008114611752576040519150601f19603f3d011682016040523d82523d6000602084013e611757565b606091505b50915091508180156117815750805115806117815750808060200190518101906117819190611a41565b61178a57600080fd5b505050505050565b6000602082840312156117a457600080fd5b5035919050565b6001600160a01b03811681146117c057600080fd5b50565b80356117ce816117ab565b919050565b600080604083850312156117e657600080fd5b82356117f1816117ab565b946020939093013593505050565b6000806040838503121561181257600080fd5b50508035926020909101359150565b60006020828403121561183357600080fd5b81356107ad816117ab565b60008060006060848603121561185357600080fd5b833592506020840135611865816117ab565b91506040840135611875816117ab565b809150509250925092565b634e487b7160e01b600052604160045260246000fd5b600080604083850312156118a957600080fd5b8235915060208084013567ffffffffffffffff808211156118c957600080fd5b818601915086601f8301126118dd57600080fd5b8135818111156118ef576118ef611880565b8060051b604051601f19603f8301168101818110858211171561191457611914611880565b60405291825284820192508381018501918983111561193257600080fd5b938501935b8285101561195757611948856117c3565b84529385019392850192611937565b8096505050505050509250929050565b634e487b7160e01b600052601160045260246000fd5b6000821982111561199057611990611967565b500190565b6000828210156119a7576119a7611967565b500390565b60008160001904831182151516156119c6576119c6611967565b500290565b634e487b7160e01b600052601260045260246000fd5b6000826119f0576119f06119cb565b500490565b600060018201611a0757611a07611967565b5060010190565b600060208284031215611a2057600080fd5b81516107ad816117ab565b634e487b7160e01b600052603260045260246000fd5b600060208284031215611a5357600080fd5b815180151581146107ad57600080fd5b600082611a7257611a726119cb565b500690565b6000825160005b81811015611a985760208186018101518583015201611a7e565b81811115611aa7576000828501525b50919091019291505056fea2646970667358221220ef7e3a96ee1a7000c2adace2a93909bb0fcb8f826e874390d6c72060a813290f64736f6c634300080d0033a2646970667358221220943c1013dfbd270919ac55756531130429c376e6c5a8727aa2bde2d722f9ca0764736f6c634300080d0033

Block Transaction Difficulty Gas Used Reward
Block Uncle Number Difficulty Gas Used Reward
Loading
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.