Source Code
Latest 25 from a total of 591 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Withdraw | 7806779 | 4 hrs ago | IN | 0 HYPE | 0.0000267 | ||||
Withdraw | 7804977 | 4 hrs ago | IN | 0 HYPE | 0.00008278 | ||||
Deposit | 7798701 | 6 hrs ago | IN | 0 HYPE | 0.00387362 | ||||
Withdraw | 7793676 | 8 hrs ago | IN | 0 HYPE | 0.00016289 | ||||
Withdraw | 7792644 | 8 hrs ago | IN | 0 HYPE | 0.00002937 | ||||
Deposit | 7787841 | 9 hrs ago | IN | 0 HYPE | 0.0000363 | ||||
Deposit | 7787435 | 9 hrs ago | IN | 0 HYPE | 0.0000363 | ||||
Deposit | 7785958 | 10 hrs ago | IN | 0 HYPE | 0.00003611 | ||||
Deposit | 7778780 | 12 hrs ago | IN | 0 HYPE | 0.00004596 | ||||
Deposit | 7775932 | 12 hrs ago | IN | 0 HYPE | 0.00003366 | ||||
Withdraw | 7774555 | 13 hrs ago | IN | 0 HYPE | 0.00003204 | ||||
Deposit | 7770674 | 14 hrs ago | IN | 0 HYPE | 0.00003351 | ||||
Deposit | 7770076 | 14 hrs ago | IN | 0 HYPE | 0.00004268 | ||||
Deposit | 7767375 | 15 hrs ago | IN | 0 HYPE | 0.00003351 | ||||
Deposit | 7767133 | 15 hrs ago | IN | 0 HYPE | 0.00003351 | ||||
Deposit | 7766481 | 15 hrs ago | IN | 0 HYPE | 0.00003611 | ||||
Withdraw | 7755623 | 18 hrs ago | IN | 0 HYPE | 0.00032581 | ||||
Withdraw | 7731967 | 24 hrs ago | IN | 0 HYPE | 0.00006223 | ||||
Withdraw | 7731192 | 25 hrs ago | IN | 0 HYPE | 0.00003556 | ||||
Withdraw | 7730111 | 25 hrs ago | IN | 0 HYPE | 0.00003204 | ||||
Withdraw | 7721517 | 27 hrs ago | IN | 0 HYPE | 0.00004272 | ||||
Deposit | 7718310 | 28 hrs ago | IN | 0 HYPE | 0.00010177 | ||||
Deposit | 7717012 | 28 hrs ago | IN | 0 HYPE | 0.00010333 | ||||
Deposit | 7716497 | 29 hrs ago | IN | 0 HYPE | 0.00005015 | ||||
Withdraw | 7715734 | 29 hrs ago | IN | 0 HYPE | 0.00002937 |
Latest 1 internal transaction
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
3765099 | 55 days ago | Contract Creation | 0 HYPE |
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
Gauge
Compiler Version
v0.8.28+commit.7893614a
Optimization Enabled:
Yes with 200 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; import {FixedPointMathLib} from "solady/utils/FixedPointMathLib.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {SystemEpoch} from "./SystemEpoch.sol"; import {IBribe} from "../interfaces/IBribe.sol"; import {IGauge} from "../interfaces/IGauge.sol"; import {IVoter} from "../interfaces/IVoter.sol"; import {IVotingEscrow} from "../interfaces/IVotingEscrow.sol"; import {ICurveGauge} from "../interfaces/ICurveGauge.sol"; // Gauges are used to incentivize pools, they emit reward tokens over 7 days for staked LP tokens contract Gauge is IGauge, SystemEpoch { address public immutable stake; // the LP token that needs to be staked for rewards address public immutable _ve; // the ve token used for gauges address public immutable internal_bribe; address public immutable external_bribe; address public immutable voter; uint256 public derivedSupply; mapping(address => uint256) public derivedBalances; bool public isForPair; uint256 internal constant PRECISION = 10 ** 18; uint256 internal constant MAX_REWARD_TOKENS = 16; // default snx staking contract implementation mapping(address => uint256) public rewardRate; mapping(address => uint256) public periodFinish; mapping(address => uint256) public lastUpdateTime; mapping(address => uint256) public rewardPerTokenStored; mapping(address => mapping(address => uint256)) public lastEarn; mapping(address => mapping(address => uint256)) public userRewardPerTokenStored; mapping(address => uint256) public tokenIds; uint256 public totalSupply; mapping(address => uint256) public balanceOf; address public staking; address[] public rewards; address[8] public stakingRewards; uint8 private _stakingRewardsCount; mapping(address => bool) public isReward; mapping(address => bool) public isStakingReward; /// @notice A checkpoint for marking balance struct Checkpoint { uint256 timestamp; uint256 balanceOf; } /// @notice A checkpoint for marking reward rate struct RewardPerTokenCheckpoint { uint256 timestamp; uint256 rewardPerToken; } /// @notice A checkpoint for marking supply struct SupplyCheckpoint { uint256 timestamp; uint256 supply; } /// @notice A record of balance checkpoints for each account, by index mapping(address => mapping(uint256 => Checkpoint)) public checkpoints; /// @notice The number of checkpoints for each account mapping(address => uint256) public numCheckpoints; /// @notice A record of balance checkpoints for each token, by index mapping(uint256 => SupplyCheckpoint) public supplyCheckpoints; /// @notice The number of checkpoints uint256 public supplyNumCheckpoints; /// @notice A record of balance checkpoints for each token, by index mapping(address => mapping(uint256 => RewardPerTokenCheckpoint)) public rewardPerTokenCheckpoints; /// @notice The number of checkpoints for each token mapping(address => uint256) public rewardPerTokenNumCheckpoints; event Deposit(address indexed from, uint256 tokenId, uint256 amount); event Withdraw(address indexed from, uint256 tokenId, uint256 amount); event NotifyReward(address indexed from, address indexed reward, uint256 amount); event ClaimFees(address indexed from, uint256 claimed0, uint256 claimed1); event ClaimRewards(address indexed from, address indexed reward, uint256 amount); constructor( address _stake, address _staking, address _internal_bribe, address _external_bribe, address __ve, address _voter, bool _forPair, address[] memory _allowedRewardTokens ) { stake = _stake; staking = _staking; internal_bribe = _internal_bribe; external_bribe = _external_bribe; _ve = __ve; voter = _voter; isForPair = _forPair; for (uint256 i; i < _allowedRewardTokens.length; i++) { if (_allowedRewardTokens[i] != address(0)) { isReward[_allowedRewardTokens[i]] = true; rewards.push(_allowedRewardTokens[i]); } } if (_staking != address(0)) { ICurveGauge(_staking).set_rewards_receiver(IVotingEscrow(__ve).team()); } } // simple re-entrancy check uint256 internal _unlocked = 1; modifier lock() { require(_unlocked == 1); _unlocked = 2; _; _unlocked = 1; } function claimFees() external lock { require(msg.sender == IVotingEscrow(_ve).team(), "only team"); if (staking == address(0)) { return; } ICurveGauge(staking).claim_rewards(address(this), address(0)); } /** * @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 account The address of the account to check * @param timestamp The timestamp to get the balance at * @return The balance the account had as of the given block */ function getPriorBalanceIndex(address account, uint256 timestamp) public view returns (uint256) { uint256 nCheckpoints = numCheckpoints[account]; if (nCheckpoints == 0) { return 0; } // First check most recent balance if (checkpoints[account][nCheckpoints - 1].timestamp <= timestamp) { return (nCheckpoints - 1); } // Next check implicit zero balance if (checkpoints[account][0].timestamp > timestamp) { return 0; } uint256 lower = 0; uint256 upper = nCheckpoints - 1; while (upper > lower) { uint256 center = upper - (upper - lower) / 2; // ceil, avoiding overflow Checkpoint memory cp = checkpoints[account][center]; if (cp.timestamp == timestamp) { return center; } else if (cp.timestamp < timestamp) { lower = center; } else { upper = center - 1; } } return lower; } function getPriorSupplyIndex(uint256 timestamp) public view returns (uint256) { uint256 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; } uint256 lower = 0; uint256 upper = nCheckpoints - 1; while (upper > lower) { uint256 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, uint256 timestamp) public view returns (uint256, uint256) { uint256 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); } uint256 lower = 0; uint256 upper = nCheckpoints - 1; while (upper > lower) { uint256 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(address account, uint256 balance) internal { uint256 _timestamp = block.timestamp; uint256 _nCheckPoints = numCheckpoints[account]; if (_nCheckPoints > 0 && checkpoints[account][_nCheckPoints - 1].timestamp == _timestamp) { checkpoints[account][_nCheckPoints - 1].balanceOf = balance; } else { checkpoints[account][_nCheckPoints] = Checkpoint(_timestamp, balance); numCheckpoints[account] = _nCheckPoints + 1; } } function _writeRewardPerTokenCheckpoint(address token, uint256 reward, uint256 timestamp) internal { uint256 _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 { uint256 _nCheckPoints = supplyNumCheckpoints; uint256 _timestamp = block.timestamp; if (_nCheckPoints > 0 && supplyCheckpoints[_nCheckPoints - 1].timestamp == _timestamp) { supplyCheckpoints[_nCheckPoints - 1].supply = derivedSupply; } else { supplyCheckpoints[_nCheckPoints] = SupplyCheckpoint(_timestamp, derivedSupply); supplyNumCheckpoints = _nCheckPoints + 1; } } function rewardsListLength() external view returns (uint256) { 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 (uint256) { return FixedPointMathLib.min(block.timestamp, periodFinish[token]); } function getReward(address account, address[] memory tokens) external lock { require(msg.sender == account || msg.sender == voter); _unlocked = 1; IVoter(voter).distribute(address(this)); _unlocked = 2; for (uint256 i = 0; i < tokens.length; i++) { (rewardPerTokenStored[tokens[i]], lastUpdateTime[tokens[i]]) = _updateRewardPerToken(tokens[i], type(uint256).max, true); uint256 _reward = earned(tokens[i], account); lastEarn[tokens[i]][account] = block.timestamp; userRewardPerTokenStored[tokens[i]][account] = rewardPerTokenStored[tokens[i]]; if (_reward > 0) _safeTransfer(tokens[i], account, _reward); emit ClaimRewards(msg.sender, tokens[i], _reward); } uint256 _derivedBalance = derivedBalances[account]; derivedSupply -= _derivedBalance; _derivedBalance = derivedBalance(account); derivedBalances[account] = _derivedBalance; derivedSupply += _derivedBalance; _writeCheckpoint(account, derivedBalances[account]); _writeSupplyCheckpoint(); } function rewardPerToken(address token) public view returns (uint256) { if (derivedSupply == 0) { return rewardPerTokenStored[token]; } return rewardPerTokenStored[token] + ( (lastTimeRewardApplicable(token) - FixedPointMathLib.min(lastUpdateTime[token], periodFinish[token])) * rewardRate[token] * PRECISION / derivedSupply ); } function derivedBalance(address account) public view returns (uint256) { return balanceOf[account]; } function batchRewardPerToken(address token, uint256 maxRuns) external { (rewardPerTokenStored[token], lastUpdateTime[token]) = _batchRewardPerToken(token, maxRuns); } function _batchRewardPerToken(address token, uint256 maxRuns) internal returns (uint256, uint256) { uint256 _startTimestamp = lastUpdateTime[token]; uint256 reward = rewardPerTokenStored[token]; if (supplyNumCheckpoints == 0) { return (reward, _startTimestamp); } if (rewardRate[token] == 0) { return (reward, block.timestamp); } uint256 _startIndex = getPriorSupplyIndex(_startTimestamp); uint256 _endIndex = FixedPointMathLib.min(supplyNumCheckpoints - 1, maxRuns); for (uint256 i = _startIndex; i < _endIndex; i++) { SupplyCheckpoint memory sp0 = supplyCheckpoints[i]; if (sp0.supply > 0) { SupplyCheckpoint memory sp1 = supplyCheckpoints[i + 1]; (uint256 _reward, uint256 _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, uint256 timestamp1, uint256 timestamp0, uint256 supply, uint256 startTimestamp ) internal view returns (uint256, uint256) { uint256 endTime = FixedPointMathLib.max(timestamp1, startTimestamp); return ( ( ( FixedPointMathLib.min(endTime, periodFinish[token]) - FixedPointMathLib.min(FixedPointMathLib.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, uint256 maxRuns) external { (rewardPerTokenStored[token], lastUpdateTime[token]) = _updateRewardPerToken(token, maxRuns, false); } function _updateRewardForAllTokens() internal { uint256 length = rewards.length; for (uint256 i; i < length; i++) { address token = rewards[i]; (rewardPerTokenStored[token], lastUpdateTime[token]) = _updateRewardPerToken(token, type(uint256).max, true); } } function _updateRewardPerToken(address token, uint256 maxRuns, bool actualLast) internal returns (uint256, uint256) { uint256 _startTimestamp = lastUpdateTime[token]; uint256 reward = rewardPerTokenStored[token]; if (supplyNumCheckpoints == 0) { return (reward, _startTimestamp); } if (rewardRate[token] == 0) { return (reward, block.timestamp); } uint256 _startIndex = getPriorSupplyIndex(_startTimestamp); uint256 _endIndex = FixedPointMathLib.min(supplyNumCheckpoints - 1, maxRuns); if (_endIndex > 0) { for (uint256 i = _startIndex; i <= _endIndex - 1; i++) { SupplyCheckpoint memory sp0 = supplyCheckpoints[i]; if (sp0.supply > 0) { SupplyCheckpoint memory sp1 = supplyCheckpoints[i + 1]; (uint256 _reward, uint256 _endTime) = _calcRewardPerToken(token, sp1.timestamp, sp0.timestamp, sp0.supply, _startTimestamp); reward += _reward; _writeRewardPerTokenCheckpoint(token, reward, _endTime); _startTimestamp = _endTime; } } } // need to override the last value with actual numbers only on deposit/withdraw/claim/notify actions if (actualLast) { SupplyCheckpoint memory sp = supplyCheckpoints[_endIndex]; if (sp.supply > 0) { (uint256 _reward,) = _calcRewardPerToken( token, lastTimeRewardApplicable(token), FixedPointMathLib.max(sp.timestamp, _startTimestamp), sp.supply, _startTimestamp ); reward += _reward; _writeRewardPerTokenCheckpoint(token, reward, block.timestamp); _startTimestamp = block.timestamp; } } return (reward, _startTimestamp); } // earned is an estimation, it won't be exact till the supply > rewardPerToken calculations have run function earned(address token, address account) public view returns (uint256) { uint256 _startTimestamp = FixedPointMathLib.max(lastEarn[token][account], rewardPerTokenCheckpoints[token][0].timestamp); if (numCheckpoints[account] == 0) { return 0; } uint256 _startIndex = getPriorBalanceIndex(account, _startTimestamp); uint256 _endIndex = numCheckpoints[account] - 1; uint256 reward = 0; if (_endIndex > 0) { for (uint256 i = _startIndex; i <= _endIndex - 1; i++) { Checkpoint memory cp0 = checkpoints[account][i]; Checkpoint memory cp1 = checkpoints[account][i + 1]; (uint256 _rewardPerTokenStored0,) = getPriorRewardPerToken(token, cp0.timestamp); (uint256 _rewardPerTokenStored1,) = getPriorRewardPerToken(token, cp1.timestamp); reward += cp0.balanceOf * (_rewardPerTokenStored1 - _rewardPerTokenStored0) / PRECISION; } } Checkpoint memory cp = checkpoints[account][_endIndex]; (uint256 _rewardPerTokenStored,) = getPriorRewardPerToken(token, cp.timestamp); reward += cp.balanceOf * ( rewardPerToken(token) - FixedPointMathLib.max(_rewardPerTokenStored, userRewardPerTokenStored[token][account]) ) / PRECISION; return reward; } function depositAll(uint256 tokenId) external { deposit(IERC20(stake).balanceOf(msg.sender), tokenId); } function deposit(uint256 amount, uint256 tokenId) public lock { require(amount > 0); _updateRewardForAllTokens(); _safeTransferFrom(stake, msg.sender, address(this), amount); address stakingAddress = staking; if (stakingAddress != address(0)) { IERC20(stake).approve(stakingAddress, amount); ICurveGauge(stakingAddress).deposit(amount); } totalSupply += amount; balanceOf[msg.sender] += amount; if (tokenId > 0) { require(IVotingEscrow(_ve).ownerOf(tokenId) == msg.sender); if (tokenIds[msg.sender] == 0) { tokenIds[msg.sender] = tokenId; IVoter(voter).attachTokenToGauge(tokenId, msg.sender); } require(tokenIds[msg.sender] == tokenId); } else { tokenId = tokenIds[msg.sender]; } uint256 _derivedBalance = derivedBalances[msg.sender]; derivedSupply -= _derivedBalance; _derivedBalance = derivedBalance(msg.sender); derivedBalances[msg.sender] = _derivedBalance; derivedSupply += _derivedBalance; _writeCheckpoint(msg.sender, _derivedBalance); _writeSupplyCheckpoint(); IVoter(voter).emitDeposit(tokenId, msg.sender, amount); emit Deposit(msg.sender, tokenId, amount); } function withdrawAll() external { withdraw(balanceOf[msg.sender]); } function withdraw(uint256 amount) public { uint256 tokenId = 0; if (amount == balanceOf[msg.sender]) { tokenId = tokenIds[msg.sender]; } withdrawToken(amount, tokenId); } function withdrawToken(uint256 amount, uint256 tokenId) public lock { _updateRewardForAllTokens(); totalSupply -= amount; balanceOf[msg.sender] -= amount; if (staking != address(0)) { ICurveGauge(staking).withdraw(amount); } _safeTransfer(stake, msg.sender, amount); if (tokenId > 0) { require(tokenId == tokenIds[msg.sender]); tokenIds[msg.sender] = 0; IVoter(voter).detachTokenFromGauge(tokenId, msg.sender); } else { tokenId = tokenIds[msg.sender]; } uint256 _derivedBalance = derivedBalances[msg.sender]; derivedSupply -= _derivedBalance; _derivedBalance = derivedBalance(msg.sender); derivedBalances[msg.sender] = _derivedBalance; derivedSupply += _derivedBalance; _writeCheckpoint(msg.sender, derivedBalances[msg.sender]); _writeSupplyCheckpoint(); IVoter(voter).emitWithdraw(tokenId, msg.sender, amount); emit Withdraw(msg.sender, tokenId, amount); } function left(address token) external view returns (uint256) { if (block.timestamp >= periodFinish[token]) return 0; uint256 _remaining = periodFinish[token] - block.timestamp; return _remaining * rewardRate[token]; } function notifyRewardAmount(address token, uint256 amount) external lock { require(token != stake); require(amount > 0); if (!isReward[token]) { require(IVoter(voter).isWhitelisted(token), "rewards tokens must be whitelisted"); require(rewards.length < MAX_REWARD_TOKENS, "too many rewards tokens"); } if (rewardRate[token] == 0) _writeRewardPerTokenCheckpoint(token, 0, block.timestamp); (rewardPerTokenStored[token], lastUpdateTime[token]) = _updateRewardPerToken(token, type(uint256).max, true); if (block.timestamp >= periodFinish[token]) { _safeTransferFrom(token, msg.sender, address(this), amount); rewardRate[token] = amount / EPOCH; } else { uint256 _remaining = periodFinish[token] - block.timestamp; uint256 _left = _remaining * rewardRate[token]; require(amount > _left); _safeTransferFrom(token, msg.sender, address(this), amount); rewardRate[token] = (amount + _left) / EPOCH; } require(rewardRate[token] > 0); uint256 balance = IERC20(token).balanceOf(address(this)); require(rewardRate[token] <= balance / EPOCH, "Provided reward too high"); periodFinish[token] = block.timestamp + EPOCH; if (!isReward[token]) { isReward[token] = true; rewards.push(token); } emit NotifyReward(msg.sender, token, amount); } function swapOutRewardToken(uint256 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 enableStaking(address _newStaking, address _rewardsReceiver) external { require(msg.sender == IVotingEscrow(_ve).team(), "only team"); require(staking == address(0), "staking already exists"); staking = _newStaking; ICurveGauge(_newStaking).set_rewards_receiver(_rewardsReceiver); IERC20 stakeToken = IERC20(stake); uint256 balance = stakeToken.balanceOf(address(this)); if (balance > 0) { stakeToken.approve(address(_newStaking), balance); ICurveGauge(_newStaking).deposit(balance); } } function setRewardsReceiver(address _rewardsReceiver) external { require(msg.sender == IVotingEscrow(_ve).team(), "only team"); require(staking != address(0), "staking already exists"); ICurveGauge(staking).set_rewards_receiver(_rewardsReceiver); } 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)))); } function _safeApprove(address token, address spender, uint256 value) internal { require(token.code.length > 0); (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.approve.selector, spender, value)); require(success && (data.length == 0 || abi.decode(data, (bool)))); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC-20 standard as defined in the ERC. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the value of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the value of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves a `value` amount of tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 value) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the * allowance mechanism. `value` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 value) external returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Arithmetic library with operations for fixed-point numbers. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/FixedPointMathLib.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol) library FixedPointMathLib { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The operation failed, as the output exceeds the maximum value of uint256. error ExpOverflow(); /// @dev The operation failed, as the output exceeds the maximum value of uint256. error FactorialOverflow(); /// @dev The operation failed, due to an overflow. error RPowOverflow(); /// @dev The mantissa is too big to fit. error MantissaOverflow(); /// @dev The operation failed, due to an multiplication overflow. error MulWadFailed(); /// @dev The operation failed, due to an multiplication overflow. error SMulWadFailed(); /// @dev The operation failed, either due to a multiplication overflow, or a division by a zero. error DivWadFailed(); /// @dev The operation failed, either due to a multiplication overflow, or a division by a zero. error SDivWadFailed(); /// @dev The operation failed, either due to a multiplication overflow, or a division by a zero. error MulDivFailed(); /// @dev The division failed, as the denominator is zero. error DivFailed(); /// @dev The full precision multiply-divide operation failed, either due /// to the result being larger than 256 bits, or a division by a zero. error FullMulDivFailed(); /// @dev The output is undefined, as the input is less-than-or-equal to zero. error LnWadUndefined(); /// @dev The input outside the acceptable domain. error OutOfDomain(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The scalar of ETH and most ERC20s. uint256 internal constant WAD = 1e18; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* SIMPLIFIED FIXED POINT OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Equivalent to `(x * y) / WAD` rounded down. function mulWad(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to `require(y == 0 || x <= type(uint256).max / y)`. if gt(x, div(not(0), y)) { if y { mstore(0x00, 0xbac65e5b) // `MulWadFailed()`. revert(0x1c, 0x04) } } z := div(mul(x, y), WAD) } } /// @dev Equivalent to `(x * y) / WAD` rounded down. function sMulWad(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := mul(x, y) // Equivalent to `require((x == 0 || z / x == y) && !(x == -1 && y == type(int256).min))`. if iszero(gt(or(iszero(x), eq(sdiv(z, x), y)), lt(not(x), eq(y, shl(255, 1))))) { mstore(0x00, 0xedcd4dd4) // `SMulWadFailed()`. revert(0x1c, 0x04) } z := sdiv(z, WAD) } } /// @dev Equivalent to `(x * y) / WAD` rounded down, but without overflow checks. function rawMulWad(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := div(mul(x, y), WAD) } } /// @dev Equivalent to `(x * y) / WAD` rounded down, but without overflow checks. function rawSMulWad(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := sdiv(mul(x, y), WAD) } } /// @dev Equivalent to `(x * y) / WAD` rounded up. function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mul(x, y) // Equivalent to `require(y == 0 || x <= type(uint256).max / y)`. if iszero(eq(div(z, y), x)) { if y { mstore(0x00, 0xbac65e5b) // `MulWadFailed()`. revert(0x1c, 0x04) } } z := add(iszero(iszero(mod(z, WAD))), div(z, WAD)) } } /// @dev Equivalent to `(x * y) / WAD` rounded up, but without overflow checks. function rawMulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := add(iszero(iszero(mod(mul(x, y), WAD))), div(mul(x, y), WAD)) } } /// @dev Equivalent to `(x * WAD) / y` rounded down. function divWad(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to `require(y != 0 && x <= type(uint256).max / WAD)`. if iszero(mul(y, lt(x, add(1, div(not(0), WAD))))) { mstore(0x00, 0x7c5f487d) // `DivWadFailed()`. revert(0x1c, 0x04) } z := div(mul(x, WAD), y) } } /// @dev Equivalent to `(x * WAD) / y` rounded down. function sDivWad(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := mul(x, WAD) // Equivalent to `require(y != 0 && ((x * WAD) / WAD == x))`. if iszero(mul(y, eq(sdiv(z, WAD), x))) { mstore(0x00, 0x5c43740d) // `SDivWadFailed()`. revert(0x1c, 0x04) } z := sdiv(z, y) } } /// @dev Equivalent to `(x * WAD) / y` rounded down, but without overflow and divide by zero checks. function rawDivWad(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := div(mul(x, WAD), y) } } /// @dev Equivalent to `(x * WAD) / y` rounded down, but without overflow and divide by zero checks. function rawSDivWad(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := sdiv(mul(x, WAD), y) } } /// @dev Equivalent to `(x * WAD) / y` rounded up. function divWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to `require(y != 0 && x <= type(uint256).max / WAD)`. if iszero(mul(y, lt(x, add(1, div(not(0), WAD))))) { mstore(0x00, 0x7c5f487d) // `DivWadFailed()`. revert(0x1c, 0x04) } z := add(iszero(iszero(mod(mul(x, WAD), y))), div(mul(x, WAD), y)) } } /// @dev Equivalent to `(x * WAD) / y` rounded up, but without overflow and divide by zero checks. function rawDivWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := add(iszero(iszero(mod(mul(x, WAD), y))), div(mul(x, WAD), y)) } } /// @dev Equivalent to `x` to the power of `y`. /// because `x ** y = (e ** ln(x)) ** y = e ** (ln(x) * y)`. /// Note: This function is an approximation. function powWad(int256 x, int256 y) internal pure returns (int256) { // Using `ln(x)` means `x` must be greater than 0. return expWad((lnWad(x) * y) / int256(WAD)); } /// @dev Returns `exp(x)`, denominated in `WAD`. /// Credit to Remco Bloemen under MIT license: https://2π.com/22/exp-ln /// Note: This function is an approximation. Monotonically increasing. function expWad(int256 x) internal pure returns (int256 r) { unchecked { // When the result is less than 0.5 we return zero. // This happens when `x <= (log(1e-18) * 1e18) ~ -4.15e19`. if (x <= -41446531673892822313) return r; /// @solidity memory-safe-assembly assembly { // When the result is greater than `(2**255 - 1) / 1e18` we can not represent it as // an int. This happens when `x >= floor(log((2**255 - 1) / 1e18) * 1e18) ≈ 135`. if iszero(slt(x, 135305999368893231589)) { mstore(0x00, 0xa37bfec9) // `ExpOverflow()`. revert(0x1c, 0x04) } } // `x` is now in the range `(-42, 136) * 1e18`. Convert to `(-42, 136) * 2**96` // for more intermediate precision and a binary basis. This base conversion // is a multiplication by 1e18 / 2**96 = 5**18 / 2**78. x = (x << 78) / 5 ** 18; // Reduce range of x to (-½ ln 2, ½ ln 2) * 2**96 by factoring out powers // of two such that exp(x) = exp(x') * 2**k, where k is an integer. // Solving this gives k = round(x / log(2)) and x' = x - k * log(2). int256 k = ((x << 96) / 54916777467707473351141471128 + 2 ** 95) >> 96; x = x - k * 54916777467707473351141471128; // `k` is in the range `[-61, 195]`. // Evaluate using a (6, 7)-term rational approximation. // `p` is made monic, we'll multiply by a scale factor later. int256 y = x + 1346386616545796478920950773328; y = ((y * x) >> 96) + 57155421227552351082224309758442; int256 p = y + x - 94201549194550492254356042504812; p = ((p * y) >> 96) + 28719021644029726153956944680412240; p = p * x + (4385272521454847904659076985693276 << 96); // We leave `p` in `2**192` basis so we don't need to scale it back up for the division. int256 q = x - 2855989394907223263936484059900; q = ((q * x) >> 96) + 50020603652535783019961831881945; q = ((q * x) >> 96) - 533845033583426703283633433725380; q = ((q * x) >> 96) + 3604857256930695427073651918091429; q = ((q * x) >> 96) - 14423608567350463180887372962807573; q = ((q * x) >> 96) + 26449188498355588339934803723976023; /// @solidity memory-safe-assembly assembly { // Div in assembly because solidity adds a zero check despite the unchecked. // The q polynomial won't have zeros in the domain as all its roots are complex. // No scaling is necessary because p is already `2**96` too large. r := sdiv(p, q) } // r should be in the range `(0.09, 0.25) * 2**96`. // We now need to multiply r by: // - The scale factor `s ≈ 6.031367120`. // - The `2**k` factor from the range reduction. // - The `1e18 / 2**96` factor for base conversion. // We do this all at once, with an intermediate result in `2**213` // basis, so the final right shift is always by a positive amount. r = int256( (uint256(r) * 3822833074963236453042738258902158003155416615667) >> uint256(195 - k) ); } } /// @dev Returns `ln(x)`, denominated in `WAD`. /// Credit to Remco Bloemen under MIT license: https://2π.com/22/exp-ln /// Note: This function is an approximation. Monotonically increasing. function lnWad(int256 x) internal pure returns (int256 r) { /// @solidity memory-safe-assembly assembly { // We want to convert `x` from `10**18` fixed point to `2**96` fixed point. // We do this by multiplying by `2**96 / 10**18`. But since // `ln(x * C) = ln(x) + ln(C)`, we can simply do nothing here // and add `ln(2**96 / 10**18)` at the end. // Compute `k = log2(x) - 96`, `r = 159 - k = 255 - log2(x) = 255 ^ log2(x)`. r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) // We place the check here for more optimal stack operations. if iszero(sgt(x, 0)) { mstore(0x00, 0x1615e638) // `LnWadUndefined()`. revert(0x1c, 0x04) } // forgefmt: disable-next-item r := xor(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)), 0xf8f9f9faf9fdfafbf9fdfcfdfafbfcfef9fafdfafcfcfbfefafafcfbffffffff)) // Reduce range of x to (1, 2) * 2**96 // ln(2^k * x) = k * ln(2) + ln(x) x := shr(159, shl(r, x)) // Evaluate using a (8, 8)-term rational approximation. // `p` is made monic, we will multiply by a scale factor later. // forgefmt: disable-next-item let p := sub( // This heavily nested expression is to avoid stack-too-deep for via-ir. sar(96, mul(add(43456485725739037958740375743393, sar(96, mul(add(24828157081833163892658089445524, sar(96, mul(add(3273285459638523848632254066296, x), x))), x))), x)), 11111509109440967052023855526967) p := sub(sar(96, mul(p, x)), 45023709667254063763336534515857) p := sub(sar(96, mul(p, x)), 14706773417378608786704636184526) p := sub(mul(p, x), shl(96, 795164235651350426258249787498)) // We leave `p` in `2**192` basis so we don't need to scale it back up for the division. // `q` is monic by convention. let q := add(5573035233440673466300451813936, x) q := add(71694874799317883764090561454958, sar(96, mul(x, q))) q := add(283447036172924575727196451306956, sar(96, mul(x, q))) q := add(401686690394027663651624208769553, sar(96, mul(x, q))) q := add(204048457590392012362485061816622, sar(96, mul(x, q))) q := add(31853899698501571402653359427138, sar(96, mul(x, q))) q := add(909429971244387300277376558375, sar(96, mul(x, q))) // `p / q` is in the range `(0, 0.125) * 2**96`. // Finalization, we need to: // - Multiply by the scale factor `s = 5.549…`. // - Add `ln(2**96 / 10**18)`. // - Add `k * ln(2)`. // - Multiply by `10**18 / 2**96 = 5**18 >> 78`. // The q polynomial is known not to have zeros in the domain. // No scaling required because p is already `2**96` too large. p := sdiv(p, q) // Multiply by the scaling factor: `s * 5**18 * 2**96`, base is now `5**18 * 2**192`. p := mul(1677202110996718588342820967067443963516166, p) // Add `ln(2) * k * 5**18 * 2**192`. // forgefmt: disable-next-item p := add(mul(16597577552685614221487285958193947469193820559219878177908093499208371, sub(159, r)), p) // Add `ln(2**96 / 10**18) * 5**18 * 2**192`. p := add(600920179829731861736702779321621459595472258049074101567377883020018308, p) // Base conversion: mul `2**18 / 2**192`. r := sar(174, p) } } /// @dev Returns `W_0(x)`, denominated in `WAD`. /// See: https://en.wikipedia.org/wiki/Lambert_W_function /// a.k.a. Product log function. This is an approximation of the principal branch. /// Note: This function is an approximation. Monotonically increasing. function lambertW0Wad(int256 x) internal pure returns (int256 w) { // forgefmt: disable-next-item unchecked { if ((w = x) <= -367879441171442322) revert OutOfDomain(); // `x` less than `-1/e`. (int256 wad, int256 p) = (int256(WAD), x); uint256 c; // Whether we need to avoid catastrophic cancellation. uint256 i = 4; // Number of iterations. if (w <= 0x1ffffffffffff) { if (-0x4000000000000 <= w) { i = 1; // Inputs near zero only take one step to converge. } else if (w <= -0x3ffffffffffffff) { i = 32; // Inputs near `-1/e` take very long to converge. } } else if (uint256(w >> 63) == uint256(0)) { /// @solidity memory-safe-assembly assembly { // Inline log2 for more performance, since the range is small. let v := shr(49, w) let l := shl(3, lt(0xff, v)) l := add(or(l, byte(and(0x1f, shr(shr(l, v), 0x8421084210842108cc6318c6db6d54be)), 0x0706060506020504060203020504030106050205030304010505030400000000)), 49) w := sdiv(shl(l, 7), byte(sub(l, 31), 0x0303030303030303040506080c13)) c := gt(l, 60) i := add(2, add(gt(l, 53), c)) } } else { int256 ll = lnWad(w = lnWad(w)); /// @solidity memory-safe-assembly assembly { // `w = ln(x) - ln(ln(x)) + b * ln(ln(x)) / ln(x)`. w := add(sdiv(mul(ll, 1023715080943847266), w), sub(w, ll)) i := add(3, iszero(shr(68, x))) c := iszero(shr(143, x)) } if (c == uint256(0)) { do { // If `x` is big, use Newton's so that intermediate values won't overflow. int256 e = expWad(w); /// @solidity memory-safe-assembly assembly { let t := mul(w, div(e, wad)) w := sub(w, sdiv(sub(t, x), div(add(e, t), wad))) } if (p <= w) break; p = w; } while (--i != uint256(0)); /// @solidity memory-safe-assembly assembly { w := sub(w, sgt(w, 2)) } return w; } } do { // Otherwise, use Halley's for faster convergence. int256 e = expWad(w); /// @solidity memory-safe-assembly assembly { let t := add(w, wad) let s := sub(mul(w, e), mul(x, wad)) w := sub(w, sdiv(mul(s, wad), sub(mul(e, t), sdiv(mul(add(t, wad), s), add(t, t))))) } if (p <= w) break; p = w; } while (--i != c); /// @solidity memory-safe-assembly assembly { w := sub(w, sgt(w, 2)) } // For certain ranges of `x`, we'll use the quadratic-rate recursive formula of // R. Iacono and J.P. Boyd for the last iteration, to avoid catastrophic cancellation. if (c == uint256(0)) return w; int256 t = w | 1; /// @solidity memory-safe-assembly assembly { x := sdiv(mul(x, wad), t) } x = (t * (wad + lnWad(x))); /// @solidity memory-safe-assembly assembly { w := sdiv(x, add(wad, t)) } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* GENERAL NUMBER UTILITIES */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns `a * b == x * y`, with full precision. function fullMulEq(uint256 a, uint256 b, uint256 x, uint256 y) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { result := and(eq(mul(a, b), mul(x, y)), eq(mulmod(x, y, not(0)), mulmod(a, b, not(0)))) } } /// @dev Calculates `floor(x * y / d)` with full precision. /// Throws if result overflows a uint256 or when `d` is zero. /// Credit to Remco Bloemen under MIT license: https://2π.com/21/muldiv function fullMulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // 512-bit multiply `[p1 p0] = x * y`. // Compute the product mod `2**256` and mod `2**256 - 1` // then use the Chinese Remainder Theorem to reconstruct // the 512 bit result. The result is stored in two 256 // variables such that `product = p1 * 2**256 + p0`. // Temporarily use `z` as `p0` to save gas. z := mul(x, y) // Lower 256 bits of `x * y`. for {} 1 {} { // If overflows. if iszero(mul(or(iszero(x), eq(div(z, x), y)), d)) { let mm := mulmod(x, y, not(0)) let p1 := sub(mm, add(z, lt(mm, z))) // Upper 256 bits of `x * y`. /*------------------- 512 by 256 division --------------------*/ // Make division exact by subtracting the remainder from `[p1 p0]`. let r := mulmod(x, y, d) // Compute remainder using mulmod. let t := and(d, sub(0, d)) // The least significant bit of `d`. `t >= 1`. // Make sure `z` is less than `2**256`. Also prevents `d == 0`. // Placing the check here seems to give more optimal stack operations. if iszero(gt(d, p1)) { mstore(0x00, 0xae47f702) // `FullMulDivFailed()`. revert(0x1c, 0x04) } d := div(d, t) // Divide `d` by `t`, which is a power of two. // Invert `d mod 2**256` // Now that `d` is an odd number, it has an inverse // modulo `2**256` such that `d * inv = 1 mod 2**256`. // Compute the inverse by starting with a seed that is correct // correct for four bits. That is, `d * inv = 1 mod 2**4`. let inv := xor(2, mul(3, d)) // Now use Newton-Raphson iteration to improve the precision. // Thanks to Hensel's lifting lemma, this also works in modular // arithmetic, doubling the correct bits in each step. inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**8 inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**16 inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**32 inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**64 inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**128 z := mul( // Divide [p1 p0] by the factors of two. // Shift in bits from `p1` into `p0`. For this we need // to flip `t` such that it is `2**256 / t`. or(mul(sub(p1, gt(r, z)), add(div(sub(0, t), t), 1)), div(sub(z, r), t)), mul(sub(2, mul(d, inv)), inv) // inverse mod 2**256 ) break } z := div(z, d) break } } } /// @dev Calculates `floor(x * y / d)` with full precision. /// Behavior is undefined if `d` is zero or the final result cannot fit in 256 bits. /// Performs the full 512 bit calculation regardless. function fullMulDivUnchecked(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mul(x, y) let mm := mulmod(x, y, not(0)) let p1 := sub(mm, add(z, lt(mm, z))) let t := and(d, sub(0, d)) let r := mulmod(x, y, d) d := div(d, t) let inv := xor(2, mul(3, d)) inv := mul(inv, sub(2, mul(d, inv))) inv := mul(inv, sub(2, mul(d, inv))) inv := mul(inv, sub(2, mul(d, inv))) inv := mul(inv, sub(2, mul(d, inv))) inv := mul(inv, sub(2, mul(d, inv))) z := mul( or(mul(sub(p1, gt(r, z)), add(div(sub(0, t), t), 1)), div(sub(z, r), t)), mul(sub(2, mul(d, inv)), inv) ) } } /// @dev Calculates `floor(x * y / d)` with full precision, rounded up. /// Throws if result overflows a uint256 or when `d` is zero. /// Credit to Uniswap-v3-core under MIT license: /// https://github.com/Uniswap/v3-core/blob/main/contracts/libraries/FullMath.sol function fullMulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { z = fullMulDiv(x, y, d); /// @solidity memory-safe-assembly assembly { if mulmod(x, y, d) { z := add(z, 1) if iszero(z) { mstore(0x00, 0xae47f702) // `FullMulDivFailed()`. revert(0x1c, 0x04) } } } } /// @dev Calculates `floor(x * y / 2 ** n)` with full precision. /// Throws if result overflows a uint256. /// Credit to Philogy under MIT license: /// https://github.com/SorellaLabs/angstrom/blob/main/contracts/src/libraries/X128MathLib.sol function fullMulDivN(uint256 x, uint256 y, uint8 n) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Temporarily use `z` as `p0` to save gas. z := mul(x, y) // Lower 256 bits of `x * y`. We'll call this `z`. for {} 1 {} { if iszero(or(iszero(x), eq(div(z, x), y))) { let k := and(n, 0xff) // `n`, cleaned. let mm := mulmod(x, y, not(0)) let p1 := sub(mm, add(z, lt(mm, z))) // Upper 256 bits of `x * y`. // | p1 | z | // Before: | p1_0 ¦ p1_1 | z_0 ¦ z_1 | // Final: | 0 ¦ p1_0 | p1_1 ¦ z_0 | // Check that final `z` doesn't overflow by checking that p1_0 = 0. if iszero(shr(k, p1)) { z := add(shl(sub(256, k), p1), shr(k, z)) break } mstore(0x00, 0xae47f702) // `FullMulDivFailed()`. revert(0x1c, 0x04) } z := shr(and(n, 0xff), z) break } } } /// @dev Returns `floor(x * y / d)`. /// Reverts if `x * y` overflows, or `d` is zero. function mulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mul(x, y) // Equivalent to `require(d != 0 && (y == 0 || x <= type(uint256).max / y))`. if iszero(mul(or(iszero(x), eq(div(z, x), y)), d)) { mstore(0x00, 0xad251c27) // `MulDivFailed()`. revert(0x1c, 0x04) } z := div(z, d) } } /// @dev Returns `ceil(x * y / d)`. /// Reverts if `x * y` overflows, or `d` is zero. function mulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mul(x, y) // Equivalent to `require(d != 0 && (y == 0 || x <= type(uint256).max / y))`. if iszero(mul(or(iszero(x), eq(div(z, x), y)), d)) { mstore(0x00, 0xad251c27) // `MulDivFailed()`. revert(0x1c, 0x04) } z := add(iszero(iszero(mod(z, d))), div(z, d)) } } /// @dev Returns `x`, the modular multiplicative inverse of `a`, such that `(a * x) % n == 1`. function invMod(uint256 a, uint256 n) internal pure returns (uint256 x) { /// @solidity memory-safe-assembly assembly { let g := n let r := mod(a, n) for { let y := 1 } 1 {} { let q := div(g, r) let t := g g := r r := sub(t, mul(r, q)) let u := x x := y y := sub(u, mul(y, q)) if iszero(r) { break } } x := mul(eq(g, 1), add(x, mul(slt(x, 0), n))) } } /// @dev Returns `ceil(x / d)`. /// Reverts if `d` is zero. function divUp(uint256 x, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { if iszero(d) { mstore(0x00, 0x65244e4e) // `DivFailed()`. revert(0x1c, 0x04) } z := add(iszero(iszero(mod(x, d))), div(x, d)) } } /// @dev Returns `max(0, x - y)`. Alias for `saturatingSub`. function zeroFloorSub(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mul(gt(x, y), sub(x, y)) } } /// @dev Returns `max(0, x - y)`. function saturatingSub(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mul(gt(x, y), sub(x, y)) } } /// @dev Returns `min(2 ** 256 - 1, x + y)`. function saturatingAdd(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := or(sub(0, lt(add(x, y), x)), add(x, y)) } } /// @dev Returns `min(2 ** 256 - 1, x * y)`. function saturatingMul(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := or(sub(or(iszero(x), eq(div(mul(x, y), x), y)), 1), mul(x, y)) } } /// @dev Returns `condition ? x : y`, without branching. function ternary(bool condition, uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), iszero(condition))) } } /// @dev Returns `condition ? x : y`, without branching. function ternary(bool condition, bytes32 x, bytes32 y) internal pure returns (bytes32 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), iszero(condition))) } } /// @dev Returns `condition ? x : y`, without branching. function ternary(bool condition, address x, address y) internal pure returns (address z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), iszero(condition))) } } /// @dev Returns `x != 0 ? x : y`, without branching. function coalesce(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := or(x, mul(y, iszero(x))) } } /// @dev Returns `x != bytes32(0) ? x : y`, without branching. function coalesce(bytes32 x, bytes32 y) internal pure returns (bytes32 z) { /// @solidity memory-safe-assembly assembly { z := or(x, mul(y, iszero(x))) } } /// @dev Returns `x != address(0) ? x : y`, without branching. function coalesce(address x, address y) internal pure returns (address z) { /// @solidity memory-safe-assembly assembly { z := or(x, mul(y, iszero(shl(96, x)))) } } /// @dev Exponentiate `x` to `y` by squaring, denominated in base `b`. /// Reverts if the computation overflows. function rpow(uint256 x, uint256 y, uint256 b) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mul(b, iszero(y)) // `0 ** 0 = 1`. Otherwise, `0 ** n = 0`. if x { z := xor(b, mul(xor(b, x), and(y, 1))) // `z = isEven(y) ? scale : x` let half := shr(1, b) // Divide `b` by 2. // Divide `y` by 2 every iteration. for { y := shr(1, y) } y { y := shr(1, y) } { let xx := mul(x, x) // Store x squared. let xxRound := add(xx, half) // Round to the nearest number. // Revert if `xx + half` overflowed, or if `x ** 2` overflows. if or(lt(xxRound, xx), shr(128, x)) { mstore(0x00, 0x49f7642b) // `RPowOverflow()`. revert(0x1c, 0x04) } x := div(xxRound, b) // Set `x` to scaled `xxRound`. // If `y` is odd: if and(y, 1) { let zx := mul(z, x) // Compute `z * x`. let zxRound := add(zx, half) // Round to the nearest number. // If `z * x` overflowed or `zx + half` overflowed: if or(xor(div(zx, x), z), lt(zxRound, zx)) { // Revert if `x` is non-zero. if x { mstore(0x00, 0x49f7642b) // `RPowOverflow()`. revert(0x1c, 0x04) } } z := div(zxRound, b) // Return properly scaled `zxRound`. } } } } } /// @dev Returns the square root of `x`, rounded down. function sqrt(uint256 x) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // `floor(sqrt(2**15)) = 181`. `sqrt(2**15) - 181 = 2.84`. z := 181 // The "correct" value is 1, but this saves a multiplication later. // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically. // Let `y = x / 2**r`. We check `y >= 2**(k + 8)` // but shift right by `k` bits to ensure that if `x >= 256`, then `y >= 256`. let r := shl(7, lt(0xffffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffffff, shr(r, x)))) z := shl(shr(1, r), z) // Goal was to get `z*z*y` within a small factor of `x`. More iterations could // get y in a tighter range. Currently, we will have y in `[256, 256*(2**16))`. // We ensured `y >= 256` so that the relative difference between `y` and `y+1` is small. // That's not possible if `x < 256` but we can just verify those cases exhaustively. // Now, `z*z*y <= x < z*z*(y+1)`, and `y <= 2**(16+8)`, and either `y >= 256`, or `x < 256`. // Correctness can be checked exhaustively for `x < 256`, so we assume `y >= 256`. // Then `z*sqrt(y)` is within `sqrt(257)/sqrt(256)` of `sqrt(x)`, or about 20bps. // For `s` in the range `[1/256, 256]`, the estimate `f(s) = (181/1024) * (s+1)` // is in the range `(1/2.84 * sqrt(s), 2.84 * sqrt(s))`, // with largest error when `s = 1` and when `s = 256` or `1/256`. // Since `y` is in `[256, 256*(2**16))`, let `a = y/65536`, so that `a` is in `[1/256, 256)`. // Then we can estimate `sqrt(y)` using // `sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2**18`. // There is no overflow risk here since `y < 2**136` after the first branch above. z := shr(18, mul(z, add(shr(r, x), 65536))) // A `mul()` is saved from starting `z` at 181. // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough. z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) // If `x+1` is a perfect square, the Babylonian method cycles between // `floor(sqrt(x))` and `ceil(sqrt(x))`. This statement ensures we return floor. // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division z := sub(z, lt(div(x, z), z)) } } /// @dev Returns the cube root of `x`, rounded down. /// Credit to bout3fiddy and pcaversaccio under AGPLv3 license: /// https://github.com/pcaversaccio/snekmate/blob/main/src/snekmate/utils/math.vy /// Formally verified by xuwinnie: /// https://github.com/vectorized/solady/blob/main/audits/xuwinnie-solady-cbrt-proof.pdf function cbrt(uint256 x) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { let r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) // Makeshift lookup table to nudge the approximate log2 result. z := div(shl(div(r, 3), shl(lt(0xf, shr(r, x)), 0xf)), xor(7, mod(r, 3))) // Newton-Raphson's. z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) // Round down. z := sub(z, lt(div(x, mul(z, z)), z)) } } /// @dev Returns the square root of `x`, denominated in `WAD`, rounded down. function sqrtWad(uint256 x) internal pure returns (uint256 z) { unchecked { if (x <= type(uint256).max / 10 ** 18) return sqrt(x * 10 ** 18); z = (1 + sqrt(x)) * 10 ** 9; z = (fullMulDivUnchecked(x, 10 ** 18, z) + z) >> 1; } /// @solidity memory-safe-assembly assembly { z := sub(z, gt(999999999999999999, sub(mulmod(z, z, x), 1))) // Round down. } } /// @dev Returns the cube root of `x`, denominated in `WAD`, rounded down. /// Formally verified by xuwinnie: /// https://github.com/vectorized/solady/blob/main/audits/xuwinnie-solady-cbrt-proof.pdf function cbrtWad(uint256 x) internal pure returns (uint256 z) { unchecked { if (x <= type(uint256).max / 10 ** 36) return cbrt(x * 10 ** 36); z = (1 + cbrt(x)) * 10 ** 12; z = (fullMulDivUnchecked(x, 10 ** 36, z * z) + z + z) / 3; } /// @solidity memory-safe-assembly assembly { let p := x for {} 1 {} { if iszero(shr(229, p)) { if iszero(shr(199, p)) { p := mul(p, 100000000000000000) // 10 ** 17. break } p := mul(p, 100000000) // 10 ** 8. break } if iszero(shr(249, p)) { p := mul(p, 100) } break } let t := mulmod(mul(z, z), z, p) z := sub(z, gt(lt(t, shr(1, p)), iszero(t))) // Round down. } } /// @dev Returns the factorial of `x`. function factorial(uint256 x) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := 1 if iszero(lt(x, 58)) { mstore(0x00, 0xaba0f2a2) // `FactorialOverflow()`. revert(0x1c, 0x04) } for {} x { x := sub(x, 1) } { z := mul(z, x) } } } /// @dev Returns the log2 of `x`. /// Equivalent to computing the index of the most significant bit (MSB) of `x`. /// Returns 0 if `x` is zero. function log2(uint256 x) internal pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) // forgefmt: disable-next-item r := or(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)), 0x0706060506020504060203020504030106050205030304010505030400000000)) } } /// @dev Returns the log2 of `x`, rounded up. /// Returns 0 if `x` is zero. function log2Up(uint256 x) internal pure returns (uint256 r) { r = log2(x); /// @solidity memory-safe-assembly assembly { r := add(r, lt(shl(r, 1), x)) } } /// @dev Returns the log10 of `x`. /// Returns 0 if `x` is zero. function log10(uint256 x) internal pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { if iszero(lt(x, 100000000000000000000000000000000000000)) { x := div(x, 100000000000000000000000000000000000000) r := 38 } if iszero(lt(x, 100000000000000000000)) { x := div(x, 100000000000000000000) r := add(r, 20) } if iszero(lt(x, 10000000000)) { x := div(x, 10000000000) r := add(r, 10) } if iszero(lt(x, 100000)) { x := div(x, 100000) r := add(r, 5) } r := add(r, add(gt(x, 9), add(gt(x, 99), add(gt(x, 999), gt(x, 9999))))) } } /// @dev Returns the log10 of `x`, rounded up. /// Returns 0 if `x` is zero. function log10Up(uint256 x) internal pure returns (uint256 r) { r = log10(x); /// @solidity memory-safe-assembly assembly { r := add(r, lt(exp(10, r), x)) } } /// @dev Returns the log256 of `x`. /// Returns 0 if `x` is zero. function log256(uint256 x) internal pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(shr(3, r), lt(0xff, shr(r, x))) } } /// @dev Returns the log256 of `x`, rounded up. /// Returns 0 if `x` is zero. function log256Up(uint256 x) internal pure returns (uint256 r) { r = log256(x); /// @solidity memory-safe-assembly assembly { r := add(r, lt(shl(shl(3, r), 1), x)) } } /// @dev Returns the scientific notation format `mantissa * 10 ** exponent` of `x`. /// Useful for compressing prices (e.g. using 25 bit mantissa and 7 bit exponent). function sci(uint256 x) internal pure returns (uint256 mantissa, uint256 exponent) { /// @solidity memory-safe-assembly assembly { mantissa := x if mantissa { if iszero(mod(mantissa, 1000000000000000000000000000000000)) { mantissa := div(mantissa, 1000000000000000000000000000000000) exponent := 33 } if iszero(mod(mantissa, 10000000000000000000)) { mantissa := div(mantissa, 10000000000000000000) exponent := add(exponent, 19) } if iszero(mod(mantissa, 1000000000000)) { mantissa := div(mantissa, 1000000000000) exponent := add(exponent, 12) } if iszero(mod(mantissa, 1000000)) { mantissa := div(mantissa, 1000000) exponent := add(exponent, 6) } if iszero(mod(mantissa, 10000)) { mantissa := div(mantissa, 10000) exponent := add(exponent, 4) } if iszero(mod(mantissa, 100)) { mantissa := div(mantissa, 100) exponent := add(exponent, 2) } if iszero(mod(mantissa, 10)) { mantissa := div(mantissa, 10) exponent := add(exponent, 1) } } } } /// @dev Convenience function for packing `x` into a smaller number using `sci`. /// The `mantissa` will be in bits [7..255] (the upper 249 bits). /// The `exponent` will be in bits [0..6] (the lower 7 bits). /// Use `SafeCastLib` to safely ensure that the `packed` number is small /// enough to fit in the desired unsigned integer type: /// ``` /// uint32 packed = SafeCastLib.toUint32(FixedPointMathLib.packSci(777 ether)); /// ``` function packSci(uint256 x) internal pure returns (uint256 packed) { (x, packed) = sci(x); // Reuse for `mantissa` and `exponent`. /// @solidity memory-safe-assembly assembly { if shr(249, x) { mstore(0x00, 0xce30380c) // `MantissaOverflow()`. revert(0x1c, 0x04) } packed := or(shl(7, x), packed) } } /// @dev Convenience function for unpacking a packed number from `packSci`. function unpackSci(uint256 packed) internal pure returns (uint256 unpacked) { unchecked { unpacked = (packed >> 7) * 10 ** (packed & 0x7f); } } /// @dev Returns the average of `x` and `y`. Rounds towards zero. function avg(uint256 x, uint256 y) internal pure returns (uint256 z) { unchecked { z = (x & y) + ((x ^ y) >> 1); } } /// @dev Returns the average of `x` and `y`. Rounds towards negative infinity. function avg(int256 x, int256 y) internal pure returns (int256 z) { unchecked { z = (x >> 1) + (y >> 1) + (x & y & 1); } } /// @dev Returns the absolute value of `x`. function abs(int256 x) internal pure returns (uint256 z) { unchecked { z = (uint256(x) + uint256(x >> 255)) ^ uint256(x >> 255); } } /// @dev Returns the absolute distance between `x` and `y`. function dist(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := add(xor(sub(0, gt(x, y)), sub(y, x)), gt(x, y)) } } /// @dev Returns the absolute distance between `x` and `y`. function dist(int256 x, int256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := add(xor(sub(0, sgt(x, y)), sub(y, x)), sgt(x, y)) } } /// @dev Returns the minimum of `x` and `y`. function min(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), lt(y, x))) } } /// @dev Returns the minimum of `x` and `y`. function min(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), slt(y, x))) } } /// @dev Returns the maximum of `x` and `y`. function max(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), gt(y, x))) } } /// @dev Returns the maximum of `x` and `y`. function max(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), sgt(y, x))) } } /// @dev Returns `x`, bounded to `minValue` and `maxValue`. function clamp(uint256 x, uint256 minValue, uint256 maxValue) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, minValue), gt(minValue, x))) z := xor(z, mul(xor(z, maxValue), lt(maxValue, z))) } } /// @dev Returns `x`, bounded to `minValue` and `maxValue`. function clamp(int256 x, int256 minValue, int256 maxValue) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, minValue), sgt(minValue, x))) z := xor(z, mul(xor(z, maxValue), slt(maxValue, z))) } } /// @dev Returns greatest common divisor of `x` and `y`. function gcd(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { for { z := x } y {} { let t := y y := mod(z, y) z := t } } } /// @dev Returns `a + (b - a) * (t - begin) / (end - begin)`, /// with `t` clamped between `begin` and `end` (inclusive). /// Agnostic to the order of (`a`, `b`) and (`end`, `begin`). /// If `begins == end`, returns `t <= begin ? a : b`. function lerp(uint256 a, uint256 b, uint256 t, uint256 begin, uint256 end) internal pure returns (uint256) { if (begin > end) (t, begin, end) = (~t, ~begin, ~end); if (t <= begin) return a; if (t >= end) return b; unchecked { if (b >= a) return a + fullMulDiv(b - a, t - begin, end - begin); return a - fullMulDiv(a - b, t - begin, end - begin); } } /// @dev Returns `a + (b - a) * (t - begin) / (end - begin)`. /// with `t` clamped between `begin` and `end` (inclusive). /// Agnostic to the order of (`a`, `b`) and (`end`, `begin`). /// If `begins == end`, returns `t <= begin ? a : b`. function lerp(int256 a, int256 b, int256 t, int256 begin, int256 end) internal pure returns (int256) { if (begin > end) (t, begin, end) = (~t, ~begin, ~end); if (t <= begin) return a; if (t >= end) return b; // forgefmt: disable-next-item unchecked { if (b >= a) return int256(uint256(a) + fullMulDiv(uint256(b - a), uint256(t - begin), uint256(end - begin))); return int256(uint256(a) - fullMulDiv(uint256(a - b), uint256(t - begin), uint256(end - begin))); } } /// @dev Returns if `x` is an even number. Some people may need this. function isEven(uint256 x) internal pure returns (bool) { return x & uint256(1) == uint256(0); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* RAW NUMBER OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns `x + y`, without checking for overflow. function rawAdd(uint256 x, uint256 y) internal pure returns (uint256 z) { unchecked { z = x + y; } } /// @dev Returns `x + y`, without checking for overflow. function rawAdd(int256 x, int256 y) internal pure returns (int256 z) { unchecked { z = x + y; } } /// @dev Returns `x - y`, without checking for underflow. function rawSub(uint256 x, uint256 y) internal pure returns (uint256 z) { unchecked { z = x - y; } } /// @dev Returns `x - y`, without checking for underflow. function rawSub(int256 x, int256 y) internal pure returns (int256 z) { unchecked { z = x - y; } } /// @dev Returns `x * y`, without checking for overflow. function rawMul(uint256 x, uint256 y) internal pure returns (uint256 z) { unchecked { z = x * y; } } /// @dev Returns `x * y`, without checking for overflow. function rawMul(int256 x, int256 y) internal pure returns (int256 z) { unchecked { z = x * y; } } /// @dev Returns `x / y`, returning 0 if `y` is zero. function rawDiv(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := div(x, y) } } /// @dev Returns `x / y`, returning 0 if `y` is zero. function rawSDiv(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := sdiv(x, y) } } /// @dev Returns `x % y`, returning 0 if `y` is zero. function rawMod(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mod(x, y) } } /// @dev Returns `x % y`, returning 0 if `y` is zero. function rawSMod(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := smod(x, y) } } /// @dev Returns `(x + y) % d`, return 0 if `d` if zero. function rawAddMod(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := addmod(x, y, d) } } /// @dev Returns `(x * y) % d`, return 0 if `d` if zero. function rawMulMod(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mulmod(x, y, d) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; abstract contract SystemEpoch { uint256 public constant EPOCH = 7 days; }
//// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; interface IBribe { function _deposit(uint256 amount, uint256 tokenId) external; function _withdraw(uint256 amount, uint256 tokenId) external; function getRewardForOwner(uint256 tokenId, address[] memory tokens) external; function notifyRewardAmount(address token, uint256 amount) external; function left(address token) external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; interface ICurveGauge { function deposit(uint256 _amount) external; function withdraw(uint256 _amount) external; function claim_rewards(address account, address receiver) external; function set_rewards_receiver(address receiver) external; }
//// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; interface IGauge { function notifyRewardAmount(address token, uint256 amount) external; function getReward(address account, address[] memory tokens) external; function left(address token) external view returns (uint256); function isForPair() external view returns (bool); }
//// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; interface IVoter { function _ve() external view returns (address); function governor() external view returns (address); function emergencyCouncil() external view returns (address); function attachTokenToGauge(uint256 _tokenId, address account) external; function detachTokenFromGauge(uint256 _tokenId, address account) external; function emitDeposit(uint256 _tokenId, address account, uint256 amount) external; function emitWithdraw(uint256 _tokenId, address account, uint256 amount) external; function isWhitelisted(address token) external view returns (bool); function notifyRewardAmount(uint256 amount) external; function distribute(address _gauge) external; }
//// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; interface IVotingEscrow { struct Point { int128 bias; int128 slope; // # -dweight / dt uint256 ts; uint256 blk; // block } struct LockedBalance { int128 amount; uint256 end; bool perpetuallyLocked; } function token() external view returns (address); function team() external returns (address); function epoch() external view returns (uint256); function point_history(uint256 loc) external view returns (Point memory); function user_point_history(uint256 tokenId, uint256 loc) external view returns (Point memory); function user_point_epoch(uint256 tokenId) external view returns (uint256); function ownerOf(uint256) external view returns (address); function isApprovedOrOwner(address, uint256) external view returns (bool); function transferFrom(address, address, uint256) external; function voting(uint256 tokenId) external; function abstain(uint256 tokenId) external; function attach(uint256 tokenId) external; function detach(uint256 tokenId) external; function checkpoint() external; function deposit_for(uint256 tokenId, uint256 value) external; function create_lock_for(uint256, uint256, address) external returns (uint256); function balanceOfNFT(uint256) external view returns (uint256); function totalSupply() external view returns (uint256); function locked(uint256 id) external view returns (LockedBalance memory); }
{ "evmVersion": "cancun", "libraries": {}, "metadata": { "appendCBOR": true, "bytecodeHash": "ipfs", "useLiteralContent": false }, "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "remappings": [ "@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/", "@openzeppelin/contracts-upgradeable/=node_modules/@openzeppelin/contracts-upgradeable/", "solady/=node_modules/solady/src/", "forge-std/=node_modules/forge-std/src/" ], "viaIR": true }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_stake","type":"address"},{"internalType":"address","name":"_staking","type":"address"},{"internalType":"address","name":"_internal_bribe","type":"address"},{"internalType":"address","name":"_external_bribe","type":"address"},{"internalType":"address","name":"__ve","type":"address"},{"internalType":"address","name":"_voter","type":"address"},{"internalType":"bool","name":"_forPair","type":"bool"},{"internalType":"address[]","name":"_allowedRewardTokens","type":"address[]"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"claimed0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"claimed1","type":"uint256"}],"name":"ClaimFees","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"reward","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ClaimRewards","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"reward","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"NotifyReward","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"EPOCH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_ve","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"maxRuns","type":"uint256"}],"name":"batchRewardPerToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"maxRuns","type":"uint256"}],"name":"batchUpdateRewardPerToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"checkpoints","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"balanceOf","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"depositAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"derivedBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"derivedBalances","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"derivedSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"account","type":"address"}],"name":"earned","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newStaking","type":"address"},{"internalType":"address","name":"_rewardsReceiver","type":"address"}],"name":"enableStaking","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"external_bribe","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getPriorBalanceIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getPriorRewardPerToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getPriorSupplyIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address[]","name":"tokens","type":"address[]"}],"name":"getReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"internal_bribe","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isForPair","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isReward","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isStakingReward","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"lastEarn","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"lastTimeRewardApplicable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"lastUpdateTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"left","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"notifyRewardAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"numCheckpoints","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"periodFinish","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"rewardPerToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"rewardPerTokenCheckpoints","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"rewardPerToken","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rewardPerTokenNumCheckpoints","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rewardPerTokenStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rewardRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rewards","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardsListLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_rewardsReceiver","type":"address"}],"name":"setRewardsReceiver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stake","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"staking","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"stakingRewards","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"supplyCheckpoints","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"supply","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"supplyNumCheckpoints","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"i","type":"uint256"},{"internalType":"address","name":"oldToken","type":"address"},{"internalType":"address","name":"newToken","type":"address"}],"name":"swapOutRewardToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"tokenIds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"userRewardPerTokenStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"voter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"withdrawToken","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
6101208060405234610387576137f3803803809161001d82856103dd565b83398101610100828203126103875761003582610400565b61004160208401610400565b9261004e60408201610400565b9161005b60608301610400565b61006760808401610400565b9561007460a08501610400565b9260c0850151948515158096036103875760e0810151906001600160401b03821161038757019680601f89011215610387578751976001600160401b038911610210578860051b90604051996100cd602084018c6103dd565b8a526020808b019282010192831161038757602001905b8282106103c5575050506001601f5560805260018060a01b0316938460018060a01b0319600c541617600c5560c05260e0528460a0526101005260ff8019600254169116176002555f5b8251811015610224576001600160a01b036101498285610414565b5116610158575b60010161012e565b6001600160a01b0361016a8285610414565b51165f908152601760205260409020805460ff191660011790556001600160a01b036101968285610414565b511690600d549168010000000000000000831015610210576001830180600d558310156101fc57600d5f527fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb590920180546001600160a01b031916909217909155610150565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52604160045260245ffd5b5082816102f5575b6040516133ca908161042982396080518181816102bb015281816106af01528181610b4401528181610cbf0152818161171401528181611d57015261254f015260a051818181610739015281816112fd015281816113e801528181611b5a01528181611c860152612905015260c05181611453015260e05181611f73015261010051818181610309015281816103cf015281816107ff015281816108ca015281816110af0152818161167c015281816117f401528181611a2a0152818161259c01526126640152f35b6040516342f9577960e11b815290602090829060049082905f906001600160a01b03165af190811561037c575f9161038b575b50813b1561038757604051635efcc08b60e11b81526001600160a01b039091166004820152905f908290602490829084905af1801561037c5761036c575b8061022c565b5f610376916103dd565b5f610366565b6040513d5f823e3d90fd5b5f80fd5b90506020813d6020116103bd575b816103a6602093836103dd565b81010312610387576103b790610400565b82610328565b3d9150610399565b602080916103d284610400565b8152019101906100e4565b601f909101601f19168101906001600160401b0382119082101761021057604052565b51906001600160a01b038216820361038757565b80518210156101fc5760209160051b01019056fe6080806040526004361015610012575f80fd5b5f905f3560e01c90816301316ddf14611fa25750806303fbf83a14611f5e5780630cdfebfa14611f11578063115c6f3914611eea57806318160ddd14611ecd578063211dc32d14611ea157806321cc096814611c4a578063221ca18c14611c115780632619582614611b295780632ce9aead14611af05780632e1a7d4d14611ad35780632f85074a14611a9457806331279d3d146117435780633a4b66f1146116fe5780633ca068b6146116ab57806346c96aac146116665780634cf088d91461163d5780634d5ce038146115fe578063597a8d6f146115c65780635a45d052146115a0578063638634ee1461156157806363fb415b1461152857806368fcee1a146114da5780636fcfff45146114a157806370a0823114610ab057806376f4be3614611482578063770f85711461143d578063853828b6146114175780638dd598fb146113d25780639418f939146112b257806399bcc0521461128e5780639ce43f9014611255578063a0dc275814611237578063a495e5b5146111e4578063aa479652146111ab578063b66503cf14610c84578063c6f678bd14610b19578063d294f09314610ae9578063d35e254414610ab0578063d7da4bb014610a93578063da09d19d14610a5a578063e2bbb1581461067e578063e57482131461065b578063e68863961461063d578063e8111a121461061f578063f1229777146105f3578063f301af42146105af578063f7412baf1461057b578063fc97a30314610542578063fd3140981461050e5763fdb483c71461024f575f80fd5b3461050b5761025d3661206b565b906001601f5403610488576002601f55816102766132be565b61028282600a546120ad565b600a55338452600b6020526040842061029c8382546120ad565b9055600c5484906001600160a01b0316806104c4575b50506102df82337f0000000000000000000000000000000000000000000000000000000000000000612eb8565b156104b05733835260096020526040832054820361048857338352600960205260408320839055827f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b156104975760405163411b1f7760e01b8152600481018590523360248201529082908290604490829084905af1801561048c5761049b575b50505b3383526001602052610385604084205484546120ad565b8355338352600b6020526103ac604084205433855260016020528060408620558454612229565b835533835260016020526103c4604084205433612f4b565b6103cc61301b565b827f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b1561049757604051633aa53b9160e21b815260048101859052336024820152604481018490529082908290606490829084905af1801561048c57610473575b505060405191825260208201527ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b56860403392a26001601f5580f35b8161047d91612049565b61048857825f610438565b8280fd5b6040513d84823e3d90fd5b5080fd5b816104a591612049565b61048857825f61036b565b33835260096020526040832054915061036e565b803b1561049757818091602460405180948193632e1a7d4d60e01b83528960048401525af1801561048c57156102b257816104fe91612049565b61050957835f6102b2565b835b80fd5b503461050b57604036600319011261050b57604061053661052d611fed565b60243590612a58565b82519182526020820152f35b503461050b57602036600319011261050b576020906040906001600160a01b0361056a611fed565b168152600983522054604051908152f35b503461050b57602036600319011261050b57604080916004358152601b602052206001815491015482519182526020820152f35b503461050b57602036600319011261050b5760043590600d5482101561050b5760206105da83612081565b905460405160039290921b1c6001600160a01b03168152f35b503461050b57602036600319011261050b576020610617610612611fed565b6129a9565b604051908152f35b503461050b578060031936011261050b576020601c54604051908152f35b503461050b578060031936011261050b576020600d54604051908152f35b503461050b578060031936011261050b57602060ff600254166040519015158152f35b503461050b5761068d3661206b565b906001601f5403610488576002601f55818115610509576106ac6132be565b837f00000000000000000000000000000000000000000000000000000000000000006106da8430338461326e565b600c546001600160a01b03169081610996575b5050506106fc82600a54612229565b600a55338452600b60205260408420610716838254612229565b905515610982576040516331a9108f60e11b8152600481018390526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610977578491610948575b50336001600160a01b03909116036104885733835260096020526040832054156108b8575b338352600960205281604084205403610488575b33835260016020526107c1604084205484546120ad565b8355338352600b6020526107f4604084205433855260016020528060408620556107ec818654612229565b855533612f4b565b6107fc61301b565b827f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b156104975760405163530e389d60e11b815260048101859052336024820152604481018490529082908290606490829084905af1801561048c576108a3575b505060405191825260208201527f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a1560403392a26001601f5580f35b816108ad91612049565b61048857825f610868565b338352600960205260408320829055827f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b156104975760405163698473e360e01b8152600481018590523360248201529082908290604490829084905af1801561048c57610933575b5050610796565b8161093d91612049565b61048857825f61092c565b61096a915060203d602011610970575b6109628183612049565b810190612429565b5f610771565b503d610958565b6040513d86823e3d90fd5b3383526009602052604083205491506107aa565b60405163095ea7b360e01b81526001600160a01b038381166004830152602482018790529091602091839160449183918891165af18015610a4f57610a22575b50803b156104975781809160246040518094819363b6b55f2560e01b83528960048401525af1801561048c57610a0d575b806106ed565b81610a1791612049565b61050957835f610a07565b610a439060203d602011610a48575b610a3b8183612049565b8101906124c5565b6109d6565b503d610a31565b6040513d85823e3d90fd5b503461050b57602036600319011261050b576020906040906001600160a01b03610a82611fed565b168152600483522054604051908152f35b503461050b578060031936011261050b5760209054604051908152f35b503461050b57602036600319011261050b576020906040906001600160a01b03610ad8611fed565b168152600b83522054604051908152f35b503461050b578060031936011261050b576001601f540361050b576002601f55610b116128ef565b6001601f5580f35b503461050b57602036600319011261050b576040516370a0823160e01b8152336004828101919091527f0000000000000000000000000000000000000000000000000000000000000000919035836001600160a01b038416602084602481845afa93841561048c578294610c49575b506001601f5403610497576002601f55829484156104885784610bb691610bad6132be565b3090339061326e565b600c546001600160a01b03169081610bd7575050506106fc82600a54612229565b60405163095ea7b360e01b81526001600160a01b038316600482015260248101869052906020908290604490829087905af18015610a4f57610a225750803b156104975781809160246040518094819363b6b55f2560e01b83528960048401525af1801561048c57610a0d57806106ed565b915092506020813d602011610c7c575b81610c6660209383612049565b81010312610c7857849051925f610b88565b5f80fd5b3d9150610c59565b503461050b57604036600319011261050b57610c9e611fed565b6024356001601f5403610488576002601f556001600160a01b0382811692907f000000000000000000000000000000000000000000000000000000000000000016831461050957811561050957828452601760205260ff60408520541615611093575b8284526003602052604084205415610fa0575b610d1d81612bb8565b848652600660205260408620908587526005602052604087205555828452600460205260408420544210155f14610f3b57610d5a8230338461326e565b828452600360205262093a80820460408520555b8284526003602052604084205415610509576040516370a0823160e01b8152306004820152602081602481875afa908115610f30578591610efe575b50838552600360205262093a806040862054910410610eb95762093a804201804211610ea55783855260046020526040852055828452601760205260ff60408520541615610e28575b506040519081527ff70d5c697de7ea828df48e5c4573cb2194c659f1901f70110c52b066dcf5082660203392a36001601f5580f35b828452601760205260408420805460ff19166001179055600d5468010000000000000000811015610e915790610e67826001610e8b9401600d55612081565b81546001600160a01b0393841660039290921b91821b9390911b1916919091179055565b5f610df3565b634e487b7160e01b85526041600452602485fd5b634e487b7160e01b85526011600452602485fd5b60405162461bcd60e51b815260206004820152601860248201527f50726f76696465642072657761726420746f6f206869676800000000000000006044820152606490fd5b90506020813d602011610f28575b81610f1960209383612049565b81010312610c7857515f610daa565b3d9150610f0c565b6040513d87823e3d90fd5b8284526004602052610f67610f544260408720546120ad565b8486526003602052604086205490612236565b80831115610f9c57610f8962093a8091610f838530338761326e565b84612229565b0483855260036020526040852055610d6e565b8480fd5b828452601e602052604084205480151580611056575b15610ffa57838552601d60205260408520905f198101908111610fe6578552602052836001604082200155610d14565b634e487b7160e01b86526011600452602486fd5b61103960405161100981612019565b428152866020820152858752601d6020526040872083885260205260408720906020600191805184550151910155565b60018101809111610ea557838552601e6020526040852055610d14565b50838552601d602052604085205f19820182811161107f57865260205242604086205414610fb6565b634e487b7160e01b87526011600452602487fd5b604051633af32abf60e01b8152600481018490526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610f3057859161118c575b501561113c576010600d5410610d015760405162461bcd60e51b815260206004820152601760248201527f746f6f206d616e79207265776172647320746f6b656e730000000000000000006044820152606490fd5b60405162461bcd60e51b815260206004820152602260248201527f7265776172647320746f6b656e73206d7573742062652077686974656c697374604482015261195960f21b6064820152608490fd5b6111a5915060203d602011610a4857610a3b8183612049565b5f6110e7565b503461050b57602036600319011261050b576020906040906001600160a01b036111d3611fed565b168152601e83522054604051908152f35b503461050b57604036600319011261050b576040611200611fed565b91611209612003565b9260018060a01b031681526007602052209060018060a01b03165f52602052602060405f2054604051908152f35b503461050b578060031936011261050b57602060405162093a808152f35b503461050b57602036600319011261050b576020906040906001600160a01b0361127d611fed565b168152600683522054604051908152f35b503461050b57602036600319011261050b5760206106176112ad611fed565b61289f565b503461050b57606036600319011261050b576004356112cf612003565b6044356001600160a01b03811692909190838303610f9c576040516342f9577960e11b8152602081600481897f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af180156113c7576113499187916113a8575b506001600160a01b03163314612448565b61135281612081565b90546001600160a01b039384169360039290921b1c16829003610f9c576113a593610e6792865260176020526040862060ff1981541690558552601760205260408520600160ff19825416179055612081565b80f35b6113c1915060203d602011610970576109628183612049565b5f611338565b6040513d88823e3d90fd5b503461050b578060031936011261050b576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b503461050b578060031936011261050b57338152600b6020526113a560408220546124dd565b503461050b578060031936011261050b576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b503461050b57602036600319011261050b5760206106176004356127b3565b503461050b57602036600319011261050b576020906040906001600160a01b036114c9611fed565b168152601a83522054604051908152f35b503461050b57604036600319011261050b576114f4611fed565b61150060243582612d4f565b909160018060a01b031690818452600660205260408420918452600560205260408420555580f35b503461050b57602036600319011261050b576020906040906001600160a01b03611550611fed565b168152600183522054604051908152f35b503461050b57602036600319011261050b576020610617611580611fed565b60018060a01b03165f52600460205260405f205442811090421802421890565b503461050b57604036600319011261050b576115ba611fed565b611500602435826130b1565b503461050b57602036600319011261050b57600435600881101561049757600e01546040516001600160a01b03909116815260209150f35b503461050b57602036600319011261050b5760209060ff906040906001600160a01b03611629611fed565b168152601784522054166040519015158152f35b503461050b578060031936011261050b57600c546040516001600160a01b039091168152602090f35b503461050b578060031936011261050b576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b503461050b57604036600319011261050b5760406116c7611fed565b916116d0612003565b9260018060a01b031681526008602052209060018060a01b03165f52602052602060405f2054604051908152f35b503461050b578060031936011261050b576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b503461050b57604036600319011261050b5761175d611fed565b60243567ffffffffffffffff811161048857366023820112156104885780600401359067ffffffffffffffff8211611a80578160051b90604051926117a56020840185612049565b83526024602084019282010190368211611a7c57602401915b818310611a58575050506001601f5403610488576001600160a01b038216903382148015611a26575b15610509576001601f55837f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b15610497578180916024604051809481936363453ae160e01b83523060048401525af1801561048c57611a11575b50506002601f55835b81518110156119b15760019061187d6001600160a01b03611876838661279f565b5116612bb8565b838060a01b0361188d848761279f565b5116885260066020526040882090848060a01b036118ab858861279f565b5116895260056020526040892055556118d585838060a01b036118ce848761279f565b5116612249565b828060a01b036118e5838661279f565b51168752600760205260408720855f5260205260405f20429055828060a01b0361190f838661279f565b5116875260066020526040872054838060a01b0361192d848761279f565b51168852600860205260408820865f5260205260405f205580611990575b828060a01b0361195b838661279f565b5116906040519081527f9aa05b3d70a9e3e2f004f039648839560576334fb45c81f91b6db03ad9e2efc960203392a301611855565b6119ac8187858060a01b036119a5868961279f565b5116612eb8565b61194b565b84611a09858580845260016020526119ce604085205485546120ad565b8455808452600b6020526119f5604085205482865260016020528060408720558554612229565b845583526001602052604083205490612f4b565b610b1161301b565b81611a1b91612049565b61050957835f61184c565b50337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316146117e7565b82356001600160a01b0381168103611a78578152602092830192016117be565b8680fd5b8580fd5b634e487b7160e01b84526041600452602484fd5b503461050b57602036600319011261050b5760209060ff906040906001600160a01b03611abf611fed565b168152601884522054166040519015158152f35b503461050b57602036600319011261050b576113a56004356124dd565b503461050b57602036600319011261050b576020906040906001600160a01b03611b18611fed565b168152600583522054604051908152f35b503461050b57602036600319011261050b5780611b44611fed565b6040516342f9577960e11b8152602081600481867f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af18015610a4f57611ba59184916113a857506001600160a01b03163314612448565b600c546001600160a01b031690611bbd821515612480565b813b15611c0d57604051635efcc08b60e11b81526001600160a01b0390911660048201529082908290602490829084905af1801561048c57611bfc5750f35b81611c0691612049565b61050b5780f35b5050fd5b503461050b57602036600319011261050b576020906040906001600160a01b03611c39611fed565b168152600383522054604051908152f35b5034610c78576040366003190112610c7857611c64611fed565b90611c6d612003565b6040516342f9577960e11b81529092906020816004815f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af18015611e9657611cd1915f916113a857506001600160a01b03163314612448565b600c5490611ce86001600160a01b03831615612480565b6001600160a01b0381166001600160a01b0319929092168217600c55813b15610c7857604051635efcc08b60e11b81526001600160a01b0390941660048501525f8460248183865af18015611e9657611e80575b6040516370a0823160e01b81523060048201529293508392907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316602083602481845afa928315610f30578593611e49575b5082611da0578480f35b60405163095ea7b360e01b81526001600160a01b03929092166004830152602482018390526020908290604490829088905af1801561097757611e2c575b50813b15611c0d57829160248392604051948593849263b6b55f2560e01b845260048401525af1801561048c57611e17575b8080808480f35b81611e2191612049565b61050b57805f611e10565b611e449060203d602011610a4857610a3b8183612049565b611dde565b945091506020843d602011611e78575b81611e6660209383612049565b81010312610c7857849351915f611d96565b3d9150611e59565b9150915f611e8d91612049565b5f908290611d3c565b6040513d5f823e3d90fd5b34610c78576040366003190112610c78576020610617611ebf611fed565b611ec7612003565b90612249565b34610c78575f366003190112610c78576020600a54604051908152f35b34610c78576040366003190112610c78576020610617611f08611fed565b6024359061210a565b34610c78576040366003190112610c78576001600160a01b03611f32611fed565b165f52601960205260405f206024355f526020526040805f206001815491015482519182526020820152f35b34610c78575f366003190112610c78576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b34610c78576040366003190112610c78576040906001600160a01b03611fc6611fed565b165f52601d602052815f206024355f52602052815f20600181549101549082526020820152f35b600435906001600160a01b0382168203610c7857565b602435906001600160a01b0382168203610c7857565b6040810190811067ffffffffffffffff82111761203557604052565b634e487b7160e01b5f52604160045260245ffd5b90601f8019910116810190811067ffffffffffffffff82111761203557604052565b6040906003190112610c78576004359060243590565b600d5481101561209957600d5f5260205f2001905f90565b634e487b7160e01b5f52603260045260245ffd5b919082039182116120ba57565b634e487b7160e01b5f52601160045260245ffd5b81156120d8570490565b634e487b7160e01b5f52601260045260245ffd5b906040516120f981612019565b602060018294805484520154910152565b6001600160a01b03165f818152601a602052604090205491821561221457815f52601960205260405f20925f19810190811193846120ba57815f526020528160405f2054111561220d57825f52601960205260405f205f80526020528160405f205411612205575f936120ba5791905b8383116121875750505090565b61219d61219485856120ad565b60011c846120ad565b93825f52601960205260405f20855f526020526121bc60405f206120ec565b518281036121cc57505050505090565b918093949592105f146121e35750925b919061217a565b93505f198101908111156121dc57634e487b7160e01b5f52601160045260245ffd5b505050505f90565b9250505090565b5050505f90565b5f1981146120ba5760010190565b919082018092116120ba57565b818102929181159184041417156120ba57565b6001600160a01b038181165f81815260076020908152604080832094871680845294825280832054848452601d8352818420848052835281842054868552601a90935292205493959293909291901561241f5782816122ae941190821802189061210a565b92805f52601a60205260405f20545f198101908082116120ba575f9582612357575b505092612347670de0b6b3a76400009383612354979661234d955f52601960205260405f20905f5260205261230760405f206120ec565b906123226020612318845188612a58565b50930151956129a9565b925f52600860205260405f20905f5260205260405f20548181119082180218906120ad565b90612236565b0490612229565b90565b9692969391906001190181811196875b6120ba5781861161240457885f52601960205260405f20865f5260205261239060405f206120ec565b895f52601960205260405f209160018801928389116120ba5761234d6123f793670de0b6b3a7640000926123fd965f526020526123478c60206123ed6123d860405f206120ec565b926123e4865182612a58565b50935190612a58565b50930151926120ad565b9561221b565b9487612367565b93979396509193509050612347670de0b6b3a76400006122d0565b5050505050505f90565b90816020910312610c7857516001600160a01b0381168103610c785790565b1561244f57565b60405162461bcd60e51b81526020600482015260096024820152686f6e6c79207465616d60b81b6044820152606490fd5b1561248757565b60405162461bcd60e51b81526020600482015260166024820152757374616b696e6720616c72656164792065786973747360501b6044820152606490fd5b90816020910312610c7857518015158103610c785790565b5f905f91335f52600b60205260405f2054821461278a575b6001601f5403610c78576002601f558261250d6132be565b61251983600a546120ad565b600a55335f52600b60205260405f206125338482546120ad565b9055600c546001600160a01b031680612745575b5061257383337f0000000000000000000000000000000000000000000000000000000000000000612eb8565b156127315733815260096020526040812054830361050b573381526009602052604081208190557f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b156104975760405163411b1f7760e01b8152600481018590523360248201529082908290604490829084905af1801561048c5790829161271c575b50505b338152600160205261261b604082205482546120ad565b8155338152600b602052612642604082205433835260016020528060408420558254612229565b8155338152600160205261265a604082205433612f4b565b61266261301b565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b1561049757604051633aa53b9160e21b815260048101859052336024820152604481018490529082908290606490829084905af1801561048c57612707575b505060405191825260208201527ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b56860403392a26001601f55565b612712828092612049565b61050b57806126cd565b8161272691612049565b61050b57805f612601565b338152600960205260408120549250612604565b803b15610c78575f8091602460405180948193632e1a7d4d60e01b83528960048401525af18015611e965715612547576127829192505f90612049565b5f905f612547565b9150335f52600960205260405f2054916124f5565b80518210156120995760209160051b010190565b601c54908115612899575f19820191821191826120ba57805f52601b6020528160405f20541115612893575f8052601b6020527f584f46c60af19681376031579adb04a2416e54ee5505351c2a8435e3766026ea548210612214575f926120ba57905b82821161282257505090565b61283861282f84846120ad565b60011c836120ad565b92835f52601b60205261284d60405f206120ec565b5182810361285c575050505090565b9180939492105f146128715750915b90612816565b92505f1981019081111561286b57634e487b7160e01b5f52601160045260245ffd5b91505090565b50505f90565b6001600160a01b03165f818152600460205260409020544210156128ea5780612354915f5260046020526128d74260405f20546120ad565b905f52600360205260405f205490612236565b505f90565b6040516342f9577960e11b81526020816004815f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af18015611e9657612950915f916113a857506001600160a01b03163314612448565b600c546001600160a01b031680156129a657803b15610c78575f8091604460405180948193639faceb1b60e01b83523060048401528160248401525af18015611e965761299a5750565b5f6129a491612049565b565b50565b5f54908115612a3c576001600160a01b03165f81815260066020908152604080832054600480845282852054600585529290942054939092529092612a089290916128d7918082188183100218904281811191811891909102186120ad565b670de0b6b3a7640000810290808204670de0b6b3a764000014901517156120ba5761235492612a36916120ce565b90612229565b6001600160a01b03165f90815260066020526040902054919050565b6001600160a01b03165f818152601e60205260409020549092918115612bae57835f52601d60205260405f20915f19810190811192836120ba57815f526020528160405f20541115612b8657845f52601d60205260405f205f80526020528160405f205411612b7b575f926120ba57905b828211612af65750505f928352601d60209081526040808520928552919052909120600181015490549091565b612b0661282f84849795976120ad565b835f52601d60205260405f20815f52602052612b2460405f206120ec565b9586518381145f14612b40575050505050506020820151915190565b839495975092909192105f14612b595750915b90612ac9565b92505f19810190811115612b5357634e487b7160e01b5f52601160045260245ffd5b50505090505f905f90565b5f948552601d6020908152604080872092875291905290932060018101549054909350919050565b505090505f905f90565b9060018060a01b038216805f52600560205260405f205492815f52600660205260405f205491601c54908115612c36575f52600360205260405f205415612d4557612c02856127b3565b5f19820191908183116120ba5782612c9d575b50505f52601b602052612c2a60405f206120ec565b60208101908151612c3d575b5050509190565b8295612c939492612c8392612c6f612c8a9660018060a01b03165f52600460205260405f205442811090421802421890565b905191519180841184821802189089613314565b5090612229565b9283429161319d565b42915f8080612c36565b9491906001190181811195865b6120ba57818111612d3957805f52601b602052612cc960405f206120ec565b602081018051612ce5575b5050612cdf9061221b565b86612caa565b90919860018a0190818b116120ba57612cdf93612d2593612d1f935f52601b602052612d1360405f206120ec565b5191519051918a613314565b97612229565b95612d3181888861319d565b97905f612cd4565b50509093505f80612c15565b5050909150904290565b919060018060a01b038316805f52600560205260405f205493815f52600660205260405f205492601c54928315612e71575f52600360205260405f205415612e6657612d9a866127b3565b905f1984019384116120ba57838110908418028084189303612dbd575050509190565b5f19830192831194919290855b6120ba57818111612e5957805f52601b602052612de960405f206120ec565b602081018051612e05575b5050612dff9061221b565b85612dca565b9091976001890190818a116120ba57612dff93612e4593612e3f935f52601b602052612e3360405f206120ec565b51915190519189613314565b96612229565b94612e5181878761319d565b96905f612df4565b50509250505f8080612c36565b505050909150904290565b505050509190565b3d15612eb3573d9067ffffffffffffffff82116120355760405191612ea8601f8201601f191660200184612049565b82523d5f602084013e565b606090565b919091803b15610c785760405163a9059cbb60e01b602082019081526001600160a01b039490941660248201526044808201939093529182525f9283928390612f02606482612049565b51925af1612f0e612e79565b81612f1c575b5015610c7857565b8051801592508215612f31575b50505f612f14565b612f4492506020809183010191016124c5565b5f80612f29565b6001600160a01b03165f818152601a60205260409020549081151580612ff2575b15612f97575f52601960205260405f20905f1981019081116120ba575f52602052600160405f200155565b9091612fd99060405190612faa82612019565b4282526020820152825f52601960205260405f20845f5260205260405f20906020600191805184550151910155565b600182018092116120ba575f52601a60205260405f2055565b50805f52601960205260405f205f1983018381116120ba575f526020524260405f205414612f6c565b601c5480151580613092575b1561304b575f54905f1981019081116120ba575f52601b602052600160405f200155565b6130825f546040519061305d82612019565b4282526020820152825f52601b60205260405f20906020600191805184550151910155565b600181018091116120ba57601c55565b505f1981018181116120ba575f52601b6020524260405f205414613027565b919060018060a01b03831690815f52600560205260405f205493825f52600660205260405f205492601c54908115612e71575f52600360205260405f205415612e66576130fd866127b3565b925f1982019182116120ba578181109082180218915b828110613121575050509190565b805f52601b60205261313560405f206120ec565b60208101805161314a575b5050600101613113565b90919660018801908189116120ba5760019361318993613183935f52601b60205261317760405f206120ec565b51915190519187613314565b95612229565b9361319581868561319d565b95905f613140565b6001600160a01b03165f818152601e6020526040902054919282151580613245575b156131eb57505f52601d60205260405f20905f1981019081116120ba575f52602052600160405f200155565b61322c919293604051916131fe83612019565b82526020820152825f52601d60205260405f20845f5260205260405f20906020600191805184550151910155565b600182018092116120ba575f52601e60205260405f2055565b50815f52601d60205260405f205f1984018481116120ba575f526020528060405f2054146131bf565b90813b15610c78576040516323b872dd60e01b602082019081526001600160a01b0392831660248301529190931660448401526064808401949094529282525f9283928390612f02608482612049565b600d545f5b8181106132ce575050565b806132da600192612081565b838060a01b0391549060031b1c166132f181612bb8565b825f93929352600660205260405f20915f52600560205260405f205555016132c3565b6001600160a01b03165f818152600460205260409020548286188387110290921895946133659391926128d792808318928110929092029091188082188183100218908088189088110287186120ad565b90670de0b6b3a7640000820291808304670de0b6b3a764000014901517156120ba57613390916120ce565b919056fea264697066735822122045575e00b1ee184ccf22d57f3cba5c2cbc6989d7c0ca3050ed9db5fbce5e22ea64736f6c634300081c003300000000000000000000000070ac2feeb9ab4417591a97ad2607dd0e87bb3e330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ba8f46e97599a038c7c1b63f6e4c0357d65ab50a0000000000000000000000000c0c11d859dbd097cef8e965c691bcc20a64f68b000000000000000000000000db9a1bdc443dd11366b8a6dc8038144ecc4d4e23000000000000000000000000f3113e4f80c84935e576cfd75f4423e9b911908a0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000030000000000000000000000008ff0dd9f9c40a0d76ef1bcfaf5f98c1610c74bd8000000000000000000000000b8ce59fc3717ada4c02eadf9682a9e934f625ebb00000000000000000000000028245ab01298eaef7933bc90d35bd9dbca5c89db
Deployed Bytecode
0x6080806040526004361015610012575f80fd5b5f905f3560e01c90816301316ddf14611fa25750806303fbf83a14611f5e5780630cdfebfa14611f11578063115c6f3914611eea57806318160ddd14611ecd578063211dc32d14611ea157806321cc096814611c4a578063221ca18c14611c115780632619582614611b295780632ce9aead14611af05780632e1a7d4d14611ad35780632f85074a14611a9457806331279d3d146117435780633a4b66f1146116fe5780633ca068b6146116ab57806346c96aac146116665780634cf088d91461163d5780634d5ce038146115fe578063597a8d6f146115c65780635a45d052146115a0578063638634ee1461156157806363fb415b1461152857806368fcee1a146114da5780636fcfff45146114a157806370a0823114610ab057806376f4be3614611482578063770f85711461143d578063853828b6146114175780638dd598fb146113d25780639418f939146112b257806399bcc0521461128e5780639ce43f9014611255578063a0dc275814611237578063a495e5b5146111e4578063aa479652146111ab578063b66503cf14610c84578063c6f678bd14610b19578063d294f09314610ae9578063d35e254414610ab0578063d7da4bb014610a93578063da09d19d14610a5a578063e2bbb1581461067e578063e57482131461065b578063e68863961461063d578063e8111a121461061f578063f1229777146105f3578063f301af42146105af578063f7412baf1461057b578063fc97a30314610542578063fd3140981461050e5763fdb483c71461024f575f80fd5b3461050b5761025d3661206b565b906001601f5403610488576002601f55816102766132be565b61028282600a546120ad565b600a55338452600b6020526040842061029c8382546120ad565b9055600c5484906001600160a01b0316806104c4575b50506102df82337f00000000000000000000000070ac2feeb9ab4417591a97ad2607dd0e87bb3e33612eb8565b156104b05733835260096020526040832054820361048857338352600960205260408320839055827f000000000000000000000000f3113e4f80c84935e576cfd75f4423e9b911908a6001600160a01b0316803b156104975760405163411b1f7760e01b8152600481018590523360248201529082908290604490829084905af1801561048c5761049b575b50505b3383526001602052610385604084205484546120ad565b8355338352600b6020526103ac604084205433855260016020528060408620558454612229565b835533835260016020526103c4604084205433612f4b565b6103cc61301b565b827f000000000000000000000000f3113e4f80c84935e576cfd75f4423e9b911908a6001600160a01b0316803b1561049757604051633aa53b9160e21b815260048101859052336024820152604481018490529082908290606490829084905af1801561048c57610473575b505060405191825260208201527ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b56860403392a26001601f5580f35b8161047d91612049565b61048857825f610438565b8280fd5b6040513d84823e3d90fd5b5080fd5b816104a591612049565b61048857825f61036b565b33835260096020526040832054915061036e565b803b1561049757818091602460405180948193632e1a7d4d60e01b83528960048401525af1801561048c57156102b257816104fe91612049565b61050957835f6102b2565b835b80fd5b503461050b57604036600319011261050b57604061053661052d611fed565b60243590612a58565b82519182526020820152f35b503461050b57602036600319011261050b576020906040906001600160a01b0361056a611fed565b168152600983522054604051908152f35b503461050b57602036600319011261050b57604080916004358152601b602052206001815491015482519182526020820152f35b503461050b57602036600319011261050b5760043590600d5482101561050b5760206105da83612081565b905460405160039290921b1c6001600160a01b03168152f35b503461050b57602036600319011261050b576020610617610612611fed565b6129a9565b604051908152f35b503461050b578060031936011261050b576020601c54604051908152f35b503461050b578060031936011261050b576020600d54604051908152f35b503461050b578060031936011261050b57602060ff600254166040519015158152f35b503461050b5761068d3661206b565b906001601f5403610488576002601f55818115610509576106ac6132be565b837f00000000000000000000000070ac2feeb9ab4417591a97ad2607dd0e87bb3e336106da8430338461326e565b600c546001600160a01b03169081610996575b5050506106fc82600a54612229565b600a55338452600b60205260408420610716838254612229565b905515610982576040516331a9108f60e11b8152600481018390526020816024817f000000000000000000000000db9a1bdc443dd11366b8a6dc8038144ecc4d4e236001600160a01b03165afa908115610977578491610948575b50336001600160a01b03909116036104885733835260096020526040832054156108b8575b338352600960205281604084205403610488575b33835260016020526107c1604084205484546120ad565b8355338352600b6020526107f4604084205433855260016020528060408620556107ec818654612229565b855533612f4b565b6107fc61301b565b827f000000000000000000000000f3113e4f80c84935e576cfd75f4423e9b911908a6001600160a01b0316803b156104975760405163530e389d60e11b815260048101859052336024820152604481018490529082908290606490829084905af1801561048c576108a3575b505060405191825260208201527f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a1560403392a26001601f5580f35b816108ad91612049565b61048857825f610868565b338352600960205260408320829055827f000000000000000000000000f3113e4f80c84935e576cfd75f4423e9b911908a6001600160a01b0316803b156104975760405163698473e360e01b8152600481018590523360248201529082908290604490829084905af1801561048c57610933575b5050610796565b8161093d91612049565b61048857825f61092c565b61096a915060203d602011610970575b6109628183612049565b810190612429565b5f610771565b503d610958565b6040513d86823e3d90fd5b3383526009602052604083205491506107aa565b60405163095ea7b360e01b81526001600160a01b038381166004830152602482018790529091602091839160449183918891165af18015610a4f57610a22575b50803b156104975781809160246040518094819363b6b55f2560e01b83528960048401525af1801561048c57610a0d575b806106ed565b81610a1791612049565b61050957835f610a07565b610a439060203d602011610a48575b610a3b8183612049565b8101906124c5565b6109d6565b503d610a31565b6040513d85823e3d90fd5b503461050b57602036600319011261050b576020906040906001600160a01b03610a82611fed565b168152600483522054604051908152f35b503461050b578060031936011261050b5760209054604051908152f35b503461050b57602036600319011261050b576020906040906001600160a01b03610ad8611fed565b168152600b83522054604051908152f35b503461050b578060031936011261050b576001601f540361050b576002601f55610b116128ef565b6001601f5580f35b503461050b57602036600319011261050b576040516370a0823160e01b8152336004828101919091527f00000000000000000000000070ac2feeb9ab4417591a97ad2607dd0e87bb3e33919035836001600160a01b038416602084602481845afa93841561048c578294610c49575b506001601f5403610497576002601f55829484156104885784610bb691610bad6132be565b3090339061326e565b600c546001600160a01b03169081610bd7575050506106fc82600a54612229565b60405163095ea7b360e01b81526001600160a01b038316600482015260248101869052906020908290604490829087905af18015610a4f57610a225750803b156104975781809160246040518094819363b6b55f2560e01b83528960048401525af1801561048c57610a0d57806106ed565b915092506020813d602011610c7c575b81610c6660209383612049565b81010312610c7857849051925f610b88565b5f80fd5b3d9150610c59565b503461050b57604036600319011261050b57610c9e611fed565b6024356001601f5403610488576002601f556001600160a01b0382811692907f00000000000000000000000070ac2feeb9ab4417591a97ad2607dd0e87bb3e3316831461050957811561050957828452601760205260ff60408520541615611093575b8284526003602052604084205415610fa0575b610d1d81612bb8565b848652600660205260408620908587526005602052604087205555828452600460205260408420544210155f14610f3b57610d5a8230338461326e565b828452600360205262093a80820460408520555b8284526003602052604084205415610509576040516370a0823160e01b8152306004820152602081602481875afa908115610f30578591610efe575b50838552600360205262093a806040862054910410610eb95762093a804201804211610ea55783855260046020526040852055828452601760205260ff60408520541615610e28575b506040519081527ff70d5c697de7ea828df48e5c4573cb2194c659f1901f70110c52b066dcf5082660203392a36001601f5580f35b828452601760205260408420805460ff19166001179055600d5468010000000000000000811015610e915790610e67826001610e8b9401600d55612081565b81546001600160a01b0393841660039290921b91821b9390911b1916919091179055565b5f610df3565b634e487b7160e01b85526041600452602485fd5b634e487b7160e01b85526011600452602485fd5b60405162461bcd60e51b815260206004820152601860248201527f50726f76696465642072657761726420746f6f206869676800000000000000006044820152606490fd5b90506020813d602011610f28575b81610f1960209383612049565b81010312610c7857515f610daa565b3d9150610f0c565b6040513d87823e3d90fd5b8284526004602052610f67610f544260408720546120ad565b8486526003602052604086205490612236565b80831115610f9c57610f8962093a8091610f838530338761326e565b84612229565b0483855260036020526040852055610d6e565b8480fd5b828452601e602052604084205480151580611056575b15610ffa57838552601d60205260408520905f198101908111610fe6578552602052836001604082200155610d14565b634e487b7160e01b86526011600452602486fd5b61103960405161100981612019565b428152866020820152858752601d6020526040872083885260205260408720906020600191805184550151910155565b60018101809111610ea557838552601e6020526040852055610d14565b50838552601d602052604085205f19820182811161107f57865260205242604086205414610fb6565b634e487b7160e01b87526011600452602487fd5b604051633af32abf60e01b8152600481018490526020816024817f000000000000000000000000f3113e4f80c84935e576cfd75f4423e9b911908a6001600160a01b03165afa908115610f3057859161118c575b501561113c576010600d5410610d015760405162461bcd60e51b815260206004820152601760248201527f746f6f206d616e79207265776172647320746f6b656e730000000000000000006044820152606490fd5b60405162461bcd60e51b815260206004820152602260248201527f7265776172647320746f6b656e73206d7573742062652077686974656c697374604482015261195960f21b6064820152608490fd5b6111a5915060203d602011610a4857610a3b8183612049565b5f6110e7565b503461050b57602036600319011261050b576020906040906001600160a01b036111d3611fed565b168152601e83522054604051908152f35b503461050b57604036600319011261050b576040611200611fed565b91611209612003565b9260018060a01b031681526007602052209060018060a01b03165f52602052602060405f2054604051908152f35b503461050b578060031936011261050b57602060405162093a808152f35b503461050b57602036600319011261050b576020906040906001600160a01b0361127d611fed565b168152600683522054604051908152f35b503461050b57602036600319011261050b5760206106176112ad611fed565b61289f565b503461050b57606036600319011261050b576004356112cf612003565b6044356001600160a01b03811692909190838303610f9c576040516342f9577960e11b8152602081600481897f000000000000000000000000db9a1bdc443dd11366b8a6dc8038144ecc4d4e236001600160a01b03165af180156113c7576113499187916113a8575b506001600160a01b03163314612448565b61135281612081565b90546001600160a01b039384169360039290921b1c16829003610f9c576113a593610e6792865260176020526040862060ff1981541690558552601760205260408520600160ff19825416179055612081565b80f35b6113c1915060203d602011610970576109628183612049565b5f611338565b6040513d88823e3d90fd5b503461050b578060031936011261050b576040517f000000000000000000000000db9a1bdc443dd11366b8a6dc8038144ecc4d4e236001600160a01b03168152602090f35b503461050b578060031936011261050b57338152600b6020526113a560408220546124dd565b503461050b578060031936011261050b576040517f000000000000000000000000ba8f46e97599a038c7c1b63f6e4c0357d65ab50a6001600160a01b03168152602090f35b503461050b57602036600319011261050b5760206106176004356127b3565b503461050b57602036600319011261050b576020906040906001600160a01b036114c9611fed565b168152601a83522054604051908152f35b503461050b57604036600319011261050b576114f4611fed565b61150060243582612d4f565b909160018060a01b031690818452600660205260408420918452600560205260408420555580f35b503461050b57602036600319011261050b576020906040906001600160a01b03611550611fed565b168152600183522054604051908152f35b503461050b57602036600319011261050b576020610617611580611fed565b60018060a01b03165f52600460205260405f205442811090421802421890565b503461050b57604036600319011261050b576115ba611fed565b611500602435826130b1565b503461050b57602036600319011261050b57600435600881101561049757600e01546040516001600160a01b03909116815260209150f35b503461050b57602036600319011261050b5760209060ff906040906001600160a01b03611629611fed565b168152601784522054166040519015158152f35b503461050b578060031936011261050b57600c546040516001600160a01b039091168152602090f35b503461050b578060031936011261050b576040517f000000000000000000000000f3113e4f80c84935e576cfd75f4423e9b911908a6001600160a01b03168152602090f35b503461050b57604036600319011261050b5760406116c7611fed565b916116d0612003565b9260018060a01b031681526008602052209060018060a01b03165f52602052602060405f2054604051908152f35b503461050b578060031936011261050b576040517f00000000000000000000000070ac2feeb9ab4417591a97ad2607dd0e87bb3e336001600160a01b03168152602090f35b503461050b57604036600319011261050b5761175d611fed565b60243567ffffffffffffffff811161048857366023820112156104885780600401359067ffffffffffffffff8211611a80578160051b90604051926117a56020840185612049565b83526024602084019282010190368211611a7c57602401915b818310611a58575050506001601f5403610488576001600160a01b038216903382148015611a26575b15610509576001601f55837f000000000000000000000000f3113e4f80c84935e576cfd75f4423e9b911908a6001600160a01b0316803b15610497578180916024604051809481936363453ae160e01b83523060048401525af1801561048c57611a11575b50506002601f55835b81518110156119b15760019061187d6001600160a01b03611876838661279f565b5116612bb8565b838060a01b0361188d848761279f565b5116885260066020526040882090848060a01b036118ab858861279f565b5116895260056020526040892055556118d585838060a01b036118ce848761279f565b5116612249565b828060a01b036118e5838661279f565b51168752600760205260408720855f5260205260405f20429055828060a01b0361190f838661279f565b5116875260066020526040872054838060a01b0361192d848761279f565b51168852600860205260408820865f5260205260405f205580611990575b828060a01b0361195b838661279f565b5116906040519081527f9aa05b3d70a9e3e2f004f039648839560576334fb45c81f91b6db03ad9e2efc960203392a301611855565b6119ac8187858060a01b036119a5868961279f565b5116612eb8565b61194b565b84611a09858580845260016020526119ce604085205485546120ad565b8455808452600b6020526119f5604085205482865260016020528060408720558554612229565b845583526001602052604083205490612f4b565b610b1161301b565b81611a1b91612049565b61050957835f61184c565b50337f000000000000000000000000f3113e4f80c84935e576cfd75f4423e9b911908a6001600160a01b0316146117e7565b82356001600160a01b0381168103611a78578152602092830192016117be565b8680fd5b8580fd5b634e487b7160e01b84526041600452602484fd5b503461050b57602036600319011261050b5760209060ff906040906001600160a01b03611abf611fed565b168152601884522054166040519015158152f35b503461050b57602036600319011261050b576113a56004356124dd565b503461050b57602036600319011261050b576020906040906001600160a01b03611b18611fed565b168152600583522054604051908152f35b503461050b57602036600319011261050b5780611b44611fed565b6040516342f9577960e11b8152602081600481867f000000000000000000000000db9a1bdc443dd11366b8a6dc8038144ecc4d4e236001600160a01b03165af18015610a4f57611ba59184916113a857506001600160a01b03163314612448565b600c546001600160a01b031690611bbd821515612480565b813b15611c0d57604051635efcc08b60e11b81526001600160a01b0390911660048201529082908290602490829084905af1801561048c57611bfc5750f35b81611c0691612049565b61050b5780f35b5050fd5b503461050b57602036600319011261050b576020906040906001600160a01b03611c39611fed565b168152600383522054604051908152f35b5034610c78576040366003190112610c7857611c64611fed565b90611c6d612003565b6040516342f9577960e11b81529092906020816004815f7f000000000000000000000000db9a1bdc443dd11366b8a6dc8038144ecc4d4e236001600160a01b03165af18015611e9657611cd1915f916113a857506001600160a01b03163314612448565b600c5490611ce86001600160a01b03831615612480565b6001600160a01b0381166001600160a01b0319929092168217600c55813b15610c7857604051635efcc08b60e11b81526001600160a01b0390941660048501525f8460248183865af18015611e9657611e80575b6040516370a0823160e01b81523060048201529293508392907f00000000000000000000000070ac2feeb9ab4417591a97ad2607dd0e87bb3e336001600160a01b0316602083602481845afa928315610f30578593611e49575b5082611da0578480f35b60405163095ea7b360e01b81526001600160a01b03929092166004830152602482018390526020908290604490829088905af1801561097757611e2c575b50813b15611c0d57829160248392604051948593849263b6b55f2560e01b845260048401525af1801561048c57611e17575b8080808480f35b81611e2191612049565b61050b57805f611e10565b611e449060203d602011610a4857610a3b8183612049565b611dde565b945091506020843d602011611e78575b81611e6660209383612049565b81010312610c7857849351915f611d96565b3d9150611e59565b9150915f611e8d91612049565b5f908290611d3c565b6040513d5f823e3d90fd5b34610c78576040366003190112610c78576020610617611ebf611fed565b611ec7612003565b90612249565b34610c78575f366003190112610c78576020600a54604051908152f35b34610c78576040366003190112610c78576020610617611f08611fed565b6024359061210a565b34610c78576040366003190112610c78576001600160a01b03611f32611fed565b165f52601960205260405f206024355f526020526040805f206001815491015482519182526020820152f35b34610c78575f366003190112610c78576040517f0000000000000000000000000c0c11d859dbd097cef8e965c691bcc20a64f68b6001600160a01b03168152602090f35b34610c78576040366003190112610c78576040906001600160a01b03611fc6611fed565b165f52601d602052815f206024355f52602052815f20600181549101549082526020820152f35b600435906001600160a01b0382168203610c7857565b602435906001600160a01b0382168203610c7857565b6040810190811067ffffffffffffffff82111761203557604052565b634e487b7160e01b5f52604160045260245ffd5b90601f8019910116810190811067ffffffffffffffff82111761203557604052565b6040906003190112610c78576004359060243590565b600d5481101561209957600d5f5260205f2001905f90565b634e487b7160e01b5f52603260045260245ffd5b919082039182116120ba57565b634e487b7160e01b5f52601160045260245ffd5b81156120d8570490565b634e487b7160e01b5f52601260045260245ffd5b906040516120f981612019565b602060018294805484520154910152565b6001600160a01b03165f818152601a602052604090205491821561221457815f52601960205260405f20925f19810190811193846120ba57815f526020528160405f2054111561220d57825f52601960205260405f205f80526020528160405f205411612205575f936120ba5791905b8383116121875750505090565b61219d61219485856120ad565b60011c846120ad565b93825f52601960205260405f20855f526020526121bc60405f206120ec565b518281036121cc57505050505090565b918093949592105f146121e35750925b919061217a565b93505f198101908111156121dc57634e487b7160e01b5f52601160045260245ffd5b505050505f90565b9250505090565b5050505f90565b5f1981146120ba5760010190565b919082018092116120ba57565b818102929181159184041417156120ba57565b6001600160a01b038181165f81815260076020908152604080832094871680845294825280832054848452601d8352818420848052835281842054868552601a90935292205493959293909291901561241f5782816122ae941190821802189061210a565b92805f52601a60205260405f20545f198101908082116120ba575f9582612357575b505092612347670de0b6b3a76400009383612354979661234d955f52601960205260405f20905f5260205261230760405f206120ec565b906123226020612318845188612a58565b50930151956129a9565b925f52600860205260405f20905f5260205260405f20548181119082180218906120ad565b90612236565b0490612229565b90565b9692969391906001190181811196875b6120ba5781861161240457885f52601960205260405f20865f5260205261239060405f206120ec565b895f52601960205260405f209160018801928389116120ba5761234d6123f793670de0b6b3a7640000926123fd965f526020526123478c60206123ed6123d860405f206120ec565b926123e4865182612a58565b50935190612a58565b50930151926120ad565b9561221b565b9487612367565b93979396509193509050612347670de0b6b3a76400006122d0565b5050505050505f90565b90816020910312610c7857516001600160a01b0381168103610c785790565b1561244f57565b60405162461bcd60e51b81526020600482015260096024820152686f6e6c79207465616d60b81b6044820152606490fd5b1561248757565b60405162461bcd60e51b81526020600482015260166024820152757374616b696e6720616c72656164792065786973747360501b6044820152606490fd5b90816020910312610c7857518015158103610c785790565b5f905f91335f52600b60205260405f2054821461278a575b6001601f5403610c78576002601f558261250d6132be565b61251983600a546120ad565b600a55335f52600b60205260405f206125338482546120ad565b9055600c546001600160a01b031680612745575b5061257383337f00000000000000000000000070ac2feeb9ab4417591a97ad2607dd0e87bb3e33612eb8565b156127315733815260096020526040812054830361050b573381526009602052604081208190557f000000000000000000000000f3113e4f80c84935e576cfd75f4423e9b911908a6001600160a01b0316803b156104975760405163411b1f7760e01b8152600481018590523360248201529082908290604490829084905af1801561048c5790829161271c575b50505b338152600160205261261b604082205482546120ad565b8155338152600b602052612642604082205433835260016020528060408420558254612229565b8155338152600160205261265a604082205433612f4b565b61266261301b565b7f000000000000000000000000f3113e4f80c84935e576cfd75f4423e9b911908a6001600160a01b0316803b1561049757604051633aa53b9160e21b815260048101859052336024820152604481018490529082908290606490829084905af1801561048c57612707575b505060405191825260208201527ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b56860403392a26001601f55565b612712828092612049565b61050b57806126cd565b8161272691612049565b61050b57805f612601565b338152600960205260408120549250612604565b803b15610c78575f8091602460405180948193632e1a7d4d60e01b83528960048401525af18015611e965715612547576127829192505f90612049565b5f905f612547565b9150335f52600960205260405f2054916124f5565b80518210156120995760209160051b010190565b601c54908115612899575f19820191821191826120ba57805f52601b6020528160405f20541115612893575f8052601b6020527f584f46c60af19681376031579adb04a2416e54ee5505351c2a8435e3766026ea548210612214575f926120ba57905b82821161282257505090565b61283861282f84846120ad565b60011c836120ad565b92835f52601b60205261284d60405f206120ec565b5182810361285c575050505090565b9180939492105f146128715750915b90612816565b92505f1981019081111561286b57634e487b7160e01b5f52601160045260245ffd5b91505090565b50505f90565b6001600160a01b03165f818152600460205260409020544210156128ea5780612354915f5260046020526128d74260405f20546120ad565b905f52600360205260405f205490612236565b505f90565b6040516342f9577960e11b81526020816004815f7f000000000000000000000000db9a1bdc443dd11366b8a6dc8038144ecc4d4e236001600160a01b03165af18015611e9657612950915f916113a857506001600160a01b03163314612448565b600c546001600160a01b031680156129a657803b15610c78575f8091604460405180948193639faceb1b60e01b83523060048401528160248401525af18015611e965761299a5750565b5f6129a491612049565b565b50565b5f54908115612a3c576001600160a01b03165f81815260066020908152604080832054600480845282852054600585529290942054939092529092612a089290916128d7918082188183100218904281811191811891909102186120ad565b670de0b6b3a7640000810290808204670de0b6b3a764000014901517156120ba5761235492612a36916120ce565b90612229565b6001600160a01b03165f90815260066020526040902054919050565b6001600160a01b03165f818152601e60205260409020549092918115612bae57835f52601d60205260405f20915f19810190811192836120ba57815f526020528160405f20541115612b8657845f52601d60205260405f205f80526020528160405f205411612b7b575f926120ba57905b828211612af65750505f928352601d60209081526040808520928552919052909120600181015490549091565b612b0661282f84849795976120ad565b835f52601d60205260405f20815f52602052612b2460405f206120ec565b9586518381145f14612b40575050505050506020820151915190565b839495975092909192105f14612b595750915b90612ac9565b92505f19810190811115612b5357634e487b7160e01b5f52601160045260245ffd5b50505090505f905f90565b5f948552601d6020908152604080872092875291905290932060018101549054909350919050565b505090505f905f90565b9060018060a01b038216805f52600560205260405f205492815f52600660205260405f205491601c54908115612c36575f52600360205260405f205415612d4557612c02856127b3565b5f19820191908183116120ba5782612c9d575b50505f52601b602052612c2a60405f206120ec565b60208101908151612c3d575b5050509190565b8295612c939492612c8392612c6f612c8a9660018060a01b03165f52600460205260405f205442811090421802421890565b905191519180841184821802189089613314565b5090612229565b9283429161319d565b42915f8080612c36565b9491906001190181811195865b6120ba57818111612d3957805f52601b602052612cc960405f206120ec565b602081018051612ce5575b5050612cdf9061221b565b86612caa565b90919860018a0190818b116120ba57612cdf93612d2593612d1f935f52601b602052612d1360405f206120ec565b5191519051918a613314565b97612229565b95612d3181888861319d565b97905f612cd4565b50509093505f80612c15565b5050909150904290565b919060018060a01b038316805f52600560205260405f205493815f52600660205260405f205492601c54928315612e71575f52600360205260405f205415612e6657612d9a866127b3565b905f1984019384116120ba57838110908418028084189303612dbd575050509190565b5f19830192831194919290855b6120ba57818111612e5957805f52601b602052612de960405f206120ec565b602081018051612e05575b5050612dff9061221b565b85612dca565b9091976001890190818a116120ba57612dff93612e4593612e3f935f52601b602052612e3360405f206120ec565b51915190519189613314565b96612229565b94612e5181878761319d565b96905f612df4565b50509250505f8080612c36565b505050909150904290565b505050509190565b3d15612eb3573d9067ffffffffffffffff82116120355760405191612ea8601f8201601f191660200184612049565b82523d5f602084013e565b606090565b919091803b15610c785760405163a9059cbb60e01b602082019081526001600160a01b039490941660248201526044808201939093529182525f9283928390612f02606482612049565b51925af1612f0e612e79565b81612f1c575b5015610c7857565b8051801592508215612f31575b50505f612f14565b612f4492506020809183010191016124c5565b5f80612f29565b6001600160a01b03165f818152601a60205260409020549081151580612ff2575b15612f97575f52601960205260405f20905f1981019081116120ba575f52602052600160405f200155565b9091612fd99060405190612faa82612019565b4282526020820152825f52601960205260405f20845f5260205260405f20906020600191805184550151910155565b600182018092116120ba575f52601a60205260405f2055565b50805f52601960205260405f205f1983018381116120ba575f526020524260405f205414612f6c565b601c5480151580613092575b1561304b575f54905f1981019081116120ba575f52601b602052600160405f200155565b6130825f546040519061305d82612019565b4282526020820152825f52601b60205260405f20906020600191805184550151910155565b600181018091116120ba57601c55565b505f1981018181116120ba575f52601b6020524260405f205414613027565b919060018060a01b03831690815f52600560205260405f205493825f52600660205260405f205492601c54908115612e71575f52600360205260405f205415612e66576130fd866127b3565b925f1982019182116120ba578181109082180218915b828110613121575050509190565b805f52601b60205261313560405f206120ec565b60208101805161314a575b5050600101613113565b90919660018801908189116120ba5760019361318993613183935f52601b60205261317760405f206120ec565b51915190519187613314565b95612229565b9361319581868561319d565b95905f613140565b6001600160a01b03165f818152601e6020526040902054919282151580613245575b156131eb57505f52601d60205260405f20905f1981019081116120ba575f52602052600160405f200155565b61322c919293604051916131fe83612019565b82526020820152825f52601d60205260405f20845f5260205260405f20906020600191805184550151910155565b600182018092116120ba575f52601e60205260405f2055565b50815f52601d60205260405f205f1984018481116120ba575f526020528060405f2054146131bf565b90813b15610c78576040516323b872dd60e01b602082019081526001600160a01b0392831660248301529190931660448401526064808401949094529282525f9283928390612f02608482612049565b600d545f5b8181106132ce575050565b806132da600192612081565b838060a01b0391549060031b1c166132f181612bb8565b825f93929352600660205260405f20915f52600560205260405f205555016132c3565b6001600160a01b03165f818152600460205260409020548286188387110290921895946133659391926128d792808318928110929092029091188082188183100218908088189088110287186120ad565b90670de0b6b3a7640000820291808304670de0b6b3a764000014901517156120ba57613390916120ce565b919056fea264697066735822122045575e00b1ee184ccf22d57f3cba5c2cbc6989d7c0ca3050ed9db5fbce5e22ea64736f6c634300081c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000070ac2feeb9ab4417591a97ad2607dd0e87bb3e330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ba8f46e97599a038c7c1b63f6e4c0357d65ab50a0000000000000000000000000c0c11d859dbd097cef8e965c691bcc20a64f68b000000000000000000000000db9a1bdc443dd11366b8a6dc8038144ecc4d4e23000000000000000000000000f3113e4f80c84935e576cfd75f4423e9b911908a0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000030000000000000000000000008ff0dd9f9c40a0d76ef1bcfaf5f98c1610c74bd8000000000000000000000000b8ce59fc3717ada4c02eadf9682a9e934f625ebb00000000000000000000000028245ab01298eaef7933bc90d35bd9dbca5c89db
-----Decoded View---------------
Arg [0] : _stake (address): 0x70ac2feeB9ab4417591a97AD2607DD0E87bb3e33
Arg [1] : _staking (address): 0x0000000000000000000000000000000000000000
Arg [2] : _internal_bribe (address): 0xbA8F46E97599a038C7c1b63f6E4C0357d65AB50A
Arg [3] : _external_bribe (address): 0x0C0C11d859DBd097ceF8e965C691bCc20a64F68B
Arg [4] : __ve (address): 0xdB9A1bdc443dd11366b8a6dc8038144eCc4D4E23
Arg [5] : _voter (address): 0xF3113E4F80c84935E576CFD75F4423E9B911908A
Arg [6] : _forPair (bool): True
Arg [7] : _allowedRewardTokens (address[]): 0x8fF0dd9f9C40a0d76eF1BcFAF5f98c1610c74Bd8,0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb,0x28245AB01298eaEf7933bC90d35Bd9DbCA5C89DB
-----Encoded View---------------
12 Constructor Arguments found :
Arg [0] : 00000000000000000000000070ac2feeb9ab4417591a97ad2607dd0e87bb3e33
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [2] : 000000000000000000000000ba8f46e97599a038c7c1b63f6e4c0357d65ab50a
Arg [3] : 0000000000000000000000000c0c11d859dbd097cef8e965c691bcc20a64f68b
Arg [4] : 000000000000000000000000db9a1bdc443dd11366b8a6dc8038144ecc4d4e23
Arg [5] : 000000000000000000000000f3113e4f80c84935e576cfd75f4423e9b911908a
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000100
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000003
Arg [9] : 0000000000000000000000008ff0dd9f9c40a0d76ef1bcfaf5f98c1610c74bd8
Arg [10] : 000000000000000000000000b8ce59fc3717ada4c02eadf9682a9e934f625ebb
Arg [11] : 00000000000000000000000028245ab01298eaef7933bc90d35bd9dbca5c89db
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 35 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ 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.