Source Code
Latest 25 from a total of 353 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Withdraw | 23048099 | 28 days ago | IN | 0 HYPE | 0.00010017 | ||||
| Withdraw | 21362524 | 47 days ago | IN | 0 HYPE | 0.0001585 | ||||
| Withdraw | 20409813 | 58 days ago | IN | 0 HYPE | 0.00144775 | ||||
| Withdraw | 16217580 | 106 days ago | IN | 0 HYPE | 0.00222299 | ||||
| Withdraw | 15120600 | 119 days ago | IN | 0 HYPE | 0.00008522 | ||||
| Withdraw | 14156849 | 129 days ago | IN | 0 HYPE | 0.00008939 | ||||
| Withdraw | 13495693 | 137 days ago | IN | 0 HYPE | 0.00107658 | ||||
| Withdraw | 13368714 | 138 days ago | IN | 0 HYPE | 0.01314793 | ||||
| Withdraw | 13337532 | 139 days ago | IN | 0 HYPE | 0.00008981 | ||||
| Withdraw | 12154953 | 152 days ago | IN | 0 HYPE | 0.000046 | ||||
| Withdraw | 12062556 | 153 days ago | IN | 0 HYPE | 0.00411583 | ||||
| Withdraw | 12033220 | 154 days ago | IN | 0 HYPE | 0.05901122 | ||||
| Withdraw | 11994755 | 154 days ago | IN | 0 HYPE | 0.0001986 | ||||
| Withdraw | 11971492 | 154 days ago | IN | 0 HYPE | 0.00002905 | ||||
| Withdraw | 11609211 | 159 days ago | IN | 0 HYPE | 0.00007396 | ||||
| Withdraw | 11571108 | 159 days ago | IN | 0 HYPE | 0.00010303 | ||||
| Withdraw | 11488221 | 160 days ago | IN | 0 HYPE | 0.00002641 | ||||
| Withdraw | 11351585 | 161 days ago | IN | 0 HYPE | 0.00005547 | ||||
| Withdraw | 11314858 | 162 days ago | IN | 0 HYPE | 0.00002644 | ||||
| Withdraw | 11298532 | 162 days ago | IN | 0 HYPE | 0.00660435 | ||||
| Withdraw | 10852151 | 167 days ago | IN | 0 HYPE | 0.00016554 | ||||
| Withdraw | 10668093 | 169 days ago | IN | 0 HYPE | 0.0000317 | ||||
| Withdraw | 10648638 | 169 days ago | IN | 0 HYPE | 0.0000317 | ||||
| Withdraw | 10630518 | 170 days ago | IN | 0 HYPE | 0.00002641 | ||||
| Withdraw | 10627267 | 170 days ago | IN | 0 HYPE | 0.00002641 |
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 3765099 | 257 days ago | Contract Creation | 0 HYPE |
Cross-Chain Transactions
Loading...
Loading
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
6101208060405234610387576137f3803803809161001d82856103dd565b83398101610100828203126103875761003582610400565b61004160208401610400565b9261004e60408201610400565b9161005b60608301610400565b61006760808401610400565b9561007460a08501610400565b9260c0850151948515158096036103875760e0810151906001600160401b03821161038757019680601f89011215610387578751976001600160401b038911610210578860051b90604051996100cd602084018c6103dd565b8a526020808b019282010192831161038757602001905b8282106103c5575050506001601f5560805260018060a01b0316938460018060a01b0319600c541617600c5560c05260e0528460a0526101005260ff8019600254169116176002555f5b8251811015610224576001600160a01b036101498285610414565b5116610158575b60010161012e565b6001600160a01b0361016a8285610414565b51165f908152601760205260409020805460ff191660011790556001600160a01b036101968285610414565b511690600d549168010000000000000000831015610210576001830180600d558310156101fc57600d5f527fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb590920180546001600160a01b031916909217909155610150565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52604160045260245ffd5b5082816102f5575b6040516133ca908161042982396080518181816102bb015281816106af01528181610b4401528181610cbf0152818161171401528181611d57015261254f015260a051818181610739015281816112fd015281816113e801528181611b5a01528181611c860152612905015260c05181611453015260e05181611f73015261010051818181610309015281816103cf015281816107ff015281816108ca015281816110af0152818161167c015281816117f401528181611a2a0152818161259c01526126640152f35b6040516342f9577960e11b815290602090829060049082905f906001600160a01b03165af190811561037c575f9161038b575b50813b1561038757604051635efcc08b60e11b81526001600160a01b039091166004820152905f908290602490829084905af1801561037c5761036c575b8061022c565b5f610376916103dd565b5f610366565b6040513d5f823e3d90fd5b5f80fd5b90506020813d6020116103bd575b816103a6602093836103dd565b81010312610387576103b790610400565b82610328565b3d9150610399565b602080916103d284610400565b8152019101906100e4565b601f909101601f19168101906001600160401b0382119082101761021057604052565b51906001600160a01b038216820361038757565b80518210156101fc5760209160051b01019056fe6080806040526004361015610012575f80fd5b5f905f3560e01c90816301316ddf14611fa25750806303fbf83a14611f5e5780630cdfebfa14611f11578063115c6f3914611eea57806318160ddd14611ecd578063211dc32d14611ea157806321cc096814611c4a578063221ca18c14611c115780632619582614611b295780632ce9aead14611af05780632e1a7d4d14611ad35780632f85074a14611a9457806331279d3d146117435780633a4b66f1146116fe5780633ca068b6146116ab57806346c96aac146116665780634cf088d91461163d5780634d5ce038146115fe578063597a8d6f146115c65780635a45d052146115a0578063638634ee1461156157806363fb415b1461152857806368fcee1a146114da5780636fcfff45146114a157806370a0823114610ab057806376f4be3614611482578063770f85711461143d578063853828b6146114175780638dd598fb146113d25780639418f939146112b257806399bcc0521461128e5780639ce43f9014611255578063a0dc275814611237578063a495e5b5146111e4578063aa479652146111ab578063b66503cf14610c84578063c6f678bd14610b19578063d294f09314610ae9578063d35e254414610ab0578063d7da4bb014610a93578063da09d19d14610a5a578063e2bbb1581461067e578063e57482131461065b578063e68863961461063d578063e8111a121461061f578063f1229777146105f3578063f301af42146105af578063f7412baf1461057b578063fc97a30314610542578063fd3140981461050e5763fdb483c71461024f575f80fd5b3461050b5761025d3661206b565b906001601f5403610488576002601f55816102766132be565b61028282600a546120ad565b600a55338452600b6020526040842061029c8382546120ad565b9055600c5484906001600160a01b0316806104c4575b50506102df82337f0000000000000000000000000000000000000000000000000000000000000000612eb8565b156104b05733835260096020526040832054820361048857338352600960205260408320839055827f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b156104975760405163411b1f7760e01b8152600481018590523360248201529082908290604490829084905af1801561048c5761049b575b50505b3383526001602052610385604084205484546120ad565b8355338352600b6020526103ac604084205433855260016020528060408620558454612229565b835533835260016020526103c4604084205433612f4b565b6103cc61301b565b827f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b1561049757604051633aa53b9160e21b815260048101859052336024820152604481018490529082908290606490829084905af1801561048c57610473575b505060405191825260208201527ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b56860403392a26001601f5580f35b8161047d91612049565b61048857825f610438565b8280fd5b6040513d84823e3d90fd5b5080fd5b816104a591612049565b61048857825f61036b565b33835260096020526040832054915061036e565b803b1561049757818091602460405180948193632e1a7d4d60e01b83528960048401525af1801561048c57156102b257816104fe91612049565b61050957835f6102b2565b835b80fd5b503461050b57604036600319011261050b57604061053661052d611fed565b60243590612a58565b82519182526020820152f35b503461050b57602036600319011261050b576020906040906001600160a01b0361056a611fed565b168152600983522054604051908152f35b503461050b57602036600319011261050b57604080916004358152601b602052206001815491015482519182526020820152f35b503461050b57602036600319011261050b5760043590600d5482101561050b5760206105da83612081565b905460405160039290921b1c6001600160a01b03168152f35b503461050b57602036600319011261050b576020610617610612611fed565b6129a9565b604051908152f35b503461050b578060031936011261050b576020601c54604051908152f35b503461050b578060031936011261050b576020600d54604051908152f35b503461050b578060031936011261050b57602060ff600254166040519015158152f35b503461050b5761068d3661206b565b906001601f5403610488576002601f55818115610509576106ac6132be565b837f00000000000000000000000000000000000000000000000000000000000000006106da8430338461326e565b600c546001600160a01b03169081610996575b5050506106fc82600a54612229565b600a55338452600b60205260408420610716838254612229565b905515610982576040516331a9108f60e11b8152600481018390526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610977578491610948575b50336001600160a01b03909116036104885733835260096020526040832054156108b8575b338352600960205281604084205403610488575b33835260016020526107c1604084205484546120ad565b8355338352600b6020526107f4604084205433855260016020528060408620556107ec818654612229565b855533612f4b565b6107fc61301b565b827f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b156104975760405163530e389d60e11b815260048101859052336024820152604481018490529082908290606490829084905af1801561048c576108a3575b505060405191825260208201527f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a1560403392a26001601f5580f35b816108ad91612049565b61048857825f610868565b338352600960205260408320829055827f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b156104975760405163698473e360e01b8152600481018590523360248201529082908290604490829084905af1801561048c57610933575b5050610796565b8161093d91612049565b61048857825f61092c565b61096a915060203d602011610970575b6109628183612049565b810190612429565b5f610771565b503d610958565b6040513d86823e3d90fd5b3383526009602052604083205491506107aa565b60405163095ea7b360e01b81526001600160a01b038381166004830152602482018790529091602091839160449183918891165af18015610a4f57610a22575b50803b156104975781809160246040518094819363b6b55f2560e01b83528960048401525af1801561048c57610a0d575b806106ed565b81610a1791612049565b61050957835f610a07565b610a439060203d602011610a48575b610a3b8183612049565b8101906124c5565b6109d6565b503d610a31565b6040513d85823e3d90fd5b503461050b57602036600319011261050b576020906040906001600160a01b03610a82611fed565b168152600483522054604051908152f35b503461050b578060031936011261050b5760209054604051908152f35b503461050b57602036600319011261050b576020906040906001600160a01b03610ad8611fed565b168152600b83522054604051908152f35b503461050b578060031936011261050b576001601f540361050b576002601f55610b116128ef565b6001601f5580f35b503461050b57602036600319011261050b576040516370a0823160e01b8152336004828101919091527f0000000000000000000000000000000000000000000000000000000000000000919035836001600160a01b038416602084602481845afa93841561048c578294610c49575b506001601f5403610497576002601f55829484156104885784610bb691610bad6132be565b3090339061326e565b600c546001600160a01b03169081610bd7575050506106fc82600a54612229565b60405163095ea7b360e01b81526001600160a01b038316600482015260248101869052906020908290604490829087905af18015610a4f57610a225750803b156104975781809160246040518094819363b6b55f2560e01b83528960048401525af1801561048c57610a0d57806106ed565b915092506020813d602011610c7c575b81610c6660209383612049565b81010312610c7857849051925f610b88565b5f80fd5b3d9150610c59565b503461050b57604036600319011261050b57610c9e611fed565b6024356001601f5403610488576002601f556001600160a01b0382811692907f000000000000000000000000000000000000000000000000000000000000000016831461050957811561050957828452601760205260ff60408520541615611093575b8284526003602052604084205415610fa0575b610d1d81612bb8565b848652600660205260408620908587526005602052604087205555828452600460205260408420544210155f14610f3b57610d5a8230338461326e565b828452600360205262093a80820460408520555b8284526003602052604084205415610509576040516370a0823160e01b8152306004820152602081602481875afa908115610f30578591610efe575b50838552600360205262093a806040862054910410610eb95762093a804201804211610ea55783855260046020526040852055828452601760205260ff60408520541615610e28575b506040519081527ff70d5c697de7ea828df48e5c4573cb2194c659f1901f70110c52b066dcf5082660203392a36001601f5580f35b828452601760205260408420805460ff19166001179055600d5468010000000000000000811015610e915790610e67826001610e8b9401600d55612081565b81546001600160a01b0393841660039290921b91821b9390911b1916919091179055565b5f610df3565b634e487b7160e01b85526041600452602485fd5b634e487b7160e01b85526011600452602485fd5b60405162461bcd60e51b815260206004820152601860248201527f50726f76696465642072657761726420746f6f206869676800000000000000006044820152606490fd5b90506020813d602011610f28575b81610f1960209383612049565b81010312610c7857515f610daa565b3d9150610f0c565b6040513d87823e3d90fd5b8284526004602052610f67610f544260408720546120ad565b8486526003602052604086205490612236565b80831115610f9c57610f8962093a8091610f838530338761326e565b84612229565b0483855260036020526040852055610d6e565b8480fd5b828452601e602052604084205480151580611056575b15610ffa57838552601d60205260408520905f198101908111610fe6578552602052836001604082200155610d14565b634e487b7160e01b86526011600452602486fd5b61103960405161100981612019565b428152866020820152858752601d6020526040872083885260205260408720906020600191805184550151910155565b60018101809111610ea557838552601e6020526040852055610d14565b50838552601d602052604085205f19820182811161107f57865260205242604086205414610fb6565b634e487b7160e01b87526011600452602487fd5b604051633af32abf60e01b8152600481018490526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610f3057859161118c575b501561113c576010600d5410610d015760405162461bcd60e51b815260206004820152601760248201527f746f6f206d616e79207265776172647320746f6b656e730000000000000000006044820152606490fd5b60405162461bcd60e51b815260206004820152602260248201527f7265776172647320746f6b656e73206d7573742062652077686974656c697374604482015261195960f21b6064820152608490fd5b6111a5915060203d602011610a4857610a3b8183612049565b5f6110e7565b503461050b57602036600319011261050b576020906040906001600160a01b036111d3611fed565b168152601e83522054604051908152f35b503461050b57604036600319011261050b576040611200611fed565b91611209612003565b9260018060a01b031681526007602052209060018060a01b03165f52602052602060405f2054604051908152f35b503461050b578060031936011261050b57602060405162093a808152f35b503461050b57602036600319011261050b576020906040906001600160a01b0361127d611fed565b168152600683522054604051908152f35b503461050b57602036600319011261050b5760206106176112ad611fed565b61289f565b503461050b57606036600319011261050b576004356112cf612003565b6044356001600160a01b03811692909190838303610f9c576040516342f9577960e11b8152602081600481897f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af180156113c7576113499187916113a8575b506001600160a01b03163314612448565b61135281612081565b90546001600160a01b039384169360039290921b1c16829003610f9c576113a593610e6792865260176020526040862060ff1981541690558552601760205260408520600160ff19825416179055612081565b80f35b6113c1915060203d602011610970576109628183612049565b5f611338565b6040513d88823e3d90fd5b503461050b578060031936011261050b576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b503461050b578060031936011261050b57338152600b6020526113a560408220546124dd565b503461050b578060031936011261050b576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b503461050b57602036600319011261050b5760206106176004356127b3565b503461050b57602036600319011261050b576020906040906001600160a01b036114c9611fed565b168152601a83522054604051908152f35b503461050b57604036600319011261050b576114f4611fed565b61150060243582612d4f565b909160018060a01b031690818452600660205260408420918452600560205260408420555580f35b503461050b57602036600319011261050b576020906040906001600160a01b03611550611fed565b168152600183522054604051908152f35b503461050b57602036600319011261050b576020610617611580611fed565b60018060a01b03165f52600460205260405f205442811090421802421890565b503461050b57604036600319011261050b576115ba611fed565b611500602435826130b1565b503461050b57602036600319011261050b57600435600881101561049757600e01546040516001600160a01b03909116815260209150f35b503461050b57602036600319011261050b5760209060ff906040906001600160a01b03611629611fed565b168152601784522054166040519015158152f35b503461050b578060031936011261050b57600c546040516001600160a01b039091168152602090f35b503461050b578060031936011261050b576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b503461050b57604036600319011261050b5760406116c7611fed565b916116d0612003565b9260018060a01b031681526008602052209060018060a01b03165f52602052602060405f2054604051908152f35b503461050b578060031936011261050b576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b503461050b57604036600319011261050b5761175d611fed565b60243567ffffffffffffffff811161048857366023820112156104885780600401359067ffffffffffffffff8211611a80578160051b90604051926117a56020840185612049565b83526024602084019282010190368211611a7c57602401915b818310611a58575050506001601f5403610488576001600160a01b038216903382148015611a26575b15610509576001601f55837f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b15610497578180916024604051809481936363453ae160e01b83523060048401525af1801561048c57611a11575b50506002601f55835b81518110156119b15760019061187d6001600160a01b03611876838661279f565b5116612bb8565b838060a01b0361188d848761279f565b5116885260066020526040882090848060a01b036118ab858861279f565b5116895260056020526040892055556118d585838060a01b036118ce848761279f565b5116612249565b828060a01b036118e5838661279f565b51168752600760205260408720855f5260205260405f20429055828060a01b0361190f838661279f565b5116875260066020526040872054838060a01b0361192d848761279f565b51168852600860205260408820865f5260205260405f205580611990575b828060a01b0361195b838661279f565b5116906040519081527f9aa05b3d70a9e3e2f004f039648839560576334fb45c81f91b6db03ad9e2efc960203392a301611855565b6119ac8187858060a01b036119a5868961279f565b5116612eb8565b61194b565b84611a09858580845260016020526119ce604085205485546120ad565b8455808452600b6020526119f5604085205482865260016020528060408720558554612229565b845583526001602052604083205490612f4b565b610b1161301b565b81611a1b91612049565b61050957835f61184c565b50337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316146117e7565b82356001600160a01b0381168103611a78578152602092830192016117be565b8680fd5b8580fd5b634e487b7160e01b84526041600452602484fd5b503461050b57602036600319011261050b5760209060ff906040906001600160a01b03611abf611fed565b168152601884522054166040519015158152f35b503461050b57602036600319011261050b576113a56004356124dd565b503461050b57602036600319011261050b576020906040906001600160a01b03611b18611fed565b168152600583522054604051908152f35b503461050b57602036600319011261050b5780611b44611fed565b6040516342f9577960e11b8152602081600481867f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af18015610a4f57611ba59184916113a857506001600160a01b03163314612448565b600c546001600160a01b031690611bbd821515612480565b813b15611c0d57604051635efcc08b60e11b81526001600160a01b0390911660048201529082908290602490829084905af1801561048c57611bfc5750f35b81611c0691612049565b61050b5780f35b5050fd5b503461050b57602036600319011261050b576020906040906001600160a01b03611c39611fed565b168152600383522054604051908152f35b5034610c78576040366003190112610c7857611c64611fed565b90611c6d612003565b6040516342f9577960e11b81529092906020816004815f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af18015611e9657611cd1915f916113a857506001600160a01b03163314612448565b600c5490611ce86001600160a01b03831615612480565b6001600160a01b0381166001600160a01b0319929092168217600c55813b15610c7857604051635efcc08b60e11b81526001600160a01b0390941660048501525f8460248183865af18015611e9657611e80575b6040516370a0823160e01b81523060048201529293508392907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316602083602481845afa928315610f30578593611e49575b5082611da0578480f35b60405163095ea7b360e01b81526001600160a01b03929092166004830152602482018390526020908290604490829088905af1801561097757611e2c575b50813b15611c0d57829160248392604051948593849263b6b55f2560e01b845260048401525af1801561048c57611e17575b8080808480f35b81611e2191612049565b61050b57805f611e10565b611e449060203d602011610a4857610a3b8183612049565b611dde565b945091506020843d602011611e78575b81611e6660209383612049565b81010312610c7857849351915f611d96565b3d9150611e59565b9150915f611e8d91612049565b5f908290611d3c565b6040513d5f823e3d90fd5b34610c78576040366003190112610c78576020610617611ebf611fed565b611ec7612003565b90612249565b34610c78575f366003190112610c78576020600a54604051908152f35b34610c78576040366003190112610c78576020610617611f08611fed565b6024359061210a565b34610c78576040366003190112610c78576001600160a01b03611f32611fed565b165f52601960205260405f206024355f526020526040805f206001815491015482519182526020820152f35b34610c78575f366003190112610c78576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b34610c78576040366003190112610c78576040906001600160a01b03611fc6611fed565b165f52601d602052815f206024355f52602052815f20600181549101549082526020820152f35b600435906001600160a01b0382168203610c7857565b602435906001600160a01b0382168203610c7857565b6040810190811067ffffffffffffffff82111761203557604052565b634e487b7160e01b5f52604160045260245ffd5b90601f8019910116810190811067ffffffffffffffff82111761203557604052565b6040906003190112610c78576004359060243590565b600d5481101561209957600d5f5260205f2001905f90565b634e487b7160e01b5f52603260045260245ffd5b919082039182116120ba57565b634e487b7160e01b5f52601160045260245ffd5b81156120d8570490565b634e487b7160e01b5f52601260045260245ffd5b906040516120f981612019565b602060018294805484520154910152565b6001600160a01b03165f818152601a602052604090205491821561221457815f52601960205260405f20925f19810190811193846120ba57815f526020528160405f2054111561220d57825f52601960205260405f205f80526020528160405f205411612205575f936120ba5791905b8383116121875750505090565b61219d61219485856120ad565b60011c846120ad565b93825f52601960205260405f20855f526020526121bc60405f206120ec565b518281036121cc57505050505090565b918093949592105f146121e35750925b919061217a565b93505f198101908111156121dc57634e487b7160e01b5f52601160045260245ffd5b505050505f90565b9250505090565b5050505f90565b5f1981146120ba5760010190565b919082018092116120ba57565b818102929181159184041417156120ba57565b6001600160a01b038181165f81815260076020908152604080832094871680845294825280832054848452601d8352818420848052835281842054868552601a90935292205493959293909291901561241f5782816122ae941190821802189061210a565b92805f52601a60205260405f20545f198101908082116120ba575f9582612357575b505092612347670de0b6b3a76400009383612354979661234d955f52601960205260405f20905f5260205261230760405f206120ec565b906123226020612318845188612a58565b50930151956129a9565b925f52600860205260405f20905f5260205260405f20548181119082180218906120ad565b90612236565b0490612229565b90565b9692969391906001190181811196875b6120ba5781861161240457885f52601960205260405f20865f5260205261239060405f206120ec565b895f52601960205260405f209160018801928389116120ba5761234d6123f793670de0b6b3a7640000926123fd965f526020526123478c60206123ed6123d860405f206120ec565b926123e4865182612a58565b50935190612a58565b50930151926120ad565b9561221b565b9487612367565b93979396509193509050612347670de0b6b3a76400006122d0565b5050505050505f90565b90816020910312610c7857516001600160a01b0381168103610c785790565b1561244f57565b60405162461bcd60e51b81526020600482015260096024820152686f6e6c79207465616d60b81b6044820152606490fd5b1561248757565b60405162461bcd60e51b81526020600482015260166024820152757374616b696e6720616c72656164792065786973747360501b6044820152606490fd5b90816020910312610c7857518015158103610c785790565b5f905f91335f52600b60205260405f2054821461278a575b6001601f5403610c78576002601f558261250d6132be565b61251983600a546120ad565b600a55335f52600b60205260405f206125338482546120ad565b9055600c546001600160a01b031680612745575b5061257383337f0000000000000000000000000000000000000000000000000000000000000000612eb8565b156127315733815260096020526040812054830361050b573381526009602052604081208190557f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b156104975760405163411b1f7760e01b8152600481018590523360248201529082908290604490829084905af1801561048c5790829161271c575b50505b338152600160205261261b604082205482546120ad565b8155338152600b602052612642604082205433835260016020528060408420558254612229565b8155338152600160205261265a604082205433612f4b565b61266261301b565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b1561049757604051633aa53b9160e21b815260048101859052336024820152604481018490529082908290606490829084905af1801561048c57612707575b505060405191825260208201527ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b56860403392a26001601f55565b612712828092612049565b61050b57806126cd565b8161272691612049565b61050b57805f612601565b338152600960205260408120549250612604565b803b15610c78575f8091602460405180948193632e1a7d4d60e01b83528960048401525af18015611e965715612547576127829192505f90612049565b5f905f612547565b9150335f52600960205260405f2054916124f5565b80518210156120995760209160051b010190565b601c54908115612899575f19820191821191826120ba57805f52601b6020528160405f20541115612893575f8052601b6020527f584f46c60af19681376031579adb04a2416e54ee5505351c2a8435e3766026ea548210612214575f926120ba57905b82821161282257505090565b61283861282f84846120ad565b60011c836120ad565b92835f52601b60205261284d60405f206120ec565b5182810361285c575050505090565b9180939492105f146128715750915b90612816565b92505f1981019081111561286b57634e487b7160e01b5f52601160045260245ffd5b91505090565b50505f90565b6001600160a01b03165f818152600460205260409020544210156128ea5780612354915f5260046020526128d74260405f20546120ad565b905f52600360205260405f205490612236565b505f90565b6040516342f9577960e11b81526020816004815f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af18015611e9657612950915f916113a857506001600160a01b03163314612448565b600c546001600160a01b031680156129a657803b15610c78575f8091604460405180948193639faceb1b60e01b83523060048401528160248401525af18015611e965761299a5750565b5f6129a491612049565b565b50565b5f54908115612a3c576001600160a01b03165f81815260066020908152604080832054600480845282852054600585529290942054939092529092612a089290916128d7918082188183100218904281811191811891909102186120ad565b670de0b6b3a7640000810290808204670de0b6b3a764000014901517156120ba5761235492612a36916120ce565b90612229565b6001600160a01b03165f90815260066020526040902054919050565b6001600160a01b03165f818152601e60205260409020549092918115612bae57835f52601d60205260405f20915f19810190811192836120ba57815f526020528160405f20541115612b8657845f52601d60205260405f205f80526020528160405f205411612b7b575f926120ba57905b828211612af65750505f928352601d60209081526040808520928552919052909120600181015490549091565b612b0661282f84849795976120ad565b835f52601d60205260405f20815f52602052612b2460405f206120ec565b9586518381145f14612b40575050505050506020820151915190565b839495975092909192105f14612b595750915b90612ac9565b92505f19810190811115612b5357634e487b7160e01b5f52601160045260245ffd5b50505090505f905f90565b5f948552601d6020908152604080872092875291905290932060018101549054909350919050565b505090505f905f90565b9060018060a01b038216805f52600560205260405f205492815f52600660205260405f205491601c54908115612c36575f52600360205260405f205415612d4557612c02856127b3565b5f19820191908183116120ba5782612c9d575b50505f52601b602052612c2a60405f206120ec565b60208101908151612c3d575b5050509190565b8295612c939492612c8392612c6f612c8a9660018060a01b03165f52600460205260405f205442811090421802421890565b905191519180841184821802189089613314565b5090612229565b9283429161319d565b42915f8080612c36565b9491906001190181811195865b6120ba57818111612d3957805f52601b602052612cc960405f206120ec565b602081018051612ce5575b5050612cdf9061221b565b86612caa565b90919860018a0190818b116120ba57612cdf93612d2593612d1f935f52601b602052612d1360405f206120ec565b5191519051918a613314565b97612229565b95612d3181888861319d565b97905f612cd4565b50509093505f80612c15565b5050909150904290565b919060018060a01b038316805f52600560205260405f205493815f52600660205260405f205492601c54928315612e71575f52600360205260405f205415612e6657612d9a866127b3565b905f1984019384116120ba57838110908418028084189303612dbd575050509190565b5f19830192831194919290855b6120ba57818111612e5957805f52601b602052612de960405f206120ec565b602081018051612e05575b5050612dff9061221b565b85612dca565b9091976001890190818a116120ba57612dff93612e4593612e3f935f52601b602052612e3360405f206120ec565b51915190519189613314565b96612229565b94612e5181878761319d565b96905f612df4565b50509250505f8080612c36565b505050909150904290565b505050509190565b3d15612eb3573d9067ffffffffffffffff82116120355760405191612ea8601f8201601f191660200184612049565b82523d5f602084013e565b606090565b919091803b15610c785760405163a9059cbb60e01b602082019081526001600160a01b039490941660248201526044808201939093529182525f9283928390612f02606482612049565b51925af1612f0e612e79565b81612f1c575b5015610c7857565b8051801592508215612f31575b50505f612f14565b612f4492506020809183010191016124c5565b5f80612f29565b6001600160a01b03165f818152601a60205260409020549081151580612ff2575b15612f97575f52601960205260405f20905f1981019081116120ba575f52602052600160405f200155565b9091612fd99060405190612faa82612019565b4282526020820152825f52601960205260405f20845f5260205260405f20906020600191805184550151910155565b600182018092116120ba575f52601a60205260405f2055565b50805f52601960205260405f205f1983018381116120ba575f526020524260405f205414612f6c565b601c5480151580613092575b1561304b575f54905f1981019081116120ba575f52601b602052600160405f200155565b6130825f546040519061305d82612019565b4282526020820152825f52601b60205260405f20906020600191805184550151910155565b600181018091116120ba57601c55565b505f1981018181116120ba575f52601b6020524260405f205414613027565b919060018060a01b03831690815f52600560205260405f205493825f52600660205260405f205492601c54908115612e71575f52600360205260405f205415612e66576130fd866127b3565b925f1982019182116120ba578181109082180218915b828110613121575050509190565b805f52601b60205261313560405f206120ec565b60208101805161314a575b5050600101613113565b90919660018801908189116120ba5760019361318993613183935f52601b60205261317760405f206120ec565b51915190519187613314565b95612229565b9361319581868561319d565b95905f613140565b6001600160a01b03165f818152601e6020526040902054919282151580613245575b156131eb57505f52601d60205260405f20905f1981019081116120ba575f52602052600160405f200155565b61322c919293604051916131fe83612019565b82526020820152825f52601d60205260405f20845f5260205260405f20906020600191805184550151910155565b600182018092116120ba575f52601e60205260405f2055565b50815f52601d60205260405f205f1984018481116120ba575f526020528060405f2054146131bf565b90813b15610c78576040516323b872dd60e01b602082019081526001600160a01b0392831660248301529190931660448401526064808401949094529282525f9283928390612f02608482612049565b600d545f5b8181106132ce575050565b806132da600192612081565b838060a01b0391549060031b1c166132f181612bb8565b825f93929352600660205260405f20915f52600560205260405f205555016132c3565b6001600160a01b03165f818152600460205260409020548286188387110290921895946133659391926128d792808318928110929092029091188082188183100218908088189088110287186120ad565b90670de0b6b3a7640000820291808304670de0b6b3a764000014901517156120ba57613390916120ce565b919056fea264697066735822122045575e00b1ee184ccf22d57f3cba5c2cbc6989d7c0ca3050ed9db5fbce5e22ea64736f6c634300081c0033000000000000000000000000749ef4ab10aef61151e14c9336b07727ffa5a3230000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d466e4e05305308beb4ab2cc6c0ca3ec15af81b4000000000000000000000000d0b4a8883769ad37537c7b409daedbc70521603a000000000000000000000000db9a1bdc443dd11366b8a6dc8038144ecc4d4e23000000000000000000000000f3113e4f80c84935e576cfd75f4423e9b911908a0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000030000000000000000000000008ff0dd9f9c40a0d76ef1bcfaf5f98c1610c74bd8000000000000000000000000555555555555555555555555555555555555555500000000000000000000000028245ab01298eaef7933bc90d35bd9dbca5c89db
Deployed Bytecode
0x6080806040526004361015610012575f80fd5b5f905f3560e01c90816301316ddf14611fa25750806303fbf83a14611f5e5780630cdfebfa14611f11578063115c6f3914611eea57806318160ddd14611ecd578063211dc32d14611ea157806321cc096814611c4a578063221ca18c14611c115780632619582614611b295780632ce9aead14611af05780632e1a7d4d14611ad35780632f85074a14611a9457806331279d3d146117435780633a4b66f1146116fe5780633ca068b6146116ab57806346c96aac146116665780634cf088d91461163d5780634d5ce038146115fe578063597a8d6f146115c65780635a45d052146115a0578063638634ee1461156157806363fb415b1461152857806368fcee1a146114da5780636fcfff45146114a157806370a0823114610ab057806376f4be3614611482578063770f85711461143d578063853828b6146114175780638dd598fb146113d25780639418f939146112b257806399bcc0521461128e5780639ce43f9014611255578063a0dc275814611237578063a495e5b5146111e4578063aa479652146111ab578063b66503cf14610c84578063c6f678bd14610b19578063d294f09314610ae9578063d35e254414610ab0578063d7da4bb014610a93578063da09d19d14610a5a578063e2bbb1581461067e578063e57482131461065b578063e68863961461063d578063e8111a121461061f578063f1229777146105f3578063f301af42146105af578063f7412baf1461057b578063fc97a30314610542578063fd3140981461050e5763fdb483c71461024f575f80fd5b3461050b5761025d3661206b565b906001601f5403610488576002601f55816102766132be565b61028282600a546120ad565b600a55338452600b6020526040842061029c8382546120ad565b9055600c5484906001600160a01b0316806104c4575b50506102df82337f000000000000000000000000749ef4ab10aef61151e14c9336b07727ffa5a323612eb8565b156104b05733835260096020526040832054820361048857338352600960205260408320839055827f000000000000000000000000f3113e4f80c84935e576cfd75f4423e9b911908a6001600160a01b0316803b156104975760405163411b1f7760e01b8152600481018590523360248201529082908290604490829084905af1801561048c5761049b575b50505b3383526001602052610385604084205484546120ad565b8355338352600b6020526103ac604084205433855260016020528060408620558454612229565b835533835260016020526103c4604084205433612f4b565b6103cc61301b565b827f000000000000000000000000f3113e4f80c84935e576cfd75f4423e9b911908a6001600160a01b0316803b1561049757604051633aa53b9160e21b815260048101859052336024820152604481018490529082908290606490829084905af1801561048c57610473575b505060405191825260208201527ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b56860403392a26001601f5580f35b8161047d91612049565b61048857825f610438565b8280fd5b6040513d84823e3d90fd5b5080fd5b816104a591612049565b61048857825f61036b565b33835260096020526040832054915061036e565b803b1561049757818091602460405180948193632e1a7d4d60e01b83528960048401525af1801561048c57156102b257816104fe91612049565b61050957835f6102b2565b835b80fd5b503461050b57604036600319011261050b57604061053661052d611fed565b60243590612a58565b82519182526020820152f35b503461050b57602036600319011261050b576020906040906001600160a01b0361056a611fed565b168152600983522054604051908152f35b503461050b57602036600319011261050b57604080916004358152601b602052206001815491015482519182526020820152f35b503461050b57602036600319011261050b5760043590600d5482101561050b5760206105da83612081565b905460405160039290921b1c6001600160a01b03168152f35b503461050b57602036600319011261050b576020610617610612611fed565b6129a9565b604051908152f35b503461050b578060031936011261050b576020601c54604051908152f35b503461050b578060031936011261050b576020600d54604051908152f35b503461050b578060031936011261050b57602060ff600254166040519015158152f35b503461050b5761068d3661206b565b906001601f5403610488576002601f55818115610509576106ac6132be565b837f000000000000000000000000749ef4ab10aef61151e14c9336b07727ffa5a3236106da8430338461326e565b600c546001600160a01b03169081610996575b5050506106fc82600a54612229565b600a55338452600b60205260408420610716838254612229565b905515610982576040516331a9108f60e11b8152600481018390526020816024817f000000000000000000000000db9a1bdc443dd11366b8a6dc8038144ecc4d4e236001600160a01b03165afa908115610977578491610948575b50336001600160a01b03909116036104885733835260096020526040832054156108b8575b338352600960205281604084205403610488575b33835260016020526107c1604084205484546120ad565b8355338352600b6020526107f4604084205433855260016020528060408620556107ec818654612229565b855533612f4b565b6107fc61301b565b827f000000000000000000000000f3113e4f80c84935e576cfd75f4423e9b911908a6001600160a01b0316803b156104975760405163530e389d60e11b815260048101859052336024820152604481018490529082908290606490829084905af1801561048c576108a3575b505060405191825260208201527f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a1560403392a26001601f5580f35b816108ad91612049565b61048857825f610868565b338352600960205260408320829055827f000000000000000000000000f3113e4f80c84935e576cfd75f4423e9b911908a6001600160a01b0316803b156104975760405163698473e360e01b8152600481018590523360248201529082908290604490829084905af1801561048c57610933575b5050610796565b8161093d91612049565b61048857825f61092c565b61096a915060203d602011610970575b6109628183612049565b810190612429565b5f610771565b503d610958565b6040513d86823e3d90fd5b3383526009602052604083205491506107aa565b60405163095ea7b360e01b81526001600160a01b038381166004830152602482018790529091602091839160449183918891165af18015610a4f57610a22575b50803b156104975781809160246040518094819363b6b55f2560e01b83528960048401525af1801561048c57610a0d575b806106ed565b81610a1791612049565b61050957835f610a07565b610a439060203d602011610a48575b610a3b8183612049565b8101906124c5565b6109d6565b503d610a31565b6040513d85823e3d90fd5b503461050b57602036600319011261050b576020906040906001600160a01b03610a82611fed565b168152600483522054604051908152f35b503461050b578060031936011261050b5760209054604051908152f35b503461050b57602036600319011261050b576020906040906001600160a01b03610ad8611fed565b168152600b83522054604051908152f35b503461050b578060031936011261050b576001601f540361050b576002601f55610b116128ef565b6001601f5580f35b503461050b57602036600319011261050b576040516370a0823160e01b8152336004828101919091527f000000000000000000000000749ef4ab10aef61151e14c9336b07727ffa5a323919035836001600160a01b038416602084602481845afa93841561048c578294610c49575b506001601f5403610497576002601f55829484156104885784610bb691610bad6132be565b3090339061326e565b600c546001600160a01b03169081610bd7575050506106fc82600a54612229565b60405163095ea7b360e01b81526001600160a01b038316600482015260248101869052906020908290604490829087905af18015610a4f57610a225750803b156104975781809160246040518094819363b6b55f2560e01b83528960048401525af1801561048c57610a0d57806106ed565b915092506020813d602011610c7c575b81610c6660209383612049565b81010312610c7857849051925f610b88565b5f80fd5b3d9150610c59565b503461050b57604036600319011261050b57610c9e611fed565b6024356001601f5403610488576002601f556001600160a01b0382811692907f000000000000000000000000749ef4ab10aef61151e14c9336b07727ffa5a32316831461050957811561050957828452601760205260ff60408520541615611093575b8284526003602052604084205415610fa0575b610d1d81612bb8565b848652600660205260408620908587526005602052604087205555828452600460205260408420544210155f14610f3b57610d5a8230338461326e565b828452600360205262093a80820460408520555b8284526003602052604084205415610509576040516370a0823160e01b8152306004820152602081602481875afa908115610f30578591610efe575b50838552600360205262093a806040862054910410610eb95762093a804201804211610ea55783855260046020526040852055828452601760205260ff60408520541615610e28575b506040519081527ff70d5c697de7ea828df48e5c4573cb2194c659f1901f70110c52b066dcf5082660203392a36001601f5580f35b828452601760205260408420805460ff19166001179055600d5468010000000000000000811015610e915790610e67826001610e8b9401600d55612081565b81546001600160a01b0393841660039290921b91821b9390911b1916919091179055565b5f610df3565b634e487b7160e01b85526041600452602485fd5b634e487b7160e01b85526011600452602485fd5b60405162461bcd60e51b815260206004820152601860248201527f50726f76696465642072657761726420746f6f206869676800000000000000006044820152606490fd5b90506020813d602011610f28575b81610f1960209383612049565b81010312610c7857515f610daa565b3d9150610f0c565b6040513d87823e3d90fd5b8284526004602052610f67610f544260408720546120ad565b8486526003602052604086205490612236565b80831115610f9c57610f8962093a8091610f838530338761326e565b84612229565b0483855260036020526040852055610d6e565b8480fd5b828452601e602052604084205480151580611056575b15610ffa57838552601d60205260408520905f198101908111610fe6578552602052836001604082200155610d14565b634e487b7160e01b86526011600452602486fd5b61103960405161100981612019565b428152866020820152858752601d6020526040872083885260205260408720906020600191805184550151910155565b60018101809111610ea557838552601e6020526040852055610d14565b50838552601d602052604085205f19820182811161107f57865260205242604086205414610fb6565b634e487b7160e01b87526011600452602487fd5b604051633af32abf60e01b8152600481018490526020816024817f000000000000000000000000f3113e4f80c84935e576cfd75f4423e9b911908a6001600160a01b03165afa908115610f3057859161118c575b501561113c576010600d5410610d015760405162461bcd60e51b815260206004820152601760248201527f746f6f206d616e79207265776172647320746f6b656e730000000000000000006044820152606490fd5b60405162461bcd60e51b815260206004820152602260248201527f7265776172647320746f6b656e73206d7573742062652077686974656c697374604482015261195960f21b6064820152608490fd5b6111a5915060203d602011610a4857610a3b8183612049565b5f6110e7565b503461050b57602036600319011261050b576020906040906001600160a01b036111d3611fed565b168152601e83522054604051908152f35b503461050b57604036600319011261050b576040611200611fed565b91611209612003565b9260018060a01b031681526007602052209060018060a01b03165f52602052602060405f2054604051908152f35b503461050b578060031936011261050b57602060405162093a808152f35b503461050b57602036600319011261050b576020906040906001600160a01b0361127d611fed565b168152600683522054604051908152f35b503461050b57602036600319011261050b5760206106176112ad611fed565b61289f565b503461050b57606036600319011261050b576004356112cf612003565b6044356001600160a01b03811692909190838303610f9c576040516342f9577960e11b8152602081600481897f000000000000000000000000db9a1bdc443dd11366b8a6dc8038144ecc4d4e236001600160a01b03165af180156113c7576113499187916113a8575b506001600160a01b03163314612448565b61135281612081565b90546001600160a01b039384169360039290921b1c16829003610f9c576113a593610e6792865260176020526040862060ff1981541690558552601760205260408520600160ff19825416179055612081565b80f35b6113c1915060203d602011610970576109628183612049565b5f611338565b6040513d88823e3d90fd5b503461050b578060031936011261050b576040517f000000000000000000000000db9a1bdc443dd11366b8a6dc8038144ecc4d4e236001600160a01b03168152602090f35b503461050b578060031936011261050b57338152600b6020526113a560408220546124dd565b503461050b578060031936011261050b576040517f000000000000000000000000d466e4e05305308beb4ab2cc6c0ca3ec15af81b46001600160a01b03168152602090f35b503461050b57602036600319011261050b5760206106176004356127b3565b503461050b57602036600319011261050b576020906040906001600160a01b036114c9611fed565b168152601a83522054604051908152f35b503461050b57604036600319011261050b576114f4611fed565b61150060243582612d4f565b909160018060a01b031690818452600660205260408420918452600560205260408420555580f35b503461050b57602036600319011261050b576020906040906001600160a01b03611550611fed565b168152600183522054604051908152f35b503461050b57602036600319011261050b576020610617611580611fed565b60018060a01b03165f52600460205260405f205442811090421802421890565b503461050b57604036600319011261050b576115ba611fed565b611500602435826130b1565b503461050b57602036600319011261050b57600435600881101561049757600e01546040516001600160a01b03909116815260209150f35b503461050b57602036600319011261050b5760209060ff906040906001600160a01b03611629611fed565b168152601784522054166040519015158152f35b503461050b578060031936011261050b57600c546040516001600160a01b039091168152602090f35b503461050b578060031936011261050b576040517f000000000000000000000000f3113e4f80c84935e576cfd75f4423e9b911908a6001600160a01b03168152602090f35b503461050b57604036600319011261050b5760406116c7611fed565b916116d0612003565b9260018060a01b031681526008602052209060018060a01b03165f52602052602060405f2054604051908152f35b503461050b578060031936011261050b576040517f000000000000000000000000749ef4ab10aef61151e14c9336b07727ffa5a3236001600160a01b03168152602090f35b503461050b57604036600319011261050b5761175d611fed565b60243567ffffffffffffffff811161048857366023820112156104885780600401359067ffffffffffffffff8211611a80578160051b90604051926117a56020840185612049565b83526024602084019282010190368211611a7c57602401915b818310611a58575050506001601f5403610488576001600160a01b038216903382148015611a26575b15610509576001601f55837f000000000000000000000000f3113e4f80c84935e576cfd75f4423e9b911908a6001600160a01b0316803b15610497578180916024604051809481936363453ae160e01b83523060048401525af1801561048c57611a11575b50506002601f55835b81518110156119b15760019061187d6001600160a01b03611876838661279f565b5116612bb8565b838060a01b0361188d848761279f565b5116885260066020526040882090848060a01b036118ab858861279f565b5116895260056020526040892055556118d585838060a01b036118ce848761279f565b5116612249565b828060a01b036118e5838661279f565b51168752600760205260408720855f5260205260405f20429055828060a01b0361190f838661279f565b5116875260066020526040872054838060a01b0361192d848761279f565b51168852600860205260408820865f5260205260405f205580611990575b828060a01b0361195b838661279f565b5116906040519081527f9aa05b3d70a9e3e2f004f039648839560576334fb45c81f91b6db03ad9e2efc960203392a301611855565b6119ac8187858060a01b036119a5868961279f565b5116612eb8565b61194b565b84611a09858580845260016020526119ce604085205485546120ad565b8455808452600b6020526119f5604085205482865260016020528060408720558554612229565b845583526001602052604083205490612f4b565b610b1161301b565b81611a1b91612049565b61050957835f61184c565b50337f000000000000000000000000f3113e4f80c84935e576cfd75f4423e9b911908a6001600160a01b0316146117e7565b82356001600160a01b0381168103611a78578152602092830192016117be565b8680fd5b8580fd5b634e487b7160e01b84526041600452602484fd5b503461050b57602036600319011261050b5760209060ff906040906001600160a01b03611abf611fed565b168152601884522054166040519015158152f35b503461050b57602036600319011261050b576113a56004356124dd565b503461050b57602036600319011261050b576020906040906001600160a01b03611b18611fed565b168152600583522054604051908152f35b503461050b57602036600319011261050b5780611b44611fed565b6040516342f9577960e11b8152602081600481867f000000000000000000000000db9a1bdc443dd11366b8a6dc8038144ecc4d4e236001600160a01b03165af18015610a4f57611ba59184916113a857506001600160a01b03163314612448565b600c546001600160a01b031690611bbd821515612480565b813b15611c0d57604051635efcc08b60e11b81526001600160a01b0390911660048201529082908290602490829084905af1801561048c57611bfc5750f35b81611c0691612049565b61050b5780f35b5050fd5b503461050b57602036600319011261050b576020906040906001600160a01b03611c39611fed565b168152600383522054604051908152f35b5034610c78576040366003190112610c7857611c64611fed565b90611c6d612003565b6040516342f9577960e11b81529092906020816004815f7f000000000000000000000000db9a1bdc443dd11366b8a6dc8038144ecc4d4e236001600160a01b03165af18015611e9657611cd1915f916113a857506001600160a01b03163314612448565b600c5490611ce86001600160a01b03831615612480565b6001600160a01b0381166001600160a01b0319929092168217600c55813b15610c7857604051635efcc08b60e11b81526001600160a01b0390941660048501525f8460248183865af18015611e9657611e80575b6040516370a0823160e01b81523060048201529293508392907f000000000000000000000000749ef4ab10aef61151e14c9336b07727ffa5a3236001600160a01b0316602083602481845afa928315610f30578593611e49575b5082611da0578480f35b60405163095ea7b360e01b81526001600160a01b03929092166004830152602482018390526020908290604490829088905af1801561097757611e2c575b50813b15611c0d57829160248392604051948593849263b6b55f2560e01b845260048401525af1801561048c57611e17575b8080808480f35b81611e2191612049565b61050b57805f611e10565b611e449060203d602011610a4857610a3b8183612049565b611dde565b945091506020843d602011611e78575b81611e6660209383612049565b81010312610c7857849351915f611d96565b3d9150611e59565b9150915f611e8d91612049565b5f908290611d3c565b6040513d5f823e3d90fd5b34610c78576040366003190112610c78576020610617611ebf611fed565b611ec7612003565b90612249565b34610c78575f366003190112610c78576020600a54604051908152f35b34610c78576040366003190112610c78576020610617611f08611fed565b6024359061210a565b34610c78576040366003190112610c78576001600160a01b03611f32611fed565b165f52601960205260405f206024355f526020526040805f206001815491015482519182526020820152f35b34610c78575f366003190112610c78576040517f000000000000000000000000d0b4a8883769ad37537c7b409daedbc70521603a6001600160a01b03168152602090f35b34610c78576040366003190112610c78576040906001600160a01b03611fc6611fed565b165f52601d602052815f206024355f52602052815f20600181549101549082526020820152f35b600435906001600160a01b0382168203610c7857565b602435906001600160a01b0382168203610c7857565b6040810190811067ffffffffffffffff82111761203557604052565b634e487b7160e01b5f52604160045260245ffd5b90601f8019910116810190811067ffffffffffffffff82111761203557604052565b6040906003190112610c78576004359060243590565b600d5481101561209957600d5f5260205f2001905f90565b634e487b7160e01b5f52603260045260245ffd5b919082039182116120ba57565b634e487b7160e01b5f52601160045260245ffd5b81156120d8570490565b634e487b7160e01b5f52601260045260245ffd5b906040516120f981612019565b602060018294805484520154910152565b6001600160a01b03165f818152601a602052604090205491821561221457815f52601960205260405f20925f19810190811193846120ba57815f526020528160405f2054111561220d57825f52601960205260405f205f80526020528160405f205411612205575f936120ba5791905b8383116121875750505090565b61219d61219485856120ad565b60011c846120ad565b93825f52601960205260405f20855f526020526121bc60405f206120ec565b518281036121cc57505050505090565b918093949592105f146121e35750925b919061217a565b93505f198101908111156121dc57634e487b7160e01b5f52601160045260245ffd5b505050505f90565b9250505090565b5050505f90565b5f1981146120ba5760010190565b919082018092116120ba57565b818102929181159184041417156120ba57565b6001600160a01b038181165f81815260076020908152604080832094871680845294825280832054848452601d8352818420848052835281842054868552601a90935292205493959293909291901561241f5782816122ae941190821802189061210a565b92805f52601a60205260405f20545f198101908082116120ba575f9582612357575b505092612347670de0b6b3a76400009383612354979661234d955f52601960205260405f20905f5260205261230760405f206120ec565b906123226020612318845188612a58565b50930151956129a9565b925f52600860205260405f20905f5260205260405f20548181119082180218906120ad565b90612236565b0490612229565b90565b9692969391906001190181811196875b6120ba5781861161240457885f52601960205260405f20865f5260205261239060405f206120ec565b895f52601960205260405f209160018801928389116120ba5761234d6123f793670de0b6b3a7640000926123fd965f526020526123478c60206123ed6123d860405f206120ec565b926123e4865182612a58565b50935190612a58565b50930151926120ad565b9561221b565b9487612367565b93979396509193509050612347670de0b6b3a76400006122d0565b5050505050505f90565b90816020910312610c7857516001600160a01b0381168103610c785790565b1561244f57565b60405162461bcd60e51b81526020600482015260096024820152686f6e6c79207465616d60b81b6044820152606490fd5b1561248757565b60405162461bcd60e51b81526020600482015260166024820152757374616b696e6720616c72656164792065786973747360501b6044820152606490fd5b90816020910312610c7857518015158103610c785790565b5f905f91335f52600b60205260405f2054821461278a575b6001601f5403610c78576002601f558261250d6132be565b61251983600a546120ad565b600a55335f52600b60205260405f206125338482546120ad565b9055600c546001600160a01b031680612745575b5061257383337f000000000000000000000000749ef4ab10aef61151e14c9336b07727ffa5a323612eb8565b156127315733815260096020526040812054830361050b573381526009602052604081208190557f000000000000000000000000f3113e4f80c84935e576cfd75f4423e9b911908a6001600160a01b0316803b156104975760405163411b1f7760e01b8152600481018590523360248201529082908290604490829084905af1801561048c5790829161271c575b50505b338152600160205261261b604082205482546120ad565b8155338152600b602052612642604082205433835260016020528060408420558254612229565b8155338152600160205261265a604082205433612f4b565b61266261301b565b7f000000000000000000000000f3113e4f80c84935e576cfd75f4423e9b911908a6001600160a01b0316803b1561049757604051633aa53b9160e21b815260048101859052336024820152604481018490529082908290606490829084905af1801561048c57612707575b505060405191825260208201527ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b56860403392a26001601f55565b612712828092612049565b61050b57806126cd565b8161272691612049565b61050b57805f612601565b338152600960205260408120549250612604565b803b15610c78575f8091602460405180948193632e1a7d4d60e01b83528960048401525af18015611e965715612547576127829192505f90612049565b5f905f612547565b9150335f52600960205260405f2054916124f5565b80518210156120995760209160051b010190565b601c54908115612899575f19820191821191826120ba57805f52601b6020528160405f20541115612893575f8052601b6020527f584f46c60af19681376031579adb04a2416e54ee5505351c2a8435e3766026ea548210612214575f926120ba57905b82821161282257505090565b61283861282f84846120ad565b60011c836120ad565b92835f52601b60205261284d60405f206120ec565b5182810361285c575050505090565b9180939492105f146128715750915b90612816565b92505f1981019081111561286b57634e487b7160e01b5f52601160045260245ffd5b91505090565b50505f90565b6001600160a01b03165f818152600460205260409020544210156128ea5780612354915f5260046020526128d74260405f20546120ad565b905f52600360205260405f205490612236565b505f90565b6040516342f9577960e11b81526020816004815f7f000000000000000000000000db9a1bdc443dd11366b8a6dc8038144ecc4d4e236001600160a01b03165af18015611e9657612950915f916113a857506001600160a01b03163314612448565b600c546001600160a01b031680156129a657803b15610c78575f8091604460405180948193639faceb1b60e01b83523060048401528160248401525af18015611e965761299a5750565b5f6129a491612049565b565b50565b5f54908115612a3c576001600160a01b03165f81815260066020908152604080832054600480845282852054600585529290942054939092529092612a089290916128d7918082188183100218904281811191811891909102186120ad565b670de0b6b3a7640000810290808204670de0b6b3a764000014901517156120ba5761235492612a36916120ce565b90612229565b6001600160a01b03165f90815260066020526040902054919050565b6001600160a01b03165f818152601e60205260409020549092918115612bae57835f52601d60205260405f20915f19810190811192836120ba57815f526020528160405f20541115612b8657845f52601d60205260405f205f80526020528160405f205411612b7b575f926120ba57905b828211612af65750505f928352601d60209081526040808520928552919052909120600181015490549091565b612b0661282f84849795976120ad565b835f52601d60205260405f20815f52602052612b2460405f206120ec565b9586518381145f14612b40575050505050506020820151915190565b839495975092909192105f14612b595750915b90612ac9565b92505f19810190811115612b5357634e487b7160e01b5f52601160045260245ffd5b50505090505f905f90565b5f948552601d6020908152604080872092875291905290932060018101549054909350919050565b505090505f905f90565b9060018060a01b038216805f52600560205260405f205492815f52600660205260405f205491601c54908115612c36575f52600360205260405f205415612d4557612c02856127b3565b5f19820191908183116120ba5782612c9d575b50505f52601b602052612c2a60405f206120ec565b60208101908151612c3d575b5050509190565b8295612c939492612c8392612c6f612c8a9660018060a01b03165f52600460205260405f205442811090421802421890565b905191519180841184821802189089613314565b5090612229565b9283429161319d565b42915f8080612c36565b9491906001190181811195865b6120ba57818111612d3957805f52601b602052612cc960405f206120ec565b602081018051612ce5575b5050612cdf9061221b565b86612caa565b90919860018a0190818b116120ba57612cdf93612d2593612d1f935f52601b602052612d1360405f206120ec565b5191519051918a613314565b97612229565b95612d3181888861319d565b97905f612cd4565b50509093505f80612c15565b5050909150904290565b919060018060a01b038316805f52600560205260405f205493815f52600660205260405f205492601c54928315612e71575f52600360205260405f205415612e6657612d9a866127b3565b905f1984019384116120ba57838110908418028084189303612dbd575050509190565b5f19830192831194919290855b6120ba57818111612e5957805f52601b602052612de960405f206120ec565b602081018051612e05575b5050612dff9061221b565b85612dca565b9091976001890190818a116120ba57612dff93612e4593612e3f935f52601b602052612e3360405f206120ec565b51915190519189613314565b96612229565b94612e5181878761319d565b96905f612df4565b50509250505f8080612c36565b505050909150904290565b505050509190565b3d15612eb3573d9067ffffffffffffffff82116120355760405191612ea8601f8201601f191660200184612049565b82523d5f602084013e565b606090565b919091803b15610c785760405163a9059cbb60e01b602082019081526001600160a01b039490941660248201526044808201939093529182525f9283928390612f02606482612049565b51925af1612f0e612e79565b81612f1c575b5015610c7857565b8051801592508215612f31575b50505f612f14565b612f4492506020809183010191016124c5565b5f80612f29565b6001600160a01b03165f818152601a60205260409020549081151580612ff2575b15612f97575f52601960205260405f20905f1981019081116120ba575f52602052600160405f200155565b9091612fd99060405190612faa82612019565b4282526020820152825f52601960205260405f20845f5260205260405f20906020600191805184550151910155565b600182018092116120ba575f52601a60205260405f2055565b50805f52601960205260405f205f1983018381116120ba575f526020524260405f205414612f6c565b601c5480151580613092575b1561304b575f54905f1981019081116120ba575f52601b602052600160405f200155565b6130825f546040519061305d82612019565b4282526020820152825f52601b60205260405f20906020600191805184550151910155565b600181018091116120ba57601c55565b505f1981018181116120ba575f52601b6020524260405f205414613027565b919060018060a01b03831690815f52600560205260405f205493825f52600660205260405f205492601c54908115612e71575f52600360205260405f205415612e66576130fd866127b3565b925f1982019182116120ba578181109082180218915b828110613121575050509190565b805f52601b60205261313560405f206120ec565b60208101805161314a575b5050600101613113565b90919660018801908189116120ba5760019361318993613183935f52601b60205261317760405f206120ec565b51915190519187613314565b95612229565b9361319581868561319d565b95905f613140565b6001600160a01b03165f818152601e6020526040902054919282151580613245575b156131eb57505f52601d60205260405f20905f1981019081116120ba575f52602052600160405f200155565b61322c919293604051916131fe83612019565b82526020820152825f52601d60205260405f20845f5260205260405f20906020600191805184550151910155565b600182018092116120ba575f52601e60205260405f2055565b50815f52601d60205260405f205f1984018481116120ba575f526020528060405f2054146131bf565b90813b15610c78576040516323b872dd60e01b602082019081526001600160a01b0392831660248301529190931660448401526064808401949094529282525f9283928390612f02608482612049565b600d545f5b8181106132ce575050565b806132da600192612081565b838060a01b0391549060031b1c166132f181612bb8565b825f93929352600660205260405f20915f52600560205260405f205555016132c3565b6001600160a01b03165f818152600460205260409020548286188387110290921895946133659391926128d792808318928110929092029091188082188183100218908088189088110287186120ad565b90670de0b6b3a7640000820291808304670de0b6b3a764000014901517156120ba57613390916120ce565b919056fea264697066735822122045575e00b1ee184ccf22d57f3cba5c2cbc6989d7c0ca3050ed9db5fbce5e22ea64736f6c634300081c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000749ef4ab10aef61151e14c9336b07727ffa5a3230000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d466e4e05305308beb4ab2cc6c0ca3ec15af81b4000000000000000000000000d0b4a8883769ad37537c7b409daedbc70521603a000000000000000000000000db9a1bdc443dd11366b8a6dc8038144ecc4d4e23000000000000000000000000f3113e4f80c84935e576cfd75f4423e9b911908a0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000030000000000000000000000008ff0dd9f9c40a0d76ef1bcfaf5f98c1610c74bd8000000000000000000000000555555555555555555555555555555555555555500000000000000000000000028245ab01298eaef7933bc90d35bd9dbca5c89db
-----Decoded View---------------
Arg [0] : _stake (address): 0x749eF4ab10aef61151E14C9336B07727ffA5a323
Arg [1] : _staking (address): 0x0000000000000000000000000000000000000000
Arg [2] : _internal_bribe (address): 0xd466e4e05305308BEB4Ab2cC6C0Ca3EC15aF81B4
Arg [3] : _external_bribe (address): 0xD0B4A8883769Ad37537c7B409DaedbC70521603a
Arg [4] : __ve (address): 0xdB9A1bdc443dd11366b8a6dc8038144eCc4D4E23
Arg [5] : _voter (address): 0xF3113E4F80c84935E576CFD75F4423E9B911908A
Arg [6] : _forPair (bool): True
Arg [7] : _allowedRewardTokens (address[]): 0x8fF0dd9f9C40a0d76eF1BcFAF5f98c1610c74Bd8,0x5555555555555555555555555555555555555555,0x28245AB01298eaEf7933bC90d35Bd9DbCA5C89DB
-----Encoded View---------------
12 Constructor Arguments found :
Arg [0] : 000000000000000000000000749ef4ab10aef61151e14c9336b07727ffa5a323
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [2] : 000000000000000000000000d466e4e05305308beb4ab2cc6c0ca3ec15af81b4
Arg [3] : 000000000000000000000000d0b4a8883769ad37537c7b409daedbc70521603a
Arg [4] : 000000000000000000000000db9a1bdc443dd11366b8a6dc8038144ecc4d4e23
Arg [5] : 000000000000000000000000f3113e4f80c84935e576cfd75f4423e9b911908a
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000100
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000003
Arg [9] : 0000000000000000000000008ff0dd9f9c40a0d76ef1bcfaf5f98c1610c74bd8
Arg [10] : 0000000000000000000000005555555555555555555555555555555555555555
Arg [11] : 00000000000000000000000028245ab01298eaef7933bc90d35bd9dbca5c89db
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in HYPE
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
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.