Source Code
Latest 25 from a total of 251 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Withdraw | 16436535 | 104 days ago | IN | 0 HYPE | 0.00011327 | ||||
| Withdraw | 15950849 | 109 days ago | IN | 0 HYPE | 0.0004911 | ||||
| Withdraw | 14779030 | 122 days ago | IN | 0 HYPE | 0.00011264 | ||||
| Withdraw | 14671300 | 124 days ago | IN | 0 HYPE | 0.00573015 | ||||
| Withdraw | 14664837 | 124 days ago | IN | 0 HYPE | 0.00096792 | ||||
| Withdraw | 14583271 | 125 days ago | IN | 0 HYPE | 0.00116274 | ||||
| Withdraw | 14485019 | 126 days ago | IN | 0 HYPE | 0.00003384 | ||||
| Withdraw | 14304188 | 128 days ago | IN | 0 HYPE | 0.0000317 | ||||
| Withdraw | 14271053 | 128 days ago | IN | 0 HYPE | 0.00032967 | ||||
| Withdraw | 14238938 | 129 days ago | IN | 0 HYPE | 0.00163585 | ||||
| Deposit | 14212535 | 129 days ago | IN | 0 HYPE | 0.00004337 | ||||
| Withdraw | 14208810 | 129 days ago | IN | 0 HYPE | 0.00003362 | ||||
| Withdraw | 14157512 | 130 days ago | IN | 0 HYPE | 0.00020443 | ||||
| Deposit | 14148653 | 130 days ago | IN | 0 HYPE | 0.00004045 | ||||
| Deposit | 14148567 | 130 days ago | IN | 0 HYPE | 0.00003643 | ||||
| Deposit | 14148518 | 130 days ago | IN | 0 HYPE | 0.00003902 | ||||
| Deposit | 14148489 | 130 days ago | IN | 0 HYPE | 0.00003419 | ||||
| Deposit | 14148461 | 130 days ago | IN | 0 HYPE | 0.00003784 | ||||
| Deposit | 14148434 | 130 days ago | IN | 0 HYPE | 0.00003438 | ||||
| Deposit | 14148412 | 130 days ago | IN | 0 HYPE | 0.00003349 | ||||
| Deposit | 14140859 | 130 days ago | IN | 0 HYPE | 0.00139753 | ||||
| Deposit | 14140257 | 130 days ago | IN | 0 HYPE | 0.00854014 | ||||
| Deposit | 14140218 | 130 days ago | IN | 0 HYPE | 0.00234021 | ||||
| Deposit | 14118442 | 130 days ago | IN | 0 HYPE | 0.00169831 | ||||
| Deposit | 14039621 | 131 days ago | IN | 0 HYPE | 0.00003195 |
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 5521186 | 228 days ago | Contract Creation | 0 HYPE |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
GaugeV2
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 {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.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 GaugeV2 is IGauge, SystemEpoch {
using SafeERC20 for IERC20;
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 rewards;
mapping(address => bool) public isReward;
/// @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;
uint256 internal _unlocked = 1;
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);
error Reentrancy();
constructor(
address _stake,
address _internalBribe,
address _externalBribe,
address _ve,
address _voter,
address[] memory _allowedRewardTokens
) {
stake = _stake;
internal_bribe = _internalBribe;
external_bribe = _externalBribe;
ve = _ve;
voter = _voter;
for (uint256 i; i < _allowedRewardTokens.length; i++) {
if (_allowedRewardTokens[i] != address(0)) {
isReward[_allowedRewardTokens[i]] = true;
rewards.push(_allowedRewardTokens[i]);
}
}
}
modifier lock() {
if (_unlocked != 1) {
revert Reentrancy();
}
_unlocked = 2;
_;
_unlocked = 1;
}
/**
* @notice Determine the prior balance for an account as of a block number
* @dev Block number must be a finalized block or else this function will revert to prevent misinformation.
* @param 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) IERC20(tokens[i]).safeTransfer(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, "amount > 0");
_updateRewardForAllTokens();
IERC20(stake).safeTransferFrom(msg.sender, address(this), amount);
totalSupply += amount;
balanceOf[msg.sender] += amount;
if (tokenId > 0) {
require(IVotingEscrow(ve).ownerOf(tokenId) == msg.sender, "not owner");
if (tokenIds[msg.sender] == 0) {
tokenIds[msg.sender] = tokenId;
IVoter(voter).attachTokenToGauge(tokenId, msg.sender);
}
require(tokenIds[msg.sender] == tokenId, "invalid token id");
} 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;
IERC20(stake).safeTransfer(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, "invalid reward");
require(amount > 0, "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]) {
IERC20(token).safeTransferFrom(msg.sender, address(this), amount);
rewardRate[token] = amount / EPOCH;
} else {
uint256 _remaining = periodFinish[token] - block.timestamp;
uint256 _left = _remaining * rewardRate[token];
require(amount > _left, "amount > _left");
IERC20(token).safeTransferFrom(msg.sender, address(this), amount);
rewardRate[token] = (amount + _left) / EPOCH;
}
require(rewardRate[token] > 0, "reward rate is 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;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol)
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";
/**
* @title IERC1363
* @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
*
* Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
* after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
*/
interface IERC1363 is IERC20, IERC165 {
/*
* Note: the ERC-165 identifier for this interface is 0xb0202a11.
* 0xb0202a11 ===
* bytes4(keccak256('transferAndCall(address,uint256)')) ^
* bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
* bytes4(keccak256('approveAndCall(address,uint256)')) ^
* bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
*/
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @param data Additional data with no specified format, sent in call to `spender`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../utils/introspection/IERC165.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../token/ERC20/IERC20.sol";// 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
// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC-20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
/**
* @dev An operation with an ERC-20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {
return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {
return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*
* NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
* only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
* set here.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
safeTransfer(token, to, value);
} else if (!token.transferAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
* has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferFromAndCallRelaxed(
IERC1363 token,
address from,
address to,
uint256 value,
bytes memory data
) internal {
if (to.code.length == 0) {
safeTransferFrom(token, from, to, value);
} else if (!token.transferFromAndCall(from, to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
* Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
* once without retrying, and relies on the returned value to be true.
*
* Reverts if the returned value is other than `true`.
*/
function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
forceApprove(token, to, value);
} else if (!token.approveAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
// bubble errors
if iszero(success) {
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize())
revert(ptr, returndatasize())
}
returnSize := returndatasize()
returnValue := mload(0)
}
if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
bool success;
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
returnSize := returndatasize()
returnValue := mload(0)
}
return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[ERC].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view 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":"_internalBribe","type":"address"},{"internalType":"address","name":"_externalBribe","type":"address"},{"internalType":"address","name":"_ve","type":"address"},{"internalType":"address","name":"_voter","type":"address"},{"internalType":"address[]","name":"_allowedRewardTokens","type":"address[]"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"Reentrancy","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"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":[{"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":[{"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":[],"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"},{"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":[],"name":"stake","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":"ve","outputs":[{"internalType":"address","name":"","type":"address"}],"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
6101206040523461029c5761307e8038038061001a816102a0565b92833981019060c08183031261029c57610033816102c5565b61003f602083016102c5565b61004b604084016102c5565b90610058606085016102c5565b92610065608086016102c5565b60a086015190956001600160401b03821161029c57019580601f8801121561029c578651966001600160401b0388116101c3578760051b906020806100ab8185016102a0565b809b8152019282010192831161029c57602001905b82821061028457505050600160145560805260c05260e05260a052610100525f5b81518110156101d7576001600160a01b036100fc82846102d9565b511661010b575b6001016100e1565b6001600160a01b0361011d82846102d9565b51165f908152600d60205260409020805460ff191660011790556001600160a01b0361014982846102d9565b511690600c5491680100000000000000008310156101c3576001830180600c558310156101af57600c5f527fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c790920180546001600160a01b031916909217909155610103565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52604160045260245ffd5b604051612d9090816102ee82396080518181816102630152818161063201528181610a2801528181610b1e015281816115bf0152611ffc015260a0518181816106a8015281816112210152611a26015260c0518161135f015260e05181611afb0152610100518181816102ba015281816103800152818161076e0152818161087101528181610f7d015281816115270152818161169e015281816118e60152818161205201526121160152f35b60208091610291846102c5565b8152019101906100c0565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176101c357604052565b51906001600160a01b038216820361029c57565b80518210156101af5760209160051b01019056fe6080806040526004361015610012575f80fd5b5f905f3560e01c90816301316ddf14611b2a5750806303fbf83a14611ae65780630cdfebfa14611a99578063115c6f3914611a7257806318160ddd14611a555780631f85071614611a11578063211dc32d146119e5578063221ca18c146119ad5780632ce9aead146119755780632e1a7d4d1461195757806331279d3d146115ee5780633a4b66f1146115a95780633ca068b61461155657806346c96aac146115115780634d5ce038146114d25780635a45d052146114ac578063638634ee1461146d57806363fb415b1461143457806368fcee1a146113e65780636fcfff45146113ad57806370a08231146109c457806376f4be361461138e578063770f857114611349578063853828b6146113235780639418f939146111d657806399bcc052146111b25780639ce43f9014611179578063a0dc27581461115b578063a495e5b514611108578063aa479652146110cf578063b66503cf14610ae3578063c6f678bd146109fd578063d35e2544146109c4578063d7da4bb0146109a7578063da09d19d1461096e578063e2bbb158146105f7578063e5748213146105d4578063e6886396146105b6578063e8111a1214610598578063f12297771461056c578063f301af4214610528578063f7412baf146104f4578063fc97a303146104bb578063fd314098146104875763fdb483c71461020d575f80fd5b346104845761021b36611bdf565b9060016014540361047557600260145581610234612c2c565b61024082600a54611c21565b600a55338452600b6020526040842061025a838254611c21565b905561029082337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316612883565b156104615733835260096020526040832054820361043957338352600960205260408320839055827f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b156104485760405163411b1f7760e01b8152600481018590523360248201529082908290604490829084905af1801561043d5761044c575b50505b338352600160205261033660408420548454611c21565b8355338352600b60205261035d604084205433855260016020528060408620558454611d9d565b835533835260016020526103756040842054336128c5565b61037d612995565b827f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b1561044857604051633aa53b9160e21b815260048101859052336024820152604481018490529082908290606490829084905af1801561043d57610424575b505060405191825260208201527ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b56860403392a2600160145580f35b8161042e91611bbd565b61043957825f6103e9565b8280fd5b6040513d84823e3d90fd5b5080fd5b8161045691611bbd565b61043957825f61031c565b33835260096020526040832054915061031f565b63558a1e0360e11b8352600483fd5b80fd5b50346104845760403660031901126104845760406104af6104a6611b75565b60243590612462565b82519182526020820152f35b5034610484576020366003190112610484576020906040906001600160a01b036104e3611b75565b168152600983522054604051908152f35b5034610484576020366003190112610484576040809160043581526010602052206001815491015482519182526020820152f35b50346104845760203660031901126104845760043590600c5482101561048457602061055383611bf5565b905460405160039290921b1c6001600160a01b03168152f35b503461048457602036600319011261048457602061059061058b611b75565b6123b3565b604051908152f35b50346104845780600319360112610484576020601154604051908152f35b50346104845780600319360112610484576020600c54604051908152f35b5034610484578060031936011261048457602060ff600254166040519015158152f35b50346104845761060636611bdf565b906001601454036104755760026014558161062282151561237a565b61062a612c2c565b61065f8230337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316612be8565b61066b82600a54611d9d565b600a55338452600b60205260408420610685838254611d9d565b90551561095a576040516331a9108f60e11b8152600481018390526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811561094f578491610920575b50336001600160a01b03909116036108ef57338352600960205260408320541561085f575b338352600960205281604084205403610827575b338352600160205261073060408420548454611c21565b8355338352600b6020526107636040842054338552600160205280604086205561075b818654611d9d565b8555336128c5565b61076b612995565b827f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b156104485760405163530e389d60e11b815260048101859052336024820152604481018490529082908290606490829084905af1801561043d57610812575b505060405191825260208201527f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a1560403392a2600160145580f35b8161081c91611bbd565b61043957825f6107d7565b60405162461bcd60e51b815260206004820152601060248201526f1a5b9d985b1a59081d1bdad95b881a5960821b6044820152606490fd5b338352600960205260408320829055827f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b156104485760405163698473e360e01b8152600481018590523360248201529082908290604490829084905af1801561043d576108da575b5050610705565b816108e491611bbd565b61043957825f6108d3565b60405162461bcd60e51b81526020600482015260096024820152683737ba1037bbb732b960b91b6044820152606490fd5b610942915060203d602011610948575b61093a8183611bbd565b81019061230b565b5f6106e0565b503d610930565b6040513d86823e3d90fd5b338352600960205260408320549150610719565b5034610484576020366003190112610484576020906040906001600160a01b03610996611b75565b168152600483522054604051908152f35b503461048457806003193601126104845760209054604051908152f35b5034610484576020366003190112610484576020906040906001600160a01b036109ec611b75565b168152600b83522054604051908152f35b5034610484576020366003190112610484576040516370a0823160e01b8152336004828101919091527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316919035602082602481865afa91821561094f578492610aab575b50600160145403610a9c57600260145561065f828294610a8b82151561237a565b610a93612c2c565b30903390612be8565b63558a1e0360e11b8452600484fd5b9091506020813d602011610adb575b81610ac760209383611bbd565b81010312610ad75751905f610a6a565b5f80fd5b3d9150610aba565b503461048457604036600319011261048457610afd611b75565b6024356001601454036104755760026014556001600160a01b0382811692907f000000000000000000000000000000000000000000000000000000000000000016831461109957610b4f82151561237a565b828452600d60205260ff60408520541615610f61575b8284526003602052604084205415610e6e575b610b81816125c2565b848652600660205260408620908587526005602052604087205555828452600460205260408420544210155f14610dd757610bbe82303386612be8565b828452600360205262093a80820460408520555b8284526003602052604084205415610d9f576040516370a0823160e01b8152306004820152602081602481875afa908115610d94578591610d62575b50838552600360205262093a806040862054910410610d1d5762093a804201804211610d095783855260046020526040852055828452600d60205260ff60408520541615610c8c575b506040519081527ff70d5c697de7ea828df48e5c4573cb2194c659f1901f70110c52b066dcf5082660203392a3600160145580f35b828452600d60205260408420805460ff19166001179055600c5468010000000000000000811015610cf55790610ccb826001610cef9401600c55611bf5565b81546001600160a01b0393841660039290921b91821b9390911b1916919091179055565b5f610c57565b634e487b7160e01b85526041600452602485fd5b634e487b7160e01b85526011600452602485fd5b60405162461bcd60e51b815260206004820152601860248201527f50726f76696465642072657761726420746f6f206869676800000000000000006044820152606490fd5b90506020813d602011610d8c575b81610d7d60209383611bbd565b81010312610ad757515f610c0e565b3d9150610d70565b6040513d87823e3d90fd5b60405162461bcd60e51b815260206004820152601060248201526f0726577617264207261746520697320360841b6044820152606490fd5b8284526004602052610e03610df0426040872054611c21565b8486526003602052604086205490611daa565b80831115610e3857610e2562093a8091610e1f85303389612be8565b84611d9d565b0483855260036020526040852055610bd2565b60405162461bcd60e51b815260206004820152600e60248201526d185b5bdd5b9d080f8817db19599d60921b6044820152606490fd5b8284526013602052604084205480151580610f24575b15610ec857838552601260205260408520905f198101908111610eb4578552602052836001604082200155610b78565b634e487b7160e01b86526011600452602486fd5b610f07604051610ed781611ba1565b42815286602082015285875260126020526040872083885260205260408720906020600191805184550151910155565b60018101809111610d095783855260136020526040852055610b78565b508385526012602052604085205f198201828111610f4d57865260205242604086205414610e84565b634e487b7160e01b87526011600452602487fd5b604051633af32abf60e01b8152600481018490526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610d9457859161105a575b501561100a576010600c5410610b655760405162461bcd60e51b815260206004820152601760248201527f746f6f206d616e79207265776172647320746f6b656e730000000000000000006044820152606490fd5b60405162461bcd60e51b815260206004820152602260248201527f7265776172647320746f6b656e73206d7573742062652077686974656c697374604482015261195960f21b6064820152608490fd5b90506020813d602011611091575b8161107560209383611bbd565b8101031261108d5751801515810361108d575f610fb5565b8480fd5b3d9150611068565b60405162461bcd60e51b815260206004820152600e60248201526d1a5b9d985b1a59081c995dd85c9960921b6044820152606490fd5b5034610484576020366003190112610484576020906040906001600160a01b036110f7611b75565b168152601383522054604051908152f35b5034610484576040366003190112610484576040611124611b75565b9161112d611b8b565b9260018060a01b031681526007602052209060018060a01b03165f52602052602060405f2054604051908152f35b5034610484578060031936011261048457602060405162093a808152f35b5034610484576020366003190112610484576020906040906001600160a01b036111a1611b75565b168152600683522054604051908152f35b50346104845760203660031901126104845760206105906111d1611b75565b61232a565b5034610484576060366003190112610484576004356111f3611b8b565b6044356001600160a01b0381169290919083830361108d576040516342f9577960e11b8152602081600481897f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af19081156113185786916112f9575b506001600160a01b031633036112c85761127281611bf5565b90546001600160a01b039384169360039290921b1c1682900361108d576112c593610ccb928652600d6020526040862060ff1981541690558552600d60205260408520600160ff19825416179055611bf5565b80f35b60405162461bcd60e51b81526020600482015260096024820152686f6e6c79207465616d60b81b6044820152606490fd5b611312915060203d6020116109485761093a8183611bbd565b5f611259565b6040513d88823e3d90fd5b5034610484578060031936011261048457338152600b6020526112c56040822054611f9d565b50346104845780600319360112610484576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b503461048457602036600319011261048457602061059060043561221f565b5034610484576020366003190112610484576020906040906001600160a01b036113d5611b75565b168152600f83522054604051908152f35b503461048457604036600319011261048457611400611b75565b61140c60243582612759565b909160018060a01b031690818452600660205260408420918452600560205260408420555580f35b5034610484576020366003190112610484576020906040906001600160a01b0361145c611b75565b168152600183522054604051908152f35b503461048457602036600319011261048457602061059061148c611b75565b60018060a01b03165f52600460205260405f205442811090421802421890565b5034610484576040366003190112610484576114c6611b75565b61140c60243582612a2b565b50346104845760203660031901126104845760209060ff906040906001600160a01b036114fd611b75565b168152600d84522054166040519015158152f35b50346104845780600319360112610484576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b5034610484576040366003190112610484576040611572611b75565b9161157b611b8b565b9260018060a01b031681526008602052209060018060a01b03165f52602052602060405f2054604051908152f35b50346104845780600319360112610484576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b5034610ad7576040366003190112610ad757611608611b75565b60243567ffffffffffffffff8111610ad75736602382011215610ad75780600401359067ffffffffffffffff8211611943578160051b90604051926116506020840185611bbd565b83526024602084019282010190368211610ad757602401915b81831061192357505050600160145403611914576001600160a01b0382169033821480156118e2575b15610ad75760016014557f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b15610ad7575f80916024604051809481936363453ae160e01b83523060048401525af180156118d7576118c2575b506002601455835b815181101561185a576001906117266001600160a01b0361171f838661220b565b51166125c2565b838060a01b03611736848761220b565b5116885260066020526040882090848060a01b03611754858861220b565b51168952600560205260408920555561177e85838060a01b03611777848761220b565b5116611dbd565b828060a01b0361178e838661220b565b51168752600760205260408720855f5260205260405f20429055828060a01b036117b8838661220b565b5116875260066020526040872054838060a01b036117d6848761220b565b51168852600860205260408820865f5260205260405f205580611839575b828060a01b03611804838661220b565b5116906040519081527f9aa05b3d70a9e3e2f004f039648839560576334fb45c81f91b6db03ad9e2efc960203392a3016116fe565b6118558187858060a01b0361184e868961220b565b5116612883565b6117f4565b846118b28585808452600160205261187760408520548554611c21565b8455808452600b60205261189e604085205482865260016020528060408720558554611d9d565b8455835260016020526040832054906128c5565b6118ba612995565b600160145580f35b6118cf9194505f90611bbd565b5f925f6116f6565b6040513d5f823e3d90fd5b50337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614611692565b63558a1e0360e11b5f5260045ffd5b82356001600160a01b0381168103610ad757815260209283019201611669565b634e487b7160e01b5f52604160045260245ffd5b34610ad7576020366003190112610ad757611973600435611f9d565b005b34610ad7576020366003190112610ad7576001600160a01b03611996611b75565b165f526005602052602060405f2054604051908152f35b34610ad7576020366003190112610ad7576001600160a01b036119ce611b75565b165f526003602052602060405f2054604051908152f35b34610ad7576040366003190112610ad7576020610590611a03611b75565b611a0b611b8b565b90611dbd565b34610ad7575f366003190112610ad7576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b34610ad7575f366003190112610ad7576020600a54604051908152f35b34610ad7576040366003190112610ad7576020610590611a90611b75565b60243590611c7e565b34610ad7576040366003190112610ad7576001600160a01b03611aba611b75565b165f52600e60205260405f206024355f526020526040805f206001815491015482519182526020820152f35b34610ad7575f366003190112610ad7576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b34610ad7576040366003190112610ad7576040906001600160a01b03611b4e611b75565b165f526012602052815f206024355f52602052815f20600181549101549082526020820152f35b600435906001600160a01b0382168203610ad757565b602435906001600160a01b0382168203610ad757565b6040810190811067ffffffffffffffff82111761194357604052565b90601f8019910116810190811067ffffffffffffffff82111761194357604052565b6040906003190112610ad7576004359060243590565b600c54811015611c0d57600c5f5260205f2001905f90565b634e487b7160e01b5f52603260045260245ffd5b91908203918211611c2e57565b634e487b7160e01b5f52601160045260245ffd5b8115611c4c570490565b634e487b7160e01b5f52601260045260245ffd5b90604051611c6d81611ba1565b602060018294805484520154910152565b6001600160a01b03165f818152600f6020526040902054918215611d8857815f52600e60205260405f20925f1981019081119384611c2e57815f526020528160405f20541115611d8157825f52600e60205260405f205f80526020528160405f205411611d79575f93611c2e5791905b838311611cfb5750505090565b611d11611d088585611c21565b60011c84611c21565b93825f52600e60205260405f20855f52602052611d3060405f20611c60565b51828103611d4057505050505090565b918093949592105f14611d575750925b9190611cee565b93505f19810190811115611d5057634e487b7160e01b5f52601160045260245ffd5b505050505f90565b9250505090565b5050505f90565b5f198114611c2e5760010190565b91908201809211611c2e57565b81810292918115918404141715611c2e57565b6001600160a01b038181165f8181526007602090815260408083209487168084529482528083205484845260128352818420848052835281842054868552600f909352922054939592939092919015611f93578281611e229411908218021890611c7e565b92805f52600f60205260405f20545f19810190808211611c2e575f9582611ecb575b505092611ebb670de0b6b3a76400009383611ec89796611ec1955f52600e60205260405f20905f52602052611e7b60405f20611c60565b90611e966020611e8c845188612462565b50930151956123b3565b925f52600860205260405f20905f5260205260405f2054818111908218021890611c21565b90611daa565b0490611d9d565b90565b9692969391906001190181811196875b611c2e57818611611f7857885f52600e60205260405f20865f52602052611f0460405f20611c60565b895f52600e60205260405f20916001880192838911611c2e57611ec1611f6b93670de0b6b3a764000092611f71965f52602052611ebb8c6020611f61611f4c60405f20611c60565b92611f58865182612462565b50935190612462565b5093015192611c21565b95611d8f565b9487611edb565b93979396509193509050611ebb670de0b6b3a7640000611e44565b5050505050505f90565b5f905f91335f52600b60205260405f205482146121f6575b60016014540361191457600260145582611fcd612c2c565b611fd983600a54611c21565b600a55335f52600b60205260405f20611ff3848254611c21565b905561202983337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316612883565b156121e157335f52600960205260405f20548303610ad757335f908152600960205260408120557f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b15610ad75760405163411b1f7760e01b815260048101859052336024820152905f908290604490829084905af180156118d7576121ce575b505b33815260016020526120cd60408220548254611c21565b8155338152600b6020526120f4604082205433835260016020528060408420558254611d9d565b8155338152600160205261210c6040822054336128c5565b612114612995565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b1561044857604051633aa53b9160e21b815260048101859052336024820152604481018490529082908290606490829084905af1801561043d576121b9575b505060405191825260208201527ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b56860403392a26001601455565b6121c4828092611bbd565b610484578061217f565b6121da91505f90611bbd565b5f5f6120b4565b9150335f52600960205260405f2054916120b6565b9150335f52600960205260405f205491611fb5565b8051821015611c0d5760209160051b010190565b601154908115612305575f1982019182119182611c2e57805f5260106020528160405f205411156122ff575f805260106020527f6e0956cda88cad152e89927e53611735b61a5c762d1428573c6931b0a5efcb01548210611d88575f92611c2e57905b82821161228e57505090565b6122a461229b8484611c21565b60011c83611c21565b92835f5260106020526122b960405f20611c60565b518281036122c8575050505090565b9180939492105f146122dd5750915b90612282565b92505f198101908111156122d757634e487b7160e01b5f52601160045260245ffd5b91505090565b50505f90565b90816020910312610ad757516001600160a01b0381168103610ad75790565b6001600160a01b03165f818152600460205260409020544210156123755780611ec8915f5260046020526123624260405f2054611c21565b905f52600360205260405f205490611daa565b505f90565b1561238157565b60405162461bcd60e51b815260206004820152600a6024820152690616d6f756e74203e20360b41b6044820152606490fd5b5f54908115612446576001600160a01b03165f8181526006602090815260408083205460048084528285205460058552929094205493909252909261241292909161236291808218818310021890428181119181189190910218611c21565b670de0b6b3a7640000810290808204670de0b6b3a76400001490151715611c2e57611ec89261244091611c42565b90611d9d565b6001600160a01b03165f90815260066020526040902054919050565b6001600160a01b03165f8181526013602052604090205490929181156125b857835f52601260205260405f20915f1981019081119283611c2e57815f526020528160405f2054111561259057845f52601260205260405f205f80526020528160405f205411612585575f92611c2e57905b8282116125005750505f928352601260209081526040808520928552919052909120600181015490549091565b61251061229b8484979597611c21565b835f52601260205260405f20815f5260205261252e60405f20611c60565b9586518381145f1461254a575050505050506020820151915190565b839495975092909192105f146125635750915b906124d3565b92505f1981019081111561255d57634e487b7160e01b5f52601160045260245ffd5b50505090505f905f90565b5f94855260126020908152604080872092875291905290932060018101549054909350919050565b505090505f905f90565b9060018060a01b038216805f52600560205260405f205492815f52600660205260405f205491601154908115612640575f52600360205260405f20541561274f5761260c8561221f565b5f1982019190818311611c2e57826126a7575b50505f52601060205261263460405f20611c60565b60208101908151612647575b5050509190565b829561269d949261268d926126796126949660018060a01b03165f52600460205260405f205442811090421802421890565b905191519180841184821802189089612c82565b5090611d9d565b92834291612b17565b42915f8080612640565b9491906001190181811195865b611c2e5781811161274357805f5260106020526126d360405f20611c60565b6020810180516126ef575b50506126e990611d8f565b866126b4565b90919860018a0190818b11611c2e576126e99361272f93612729935f52601060205261271d60405f20611c60565b5191519051918a612c82565b97611d9d565b9561273b818888612b17565b97905f6126de565b50509093505f8061261f565b5050909150904290565b919060018060a01b038316805f52600560205260405f205493815f52600660205260405f20549260115492831561287b575f52600360205260405f205415612870576127a48661221f565b905f198401938411611c2e578381109084180280841893036127c7575050509190565b5f19830192831194919290855b611c2e5781811161286357805f5260106020526127f360405f20611c60565b60208101805161280f575b505061280990611d8f565b856127d4565b9091976001890190818a11611c2e576128099361284f93612849935f52601060205261283d60405f20611c60565b51915190519189612c82565b96611d9d565b9461285b818787612b17565b96905f6127fe565b50509250505f8080612640565b505050909150904290565b505050509190565b60405163a9059cbb60e01b60208201526001600160a01b0390921660248301526044808301939093529181526128c3916128be606483611bbd565b612d02565b565b6001600160a01b03165f818152600f6020526040902054908115158061296c575b15612911575f52600e60205260405f20905f198101908111611c2e575f52602052600160405f200155565b9091612953906040519061292482611ba1565b4282526020820152825f52600e60205260405f20845f5260205260405f20906020600191805184550151910155565b60018201809211611c2e575f52600f60205260405f2055565b50805f52600e60205260405f205f198301838111611c2e575f526020524260405f2054146128e6565b60115480151580612a0c575b156129c5575f54905f198101908111611c2e575f526010602052600160405f200155565b6129fc5f54604051906129d782611ba1565b4282526020820152825f52601060205260405f20906020600191805184550151910155565b60018101809111611c2e57601155565b505f198101818111611c2e575f5260106020524260405f2054146129a1565b919060018060a01b03831690815f52600560205260405f205493825f52600660205260405f20549260115490811561287b575f52600360205260405f20541561287057612a778661221f565b925f198201918211611c2e578181109082180218915b828110612a9b575050509190565b805f526010602052612aaf60405f20611c60565b602081018051612ac4575b5050600101612a8d565b9091966001880190818911611c2e57600193612b0393612afd935f526010602052612af160405f20611c60565b51915190519187612c82565b95611d9d565b93612b0f818685612b17565b95905f612aba565b6001600160a01b03165f81815260136020526040902054919282151580612bbf575b15612b6557505f52601260205260405f20905f198101908111611c2e575f52602052600160405f200155565b612ba691929360405191612b7883611ba1565b82526020820152825f52601260205260405f20845f5260205260405f20906020600191805184550151910155565b60018201809211611c2e575f52601360205260405f2055565b50815f52601260205260405f205f198401848111611c2e575f526020528060405f205414612b39565b6040516323b872dd60e01b60208201526001600160a01b0392831660248201529290911660448301526064808301939093529181526128c3916128be608483611bbd565b600c545f5b818110612c3c575050565b80612c48600192611bf5565b838060a01b0391549060031b1c16612c5f816125c2565b825f93929352600660205260405f20915f52600560205260405f20555501612c31565b6001600160a01b03165f81815260046020526040902054828618838711029092189594612cd39391926123629280831892811092909202909118808218818310021890808818908811028718611c21565b90670de0b6b3a7640000820291808304670de0b6b3a76400001490151715611c2e57612cfe91611c42565b9190565b905f602091828151910182855af1156118d7575f513d612d5157506001600160a01b0381163b155b612d315750565b635274afe760e01b5f9081526001600160a01b0391909116600452602490fd5b60011415612d2a56fea264697066735822122094a5245624aec3c2a4f08b600b7911784f77ecb7641ec165be4b80bec26c266264736f6c634300081c003300000000000000000000000094cedcb72fd719ec7f28f6c7daeeca24871dbbff000000000000000000000000ccd2f9920f45308652667bcadce4e91080edafb5000000000000000000000000d86cde14fe4310feb50558c92b0eaec56bb7aed9000000000000000000000000db9a1bdc443dd11366b8a6dc8038144ecc4d4e23000000000000000000000000f3113e4f80c84935e576cfd75f4423e9b911908a00000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000030000000000000000000000008ff0dd9f9c40a0d76ef1bcfaf5f98c1610c74bd8000000000000000000000000b50a96253abdf803d85efcdce07ad8becbc52bd500000000000000000000000028245ab01298eaef7933bc90d35bd9dbca5c89db
Deployed Bytecode
0x6080806040526004361015610012575f80fd5b5f905f3560e01c90816301316ddf14611b2a5750806303fbf83a14611ae65780630cdfebfa14611a99578063115c6f3914611a7257806318160ddd14611a555780631f85071614611a11578063211dc32d146119e5578063221ca18c146119ad5780632ce9aead146119755780632e1a7d4d1461195757806331279d3d146115ee5780633a4b66f1146115a95780633ca068b61461155657806346c96aac146115115780634d5ce038146114d25780635a45d052146114ac578063638634ee1461146d57806363fb415b1461143457806368fcee1a146113e65780636fcfff45146113ad57806370a08231146109c457806376f4be361461138e578063770f857114611349578063853828b6146113235780639418f939146111d657806399bcc052146111b25780639ce43f9014611179578063a0dc27581461115b578063a495e5b514611108578063aa479652146110cf578063b66503cf14610ae3578063c6f678bd146109fd578063d35e2544146109c4578063d7da4bb0146109a7578063da09d19d1461096e578063e2bbb158146105f7578063e5748213146105d4578063e6886396146105b6578063e8111a1214610598578063f12297771461056c578063f301af4214610528578063f7412baf146104f4578063fc97a303146104bb578063fd314098146104875763fdb483c71461020d575f80fd5b346104845761021b36611bdf565b9060016014540361047557600260145581610234612c2c565b61024082600a54611c21565b600a55338452600b6020526040842061025a838254611c21565b905561029082337f00000000000000000000000094cedcb72fd719ec7f28f6c7daeeca24871dbbff6001600160a01b0316612883565b156104615733835260096020526040832054820361043957338352600960205260408320839055827f000000000000000000000000f3113e4f80c84935e576cfd75f4423e9b911908a6001600160a01b0316803b156104485760405163411b1f7760e01b8152600481018590523360248201529082908290604490829084905af1801561043d5761044c575b50505b338352600160205261033660408420548454611c21565b8355338352600b60205261035d604084205433855260016020528060408620558454611d9d565b835533835260016020526103756040842054336128c5565b61037d612995565b827f000000000000000000000000f3113e4f80c84935e576cfd75f4423e9b911908a6001600160a01b0316803b1561044857604051633aa53b9160e21b815260048101859052336024820152604481018490529082908290606490829084905af1801561043d57610424575b505060405191825260208201527ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b56860403392a2600160145580f35b8161042e91611bbd565b61043957825f6103e9565b8280fd5b6040513d84823e3d90fd5b5080fd5b8161045691611bbd565b61043957825f61031c565b33835260096020526040832054915061031f565b63558a1e0360e11b8352600483fd5b80fd5b50346104845760403660031901126104845760406104af6104a6611b75565b60243590612462565b82519182526020820152f35b5034610484576020366003190112610484576020906040906001600160a01b036104e3611b75565b168152600983522054604051908152f35b5034610484576020366003190112610484576040809160043581526010602052206001815491015482519182526020820152f35b50346104845760203660031901126104845760043590600c5482101561048457602061055383611bf5565b905460405160039290921b1c6001600160a01b03168152f35b503461048457602036600319011261048457602061059061058b611b75565b6123b3565b604051908152f35b50346104845780600319360112610484576020601154604051908152f35b50346104845780600319360112610484576020600c54604051908152f35b5034610484578060031936011261048457602060ff600254166040519015158152f35b50346104845761060636611bdf565b906001601454036104755760026014558161062282151561237a565b61062a612c2c565b61065f8230337f00000000000000000000000094cedcb72fd719ec7f28f6c7daeeca24871dbbff6001600160a01b0316612be8565b61066b82600a54611d9d565b600a55338452600b60205260408420610685838254611d9d565b90551561095a576040516331a9108f60e11b8152600481018390526020816024817f000000000000000000000000db9a1bdc443dd11366b8a6dc8038144ecc4d4e236001600160a01b03165afa90811561094f578491610920575b50336001600160a01b03909116036108ef57338352600960205260408320541561085f575b338352600960205281604084205403610827575b338352600160205261073060408420548454611c21565b8355338352600b6020526107636040842054338552600160205280604086205561075b818654611d9d565b8555336128c5565b61076b612995565b827f000000000000000000000000f3113e4f80c84935e576cfd75f4423e9b911908a6001600160a01b0316803b156104485760405163530e389d60e11b815260048101859052336024820152604481018490529082908290606490829084905af1801561043d57610812575b505060405191825260208201527f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a1560403392a2600160145580f35b8161081c91611bbd565b61043957825f6107d7565b60405162461bcd60e51b815260206004820152601060248201526f1a5b9d985b1a59081d1bdad95b881a5960821b6044820152606490fd5b338352600960205260408320829055827f000000000000000000000000f3113e4f80c84935e576cfd75f4423e9b911908a6001600160a01b0316803b156104485760405163698473e360e01b8152600481018590523360248201529082908290604490829084905af1801561043d576108da575b5050610705565b816108e491611bbd565b61043957825f6108d3565b60405162461bcd60e51b81526020600482015260096024820152683737ba1037bbb732b960b91b6044820152606490fd5b610942915060203d602011610948575b61093a8183611bbd565b81019061230b565b5f6106e0565b503d610930565b6040513d86823e3d90fd5b338352600960205260408320549150610719565b5034610484576020366003190112610484576020906040906001600160a01b03610996611b75565b168152600483522054604051908152f35b503461048457806003193601126104845760209054604051908152f35b5034610484576020366003190112610484576020906040906001600160a01b036109ec611b75565b168152600b83522054604051908152f35b5034610484576020366003190112610484576040516370a0823160e01b8152336004828101919091527f00000000000000000000000094cedcb72fd719ec7f28f6c7daeeca24871dbbff6001600160a01b0316919035602082602481865afa91821561094f578492610aab575b50600160145403610a9c57600260145561065f828294610a8b82151561237a565b610a93612c2c565b30903390612be8565b63558a1e0360e11b8452600484fd5b9091506020813d602011610adb575b81610ac760209383611bbd565b81010312610ad75751905f610a6a565b5f80fd5b3d9150610aba565b503461048457604036600319011261048457610afd611b75565b6024356001601454036104755760026014556001600160a01b0382811692907f00000000000000000000000094cedcb72fd719ec7f28f6c7daeeca24871dbbff16831461109957610b4f82151561237a565b828452600d60205260ff60408520541615610f61575b8284526003602052604084205415610e6e575b610b81816125c2565b848652600660205260408620908587526005602052604087205555828452600460205260408420544210155f14610dd757610bbe82303386612be8565b828452600360205262093a80820460408520555b8284526003602052604084205415610d9f576040516370a0823160e01b8152306004820152602081602481875afa908115610d94578591610d62575b50838552600360205262093a806040862054910410610d1d5762093a804201804211610d095783855260046020526040852055828452600d60205260ff60408520541615610c8c575b506040519081527ff70d5c697de7ea828df48e5c4573cb2194c659f1901f70110c52b066dcf5082660203392a3600160145580f35b828452600d60205260408420805460ff19166001179055600c5468010000000000000000811015610cf55790610ccb826001610cef9401600c55611bf5565b81546001600160a01b0393841660039290921b91821b9390911b1916919091179055565b5f610c57565b634e487b7160e01b85526041600452602485fd5b634e487b7160e01b85526011600452602485fd5b60405162461bcd60e51b815260206004820152601860248201527f50726f76696465642072657761726420746f6f206869676800000000000000006044820152606490fd5b90506020813d602011610d8c575b81610d7d60209383611bbd565b81010312610ad757515f610c0e565b3d9150610d70565b6040513d87823e3d90fd5b60405162461bcd60e51b815260206004820152601060248201526f0726577617264207261746520697320360841b6044820152606490fd5b8284526004602052610e03610df0426040872054611c21565b8486526003602052604086205490611daa565b80831115610e3857610e2562093a8091610e1f85303389612be8565b84611d9d565b0483855260036020526040852055610bd2565b60405162461bcd60e51b815260206004820152600e60248201526d185b5bdd5b9d080f8817db19599d60921b6044820152606490fd5b8284526013602052604084205480151580610f24575b15610ec857838552601260205260408520905f198101908111610eb4578552602052836001604082200155610b78565b634e487b7160e01b86526011600452602486fd5b610f07604051610ed781611ba1565b42815286602082015285875260126020526040872083885260205260408720906020600191805184550151910155565b60018101809111610d095783855260136020526040852055610b78565b508385526012602052604085205f198201828111610f4d57865260205242604086205414610e84565b634e487b7160e01b87526011600452602487fd5b604051633af32abf60e01b8152600481018490526020816024817f000000000000000000000000f3113e4f80c84935e576cfd75f4423e9b911908a6001600160a01b03165afa908115610d9457859161105a575b501561100a576010600c5410610b655760405162461bcd60e51b815260206004820152601760248201527f746f6f206d616e79207265776172647320746f6b656e730000000000000000006044820152606490fd5b60405162461bcd60e51b815260206004820152602260248201527f7265776172647320746f6b656e73206d7573742062652077686974656c697374604482015261195960f21b6064820152608490fd5b90506020813d602011611091575b8161107560209383611bbd565b8101031261108d5751801515810361108d575f610fb5565b8480fd5b3d9150611068565b60405162461bcd60e51b815260206004820152600e60248201526d1a5b9d985b1a59081c995dd85c9960921b6044820152606490fd5b5034610484576020366003190112610484576020906040906001600160a01b036110f7611b75565b168152601383522054604051908152f35b5034610484576040366003190112610484576040611124611b75565b9161112d611b8b565b9260018060a01b031681526007602052209060018060a01b03165f52602052602060405f2054604051908152f35b5034610484578060031936011261048457602060405162093a808152f35b5034610484576020366003190112610484576020906040906001600160a01b036111a1611b75565b168152600683522054604051908152f35b50346104845760203660031901126104845760206105906111d1611b75565b61232a565b5034610484576060366003190112610484576004356111f3611b8b565b6044356001600160a01b0381169290919083830361108d576040516342f9577960e11b8152602081600481897f000000000000000000000000db9a1bdc443dd11366b8a6dc8038144ecc4d4e236001600160a01b03165af19081156113185786916112f9575b506001600160a01b031633036112c85761127281611bf5565b90546001600160a01b039384169360039290921b1c1682900361108d576112c593610ccb928652600d6020526040862060ff1981541690558552600d60205260408520600160ff19825416179055611bf5565b80f35b60405162461bcd60e51b81526020600482015260096024820152686f6e6c79207465616d60b81b6044820152606490fd5b611312915060203d6020116109485761093a8183611bbd565b5f611259565b6040513d88823e3d90fd5b5034610484578060031936011261048457338152600b6020526112c56040822054611f9d565b50346104845780600319360112610484576040517f000000000000000000000000ccd2f9920f45308652667bcadce4e91080edafb56001600160a01b03168152602090f35b503461048457602036600319011261048457602061059060043561221f565b5034610484576020366003190112610484576020906040906001600160a01b036113d5611b75565b168152600f83522054604051908152f35b503461048457604036600319011261048457611400611b75565b61140c60243582612759565b909160018060a01b031690818452600660205260408420918452600560205260408420555580f35b5034610484576020366003190112610484576020906040906001600160a01b0361145c611b75565b168152600183522054604051908152f35b503461048457602036600319011261048457602061059061148c611b75565b60018060a01b03165f52600460205260405f205442811090421802421890565b5034610484576040366003190112610484576114c6611b75565b61140c60243582612a2b565b50346104845760203660031901126104845760209060ff906040906001600160a01b036114fd611b75565b168152600d84522054166040519015158152f35b50346104845780600319360112610484576040517f000000000000000000000000f3113e4f80c84935e576cfd75f4423e9b911908a6001600160a01b03168152602090f35b5034610484576040366003190112610484576040611572611b75565b9161157b611b8b565b9260018060a01b031681526008602052209060018060a01b03165f52602052602060405f2054604051908152f35b50346104845780600319360112610484576040517f00000000000000000000000094cedcb72fd719ec7f28f6c7daeeca24871dbbff6001600160a01b03168152602090f35b5034610ad7576040366003190112610ad757611608611b75565b60243567ffffffffffffffff8111610ad75736602382011215610ad75780600401359067ffffffffffffffff8211611943578160051b90604051926116506020840185611bbd565b83526024602084019282010190368211610ad757602401915b81831061192357505050600160145403611914576001600160a01b0382169033821480156118e2575b15610ad75760016014557f000000000000000000000000f3113e4f80c84935e576cfd75f4423e9b911908a6001600160a01b0316803b15610ad7575f80916024604051809481936363453ae160e01b83523060048401525af180156118d7576118c2575b506002601455835b815181101561185a576001906117266001600160a01b0361171f838661220b565b51166125c2565b838060a01b03611736848761220b565b5116885260066020526040882090848060a01b03611754858861220b565b51168952600560205260408920555561177e85838060a01b03611777848761220b565b5116611dbd565b828060a01b0361178e838661220b565b51168752600760205260408720855f5260205260405f20429055828060a01b036117b8838661220b565b5116875260066020526040872054838060a01b036117d6848761220b565b51168852600860205260408820865f5260205260405f205580611839575b828060a01b03611804838661220b565b5116906040519081527f9aa05b3d70a9e3e2f004f039648839560576334fb45c81f91b6db03ad9e2efc960203392a3016116fe565b6118558187858060a01b0361184e868961220b565b5116612883565b6117f4565b846118b28585808452600160205261187760408520548554611c21565b8455808452600b60205261189e604085205482865260016020528060408720558554611d9d565b8455835260016020526040832054906128c5565b6118ba612995565b600160145580f35b6118cf9194505f90611bbd565b5f925f6116f6565b6040513d5f823e3d90fd5b50337f000000000000000000000000f3113e4f80c84935e576cfd75f4423e9b911908a6001600160a01b031614611692565b63558a1e0360e11b5f5260045ffd5b82356001600160a01b0381168103610ad757815260209283019201611669565b634e487b7160e01b5f52604160045260245ffd5b34610ad7576020366003190112610ad757611973600435611f9d565b005b34610ad7576020366003190112610ad7576001600160a01b03611996611b75565b165f526005602052602060405f2054604051908152f35b34610ad7576020366003190112610ad7576001600160a01b036119ce611b75565b165f526003602052602060405f2054604051908152f35b34610ad7576040366003190112610ad7576020610590611a03611b75565b611a0b611b8b565b90611dbd565b34610ad7575f366003190112610ad7576040517f000000000000000000000000db9a1bdc443dd11366b8a6dc8038144ecc4d4e236001600160a01b03168152602090f35b34610ad7575f366003190112610ad7576020600a54604051908152f35b34610ad7576040366003190112610ad7576020610590611a90611b75565b60243590611c7e565b34610ad7576040366003190112610ad7576001600160a01b03611aba611b75565b165f52600e60205260405f206024355f526020526040805f206001815491015482519182526020820152f35b34610ad7575f366003190112610ad7576040517f000000000000000000000000d86cde14fe4310feb50558c92b0eaec56bb7aed96001600160a01b03168152602090f35b34610ad7576040366003190112610ad7576040906001600160a01b03611b4e611b75565b165f526012602052815f206024355f52602052815f20600181549101549082526020820152f35b600435906001600160a01b0382168203610ad757565b602435906001600160a01b0382168203610ad757565b6040810190811067ffffffffffffffff82111761194357604052565b90601f8019910116810190811067ffffffffffffffff82111761194357604052565b6040906003190112610ad7576004359060243590565b600c54811015611c0d57600c5f5260205f2001905f90565b634e487b7160e01b5f52603260045260245ffd5b91908203918211611c2e57565b634e487b7160e01b5f52601160045260245ffd5b8115611c4c570490565b634e487b7160e01b5f52601260045260245ffd5b90604051611c6d81611ba1565b602060018294805484520154910152565b6001600160a01b03165f818152600f6020526040902054918215611d8857815f52600e60205260405f20925f1981019081119384611c2e57815f526020528160405f20541115611d8157825f52600e60205260405f205f80526020528160405f205411611d79575f93611c2e5791905b838311611cfb5750505090565b611d11611d088585611c21565b60011c84611c21565b93825f52600e60205260405f20855f52602052611d3060405f20611c60565b51828103611d4057505050505090565b918093949592105f14611d575750925b9190611cee565b93505f19810190811115611d5057634e487b7160e01b5f52601160045260245ffd5b505050505f90565b9250505090565b5050505f90565b5f198114611c2e5760010190565b91908201809211611c2e57565b81810292918115918404141715611c2e57565b6001600160a01b038181165f8181526007602090815260408083209487168084529482528083205484845260128352818420848052835281842054868552600f909352922054939592939092919015611f93578281611e229411908218021890611c7e565b92805f52600f60205260405f20545f19810190808211611c2e575f9582611ecb575b505092611ebb670de0b6b3a76400009383611ec89796611ec1955f52600e60205260405f20905f52602052611e7b60405f20611c60565b90611e966020611e8c845188612462565b50930151956123b3565b925f52600860205260405f20905f5260205260405f2054818111908218021890611c21565b90611daa565b0490611d9d565b90565b9692969391906001190181811196875b611c2e57818611611f7857885f52600e60205260405f20865f52602052611f0460405f20611c60565b895f52600e60205260405f20916001880192838911611c2e57611ec1611f6b93670de0b6b3a764000092611f71965f52602052611ebb8c6020611f61611f4c60405f20611c60565b92611f58865182612462565b50935190612462565b5093015192611c21565b95611d8f565b9487611edb565b93979396509193509050611ebb670de0b6b3a7640000611e44565b5050505050505f90565b5f905f91335f52600b60205260405f205482146121f6575b60016014540361191457600260145582611fcd612c2c565b611fd983600a54611c21565b600a55335f52600b60205260405f20611ff3848254611c21565b905561202983337f00000000000000000000000094cedcb72fd719ec7f28f6c7daeeca24871dbbff6001600160a01b0316612883565b156121e157335f52600960205260405f20548303610ad757335f908152600960205260408120557f000000000000000000000000f3113e4f80c84935e576cfd75f4423e9b911908a6001600160a01b0316803b15610ad75760405163411b1f7760e01b815260048101859052336024820152905f908290604490829084905af180156118d7576121ce575b505b33815260016020526120cd60408220548254611c21565b8155338152600b6020526120f4604082205433835260016020528060408420558254611d9d565b8155338152600160205261210c6040822054336128c5565b612114612995565b7f000000000000000000000000f3113e4f80c84935e576cfd75f4423e9b911908a6001600160a01b0316803b1561044857604051633aa53b9160e21b815260048101859052336024820152604481018490529082908290606490829084905af1801561043d576121b9575b505060405191825260208201527ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b56860403392a26001601455565b6121c4828092611bbd565b610484578061217f565b6121da91505f90611bbd565b5f5f6120b4565b9150335f52600960205260405f2054916120b6565b9150335f52600960205260405f205491611fb5565b8051821015611c0d5760209160051b010190565b601154908115612305575f1982019182119182611c2e57805f5260106020528160405f205411156122ff575f805260106020527f6e0956cda88cad152e89927e53611735b61a5c762d1428573c6931b0a5efcb01548210611d88575f92611c2e57905b82821161228e57505090565b6122a461229b8484611c21565b60011c83611c21565b92835f5260106020526122b960405f20611c60565b518281036122c8575050505090565b9180939492105f146122dd5750915b90612282565b92505f198101908111156122d757634e487b7160e01b5f52601160045260245ffd5b91505090565b50505f90565b90816020910312610ad757516001600160a01b0381168103610ad75790565b6001600160a01b03165f818152600460205260409020544210156123755780611ec8915f5260046020526123624260405f2054611c21565b905f52600360205260405f205490611daa565b505f90565b1561238157565b60405162461bcd60e51b815260206004820152600a6024820152690616d6f756e74203e20360b41b6044820152606490fd5b5f54908115612446576001600160a01b03165f8181526006602090815260408083205460048084528285205460058552929094205493909252909261241292909161236291808218818310021890428181119181189190910218611c21565b670de0b6b3a7640000810290808204670de0b6b3a76400001490151715611c2e57611ec89261244091611c42565b90611d9d565b6001600160a01b03165f90815260066020526040902054919050565b6001600160a01b03165f8181526013602052604090205490929181156125b857835f52601260205260405f20915f1981019081119283611c2e57815f526020528160405f2054111561259057845f52601260205260405f205f80526020528160405f205411612585575f92611c2e57905b8282116125005750505f928352601260209081526040808520928552919052909120600181015490549091565b61251061229b8484979597611c21565b835f52601260205260405f20815f5260205261252e60405f20611c60565b9586518381145f1461254a575050505050506020820151915190565b839495975092909192105f146125635750915b906124d3565b92505f1981019081111561255d57634e487b7160e01b5f52601160045260245ffd5b50505090505f905f90565b5f94855260126020908152604080872092875291905290932060018101549054909350919050565b505090505f905f90565b9060018060a01b038216805f52600560205260405f205492815f52600660205260405f205491601154908115612640575f52600360205260405f20541561274f5761260c8561221f565b5f1982019190818311611c2e57826126a7575b50505f52601060205261263460405f20611c60565b60208101908151612647575b5050509190565b829561269d949261268d926126796126949660018060a01b03165f52600460205260405f205442811090421802421890565b905191519180841184821802189089612c82565b5090611d9d565b92834291612b17565b42915f8080612640565b9491906001190181811195865b611c2e5781811161274357805f5260106020526126d360405f20611c60565b6020810180516126ef575b50506126e990611d8f565b866126b4565b90919860018a0190818b11611c2e576126e99361272f93612729935f52601060205261271d60405f20611c60565b5191519051918a612c82565b97611d9d565b9561273b818888612b17565b97905f6126de565b50509093505f8061261f565b5050909150904290565b919060018060a01b038316805f52600560205260405f205493815f52600660205260405f20549260115492831561287b575f52600360205260405f205415612870576127a48661221f565b905f198401938411611c2e578381109084180280841893036127c7575050509190565b5f19830192831194919290855b611c2e5781811161286357805f5260106020526127f360405f20611c60565b60208101805161280f575b505061280990611d8f565b856127d4565b9091976001890190818a11611c2e576128099361284f93612849935f52601060205261283d60405f20611c60565b51915190519189612c82565b96611d9d565b9461285b818787612b17565b96905f6127fe565b50509250505f8080612640565b505050909150904290565b505050509190565b60405163a9059cbb60e01b60208201526001600160a01b0390921660248301526044808301939093529181526128c3916128be606483611bbd565b612d02565b565b6001600160a01b03165f818152600f6020526040902054908115158061296c575b15612911575f52600e60205260405f20905f198101908111611c2e575f52602052600160405f200155565b9091612953906040519061292482611ba1565b4282526020820152825f52600e60205260405f20845f5260205260405f20906020600191805184550151910155565b60018201809211611c2e575f52600f60205260405f2055565b50805f52600e60205260405f205f198301838111611c2e575f526020524260405f2054146128e6565b60115480151580612a0c575b156129c5575f54905f198101908111611c2e575f526010602052600160405f200155565b6129fc5f54604051906129d782611ba1565b4282526020820152825f52601060205260405f20906020600191805184550151910155565b60018101809111611c2e57601155565b505f198101818111611c2e575f5260106020524260405f2054146129a1565b919060018060a01b03831690815f52600560205260405f205493825f52600660205260405f20549260115490811561287b575f52600360205260405f20541561287057612a778661221f565b925f198201918211611c2e578181109082180218915b828110612a9b575050509190565b805f526010602052612aaf60405f20611c60565b602081018051612ac4575b5050600101612a8d565b9091966001880190818911611c2e57600193612b0393612afd935f526010602052612af160405f20611c60565b51915190519187612c82565b95611d9d565b93612b0f818685612b17565b95905f612aba565b6001600160a01b03165f81815260136020526040902054919282151580612bbf575b15612b6557505f52601260205260405f20905f198101908111611c2e575f52602052600160405f200155565b612ba691929360405191612b7883611ba1565b82526020820152825f52601260205260405f20845f5260205260405f20906020600191805184550151910155565b60018201809211611c2e575f52601360205260405f2055565b50815f52601260205260405f205f198401848111611c2e575f526020528060405f205414612b39565b6040516323b872dd60e01b60208201526001600160a01b0392831660248201529290911660448301526064808301939093529181526128c3916128be608483611bbd565b600c545f5b818110612c3c575050565b80612c48600192611bf5565b838060a01b0391549060031b1c16612c5f816125c2565b825f93929352600660205260405f20915f52600560205260405f20555501612c31565b6001600160a01b03165f81815260046020526040902054828618838711029092189594612cd39391926123629280831892811092909202909118808218818310021890808818908811028718611c21565b90670de0b6b3a7640000820291808304670de0b6b3a76400001490151715611c2e57612cfe91611c42565b9190565b905f602091828151910182855af1156118d7575f513d612d5157506001600160a01b0381163b155b612d315750565b635274afe760e01b5f9081526001600160a01b0391909116600452602490fd5b60011415612d2a56fea264697066735822122094a5245624aec3c2a4f08b600b7911784f77ecb7641ec165be4b80bec26c266264736f6c634300081c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000094cedcb72fd719ec7f28f6c7daeeca24871dbbff000000000000000000000000ccd2f9920f45308652667bcadce4e91080edafb5000000000000000000000000d86cde14fe4310feb50558c92b0eaec56bb7aed9000000000000000000000000db9a1bdc443dd11366b8a6dc8038144ecc4d4e23000000000000000000000000f3113e4f80c84935e576cfd75f4423e9b911908a00000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000030000000000000000000000008ff0dd9f9c40a0d76ef1bcfaf5f98c1610c74bd8000000000000000000000000b50a96253abdf803d85efcdce07ad8becbc52bd500000000000000000000000028245ab01298eaef7933bc90d35bd9dbca5c89db
-----Decoded View---------------
Arg [0] : _stake (address): 0x94cEdCB72Fd719EC7F28F6c7DAeeCA24871DBbff
Arg [1] : _internalBribe (address): 0xccd2F9920f45308652667bCaDcE4e91080eDafB5
Arg [2] : _externalBribe (address): 0xD86cDE14fe4310fEb50558C92B0EaeC56bb7AeD9
Arg [3] : _ve (address): 0xdB9A1bdc443dd11366b8a6dc8038144eCc4D4E23
Arg [4] : _voter (address): 0xF3113E4F80c84935E576CFD75F4423E9B911908A
Arg [5] : _allowedRewardTokens (address[]): 0x8fF0dd9f9C40a0d76eF1BcFAF5f98c1610c74Bd8,0xb50A96253aBDF803D85efcDce07Ad8becBc52BD5,0x28245AB01298eaEf7933bC90d35Bd9DbCA5C89DB
-----Encoded View---------------
10 Constructor Arguments found :
Arg [0] : 00000000000000000000000094cedcb72fd719ec7f28f6c7daeeca24871dbbff
Arg [1] : 000000000000000000000000ccd2f9920f45308652667bcadce4e91080edafb5
Arg [2] : 000000000000000000000000d86cde14fe4310feb50558c92b0eaec56bb7aed9
Arg [3] : 000000000000000000000000db9a1bdc443dd11366b8a6dc8038144ecc4d4e23
Arg [4] : 000000000000000000000000f3113e4f80c84935e576cfd75f4423e9b911908a
Arg [5] : 00000000000000000000000000000000000000000000000000000000000000c0
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000003
Arg [7] : 0000000000000000000000008ff0dd9f9c40a0d76ef1bcfaf5f98c1610c74bd8
Arg [8] : 000000000000000000000000b50a96253abdf803d85efcdce07ad8becbc52bd5
Arg [9] : 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.