Source Code
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 68452902 | 517 days ago | Contract Creation | 0 MNT |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
RollingRewarder
Compiler Version
v0.8.23+commit.f704f362
Optimization Enabled:
Yes with 800 runs
Other Settings:
shanghai EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;
import "../interfaces/IRollingRewarder.sol";
import "../interfaces/IRewarder.sol";
import "../interfaces/IReliquary.sol";
import "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";
import "openzeppelin-contracts/contracts/utils/math/Math.sol";
import "openzeppelin-contracts/contracts/access/Ownable.sol";
/// @title Rewarder that can be funded with a set token, distributing it over a period of time.
contract RollingRewarder is IRollingRewarder {
using SafeERC20 for IERC20;
uint256 private constant REWARD_PER_SECOND_PRECISION = 10_000;
address public immutable parent;
address public immutable reliquary;
address public immutable rewardToken;
uint8 public immutable poolId;
uint256 public lastDistributionTime;
uint256 public distributionPeriod;
uint256 public lastIssuanceTimestamp;
uint256 public rewardPerSecond;
uint256 public accRewardPerShare;
mapping(uint256 => uint256) private rewardDebt;
mapping(uint256 => uint256) private rewardCredit;
// Errors
error RollingRewarder__NOT_PARENT();
error RollingRewarder__NOT_OWNER();
error RollingRewarder__ZERO_INPUT();
// Events
event LogOnReward(uint256 _relicId, uint256 _rewardAmount, address _to);
event UpdateDistributionPeriod(uint256 _newDistributionPeriod);
event Fund(uint256 _newDistributionPeriod);
event Issue(uint256 _newDistributionPeriod);
/// @dev We define owner of parent owner of the child too.
modifier onlyOwner() {
if (msg.sender != Ownable(parent).owner()) revert RollingRewarder__NOT_OWNER();
_;
}
/// @dev Limits function calls to address of parent contract `ParentRollingRewarder`
modifier onlyParent() {
if (msg.sender != parent) revert RollingRewarder__NOT_PARENT();
_;
}
/**
* @dev Contructor called on deployment of this contract.
* @param _rewardToken Address of token rewards are distributed in.
* @param _reliquary Address of Reliquary this rewarder will read state from.
*/
constructor(address _rewardToken, address _reliquary, uint8 _poolId) {
poolId = _poolId;
parent = msg.sender;
rewardToken = _rewardToken;
reliquary = _reliquary;
_updateDistributionPeriod(7 days);
}
// -------------- Admin --------------
function fund(uint256 _amount) external onlyOwner {
IERC20(rewardToken).safeTransferFrom(msg.sender, address(this), _amount);
_fund(_amount);
}
function updateDistributionPeriod(uint256 _newDistributionPeriod) external onlyOwner {
_updateDistributionPeriod(_newDistributionPeriod);
}
// -------------- Hooks --------------
function onUpdate(
ICurves _curve,
uint256 _relicId,
uint256 _amount,
uint256 _oldLevel,
uint256 _newLevel
) external virtual onlyParent {
uint256 oldAmountMultiplied_ = _amount * _curve.getFunction(_oldLevel);
uint256 newAmountMultiplied_ = _amount * _curve.getFunction(_newLevel);
_issueTokens();
uint256 accRewardPerShare_ = accRewardPerShare;
rewardCredit[_relicId] += Math.mulDiv(
oldAmountMultiplied_, accRewardPerShare_, ACC_REWARD_PRECISION
) - rewardDebt[_relicId];
rewardDebt[_relicId] =
Math.mulDiv(newAmountMultiplied_, accRewardPerShare_, ACC_REWARD_PRECISION);
}
/// @dev Must always be called after `onUpdate`, `onDeposit` or `onWithdraw`.
function onReward(uint256 _relicId, address _to) external virtual onlyParent {
uint256 pending_ = rewardCredit[_relicId];
if (pending_ != 0) {
rewardCredit[_relicId] = 0;
IERC20(rewardToken).safeTransfer(_to, pending_);
emit LogOnReward(_relicId, pending_, _to);
}
}
function onDeposit(
ICurves _curve,
uint256 _relicId,
uint256 _depositAmount,
uint256 _oldAmount,
uint256 _oldLevel,
uint256 _newLevel
) external virtual onlyParent {
uint256 oldAmountMultiplied_ = _oldAmount * _curve.getFunction(_oldLevel);
uint256 newAmountMultiplied_ = (_oldAmount + _depositAmount) * _curve.getFunction(_newLevel);
_issueTokens();
uint256 accRewardPerShare_ = accRewardPerShare;
rewardCredit[_relicId] += Math.mulDiv(
oldAmountMultiplied_, accRewardPerShare_, ACC_REWARD_PRECISION
) - rewardDebt[_relicId];
rewardDebt[_relicId] =
Math.mulDiv(newAmountMultiplied_, accRewardPerShare_, ACC_REWARD_PRECISION);
}
function onWithdraw(
ICurves _curve,
uint256 _relicId,
uint256 _withdrawalAmount,
uint256 _oldAmount,
uint256 _oldLevel,
uint256 _newLevel
) external virtual onlyParent {
uint256 oldAmountMultiplied_ = _oldAmount * _curve.getFunction(_oldLevel);
uint256 newAmountMultiplied_ =
(_oldAmount - _withdrawalAmount) * _curve.getFunction(_newLevel);
_issueTokens();
uint256 accRewardPerShare_ = accRewardPerShare;
rewardCredit[_relicId] += Math.mulDiv(
oldAmountMultiplied_, accRewardPerShare_, ACC_REWARD_PRECISION
) - rewardDebt[_relicId];
rewardDebt[_relicId] =
Math.mulDiv(newAmountMultiplied_, accRewardPerShare_, ACC_REWARD_PRECISION);
}
function onSplit(
ICurves _curve,
uint256 _fromId,
uint256 _newId,
uint256 _amount,
uint256 _fromAmount,
uint256 _level
) external virtual onlyParent {
_issueTokens();
uint256 accRewardPerShare_ = accRewardPerShare;
uint256 multiplier_ = _curve.getFunction(_level);
rewardCredit[_fromId] += Math.mulDiv(
_fromAmount, multiplier_ * accRewardPerShare_, ACC_REWARD_PRECISION
) - rewardDebt[_fromId];
rewardDebt[_fromId] = Math.mulDiv(
_fromAmount - _amount, multiplier_ * accRewardPerShare_, ACC_REWARD_PRECISION
);
rewardDebt[_newId] =
Math.mulDiv(_amount, multiplier_ * accRewardPerShare_, ACC_REWARD_PRECISION);
}
function onShift(
ICurves _curve,
uint256 _fromId,
uint256 _toId,
uint256 _amount,
uint256 _oldFromAmount,
uint256 _oldToAmount,
uint256 _fromLevel,
uint256 _oldToLevel,
uint256 _newToLevel
) external virtual onlyParent {
uint256 _multiplierFrom = _curve.getFunction(_fromLevel);
_issueTokens();
uint256 accRewardPerShare_ = accRewardPerShare;
rewardCredit[_fromId] += Math.mulDiv(
_oldFromAmount, _multiplierFrom * accRewardPerShare_, ACC_REWARD_PRECISION
) - rewardDebt[_fromId];
rewardDebt[_fromId] = Math.mulDiv(
_oldFromAmount - _amount, _multiplierFrom * accRewardPerShare_, ACC_REWARD_PRECISION
);
rewardCredit[_toId] += Math.mulDiv(
_oldToAmount, _curve.getFunction(_oldToLevel) * accRewardPerShare_, ACC_REWARD_PRECISION
) - rewardDebt[_toId];
rewardDebt[_toId] = Math.mulDiv(
_oldToAmount + _amount,
_curve.getFunction(_newToLevel) * accRewardPerShare_,
ACC_REWARD_PRECISION
);
}
function onMerge(
ICurves _curve,
uint256 _fromId,
uint256 _toId,
uint256 _fromAmount,
uint256 _toAmount,
uint256 _fromLevel,
uint256 _oldToLevel,
uint256 _newToLevel
) external virtual onlyParent {
uint256 fromAmountMultiplied_ = _fromAmount * _curve.getFunction(_fromLevel);
uint256 oldToAmountMultiplied_ = _toAmount * _curve.getFunction(_oldToLevel);
uint256 newToAmountMultiplied_ = (_toAmount + _fromAmount) * _curve.getFunction(_newToLevel);
_issueTokens();
uint256 accRewardPerShare_ = accRewardPerShare;
uint256 pendingTo_ = Math.mulDiv(
accRewardPerShare_, fromAmountMultiplied_ + oldToAmountMultiplied_, ACC_REWARD_PRECISION
) + rewardCredit[_fromId] - rewardDebt[_fromId] - rewardDebt[_toId];
if (pendingTo_ != 0) {
rewardCredit[_toId] += pendingTo_;
}
rewardCredit[_fromId] = 0;
rewardDebt[_toId] =
Math.mulDiv(newToAmountMultiplied_, accRewardPerShare_, ACC_REWARD_PRECISION);
}
// -------------- Internals --------------
function _updateDistributionPeriod(uint256 _newDistributionPeriod) internal {
distributionPeriod = _newDistributionPeriod;
emit UpdateDistributionPeriod(_newDistributionPeriod);
}
function _fund(uint256 _amount) internal {
if (_amount == 0) revert RollingRewarder__ZERO_INPUT();
uint256 lastIssuanceTimestamp_ = lastIssuanceTimestamp; // Last time token was distributed.
uint256 lastDistributionTime_ = lastDistributionTime; // Timestamp of the final distribution of tokens.
uint256 amount_ = _amount; // Amount of tokens to add to the distribution.
if (lastIssuanceTimestamp_ < lastDistributionTime_) {
amount_ += getRewardAmount(lastDistributionTime_ - lastIssuanceTimestamp_); // Add to the funding amount that hasnt been issued.
}
uint256 distributionPeriod_ = distributionPeriod; // How many days will we distribute these assets over.
rewardPerSecond = (amount_ * REWARD_PER_SECOND_PRECISION) / distributionPeriod_; // How many tokens per second will be distributed.
lastDistributionTime = block.timestamp + distributionPeriod_; // When will the new final distribution be.
lastIssuanceTimestamp = block.timestamp; // When was the last time tokens were distributed -- now.
emit Fund(_amount);
}
function _issueTokens() internal returns (uint256 issuance_) {
uint256 poolBalance_ = IReliquary(reliquary).getTotalLpSupplied(poolId);
uint256 lastIssuanceTimestamp_ = lastIssuanceTimestamp; // Last time token was distributed.
uint256 lastDistributionTime_ = lastDistributionTime; // Timestamp of the final distribution of tokens.
if (lastIssuanceTimestamp_ < lastDistributionTime_) {
uint256 endTimestamp_ =
block.timestamp > lastDistributionTime_ ? lastDistributionTime_ : block.timestamp;
issuance_ = getRewardAmount(endTimestamp_ - lastIssuanceTimestamp_);
if (poolBalance_ != 0) {
accRewardPerShare += Math.mulDiv(issuance_, ACC_REWARD_PRECISION, poolBalance_);
}
}
lastIssuanceTimestamp = block.timestamp;
emit Issue(issuance_);
}
// -------------- View --------------
/// @notice Returns the amount of pending rewardToken for a position from this rewarder.
function pendingToken(uint256 _relicId) public view returns (uint256 amount_) {
uint256 poolBalance_ = IReliquary(reliquary).getTotalLpSupplied(poolId);
uint256 lastIssuanceTimestamp_ = lastIssuanceTimestamp; // Last time token was distributed.
uint256 lastDistributionTime_ = lastDistributionTime; // Timestamp of the final distribution of tokens.
uint256 newAccReward_ = accRewardPerShare;
if (lastIssuanceTimestamp_ < lastDistributionTime_) {
uint256 endTimestamp_ =
block.timestamp > lastDistributionTime_ ? lastDistributionTime_ : block.timestamp;
uint256 issuance_ = getRewardAmount(endTimestamp_ - lastIssuanceTimestamp_);
if (poolBalance_ != 0) {
newAccReward_ += Math.mulDiv(issuance_, ACC_REWARD_PRECISION, poolBalance_);
}
}
PositionInfo memory position_ = IReliquary(reliquary).getPositionForId(_relicId);
uint256 amountMultiplied_ = uint256(position_.amount)
* IReliquary(reliquary).getPoolInfo(poolId).curve.getFunction(uint256(position_.level));
uint256 pending_ = Math.mulDiv(amountMultiplied_, newAccReward_, ACC_REWARD_PRECISION)
- rewardDebt[_relicId];
pending_ += rewardCredit[_relicId];
amount_ = pending_;
}
function pendingTokens(uint256 _relicId)
external
view
virtual
override
returns (address[] memory rewardTokens_, uint256[] memory rewardAmounts_)
{
rewardTokens_ = new address[](1);
rewardTokens_[0] = rewardToken;
rewardAmounts_ = new uint256[](1);
rewardAmounts_[0] = pendingToken(_relicId);
}
function getRewardAmount(uint256 _seconds) public view returns (uint256) {
return ((rewardPerSecond * _seconds) / REWARD_PER_SECOND_PRECISION);
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;
interface ICurves {
function getFunction(uint256 _maturity) external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;
import "contracts/interfaces/ICurves.sol";
import "lib/openzeppelin-contracts/contracts/token/ERC721/IERC721.sol";
/// @dev Level of precision rewards are calculated to.
uint256 constant ACC_REWARD_PRECISION = 1e41;
/// @dev Max supply allowed for checks purpose.
uint256 constant MAX_SUPPLY_ALLOWED = 100e9 ether;
/// @dev Indicates whether tokens are being added to, or removed from, a pool.
enum Kind {
DEPOSIT,
WITHDRAW,
UPDATE
}
/**
* @notice Info for each Reliquary position.
* @dev 3 storage slots
* `rewardDebt` Amount of reward token accumalated before the position's entry or last harvest.
* `rewardCredit` Amount of reward token owed to the user on next harvest.
* `amount` LP token amount the position owner has provided.
* `entry` Used to determine the maturity of the position, position owner's relative entry into the pool.
* `level` Index of this position's level within the pool's array of levels, ensures that a single Relic is only used for one pool.
* `poolId` ID of the pool to which this position belongs.
*/
struct PositionInfo {
uint256 rewardDebt;
uint256 rewardCredit;
uint128 amount;
uint40 entry;
uint40 level;
uint8 poolId;
}
/**
* @notice Info of each Reliquary pool.
* @dev 7 storage slots
* `name` Name of pool to be displayed in NFT image.
* `accRewardPerShare` Accumulated reward tokens per share of pool (1 / ACC_REWARD_PRECISION).
* `totalLpSupplied` Total number of LPs in the pool.
* `nftDescriptor` The nft descriptor address.
* `rewarder` The nft rewarder address.
* `poolToken` ERC20 token supplied.
* `lastRewardTime` Last timestamp the accumulated reward was updated.
* `allowPartialWithdrawals` Whether users can withdraw less than their entire position.
* `allocPoint` Pool's individual allocation - ratio of the total allocation.
* `curve` Contract that define the function: f(maturity) = multiplier.
* A value of false will also disable shift and split functionality.
*/
struct PoolInfo {
string name;
uint256 accRewardPerShare;
uint256 totalLpSupplied;
address nftDescriptor;
address rewarder;
address gauge;
address poolToken;
uint40 lastRewardTime;
bool allowPartialWithdrawals;
uint96 allocPoint;
ICurves curve;
}
interface IReliquary is IERC721 {
// Errors
error Reliquary__BURNING_PRINCIPAL();
error Reliquary__BURNING_REWARDS();
error Reliquary__REWARD_TOKEN_AS_POOL_TOKEN();
error Reliquary__TOKEN_NOT_COMPATIBLE();
error Reliquary__ZERO_TOTAL_ALLOC_POINT();
error Reliquary__NON_EXISTENT_POOL();
error Reliquary__ZERO_INPUT();
error Reliquary__NOT_OWNER();
error Reliquary__DUPLICATE_RELIC_IDS();
error Reliquary__RELICS_NOT_OF_SAME_POOL();
error Reliquary__MERGING_EMPTY_RELICS();
error Reliquary__NOT_APPROVED_OR_OWNER();
error Reliquary__PARTIAL_WITHDRAWALS_DISABLED();
error Reliquary__MULTIPLIER_AT_LEVEL_ZERO_SHOULD_BE_GT_ZERO();
error Reliquary__REWARD_PRECISION_ISSUE();
error Reliquary__CURVE_OVERFLOW();
error Reliquary__PAUSED();
error Reliquary__GAUGE_NOT_ALIVE();
function setEmissionRate(uint256 _emissionRate) external;
function addPool(
uint256 _allocPoint,
address _poolToken,
address _rewarder,
ICurves _curve,
string memory _name,
address _nftDescriptor,
bool _allowPartialWithdrawals,
address _to
) external;
function modifyPool(
uint8 _poolId,
uint256 _allocPoint,
address _rewarder,
string calldata _name,
address _nftDescriptor,
bool _overwriteRewarder
) external;
function massUpdatePools() external;
function updatePool(uint8 _poolId) external;
function deposit(uint256 _amount, uint256 _relicId, address _harvestTo) external;
function withdraw(uint256 _amount, uint256 _relicId, address _harvestTo) external;
function update(uint256 _relicId, address _harvestTo) external;
function emergencyWithdraw(uint256 _relicId) external;
function poolLength() external view returns (uint256 pools_);
function getPositionForId(uint256 _posId) external view returns (PositionInfo memory);
function getPoolInfo(uint8 _poolId) external view returns (PoolInfo memory);
function getTotalLpSupplied(uint8 _poolId) external view returns (uint256 lp_);
function isApprovedOrOwner(address, uint256) external view returns (bool);
function createRelicAndDeposit(address _to, uint8 _poolId, uint256 _amount)
external
returns (uint256 newRelicId_);
function split(uint256 _relicId, uint256 _amount, address _to)
external
returns (uint256 newRelicId_);
function shift(uint256 _fromId, uint256 _toId, uint256 _amount) external;
function burn(uint256 _tokenId) external;
function pendingReward(uint256 _relicId) external view returns (uint256 pending_);
function rewardToken() external view returns (address);
function emissionRate() external view returns (uint256);
function totalAllocPoint() external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;
import "../interfaces/ICurves.sol";
interface IRewarder {
function onReward(uint256 _relicId, address _to) external;
function onUpdate(
ICurves _curve,
uint256 _relicId,
uint256 _amount,
uint256 _oldLevel,
uint256 _newLevel
) external;
function onDeposit(
ICurves _curve,
uint256 _relicId,
uint256 _depositAmount,
uint256 _oldAmount,
uint256 _oldLevel,
uint256 _newLevel
) external;
function onWithdraw(
ICurves _curve,
uint256 _relicId,
uint256 _withdrawalAmount,
uint256 _oldAmount,
uint256 _oldLevel,
uint256 _newLevel
) external;
function onSplit(
ICurves _curve,
uint256 _fromId,
uint256 _newId,
uint256 _amount,
uint256 _fromAmount,
uint256 _level
) external;
function onShift(
ICurves _curve,
uint256 _fromId,
uint256 _toId,
uint256 _amount,
uint256 _oldFromAmount,
uint256 _oldToAmount,
uint256 _fromLevel,
uint256 _oldToLevel,
uint256 _newToLevel
) external;
function onMerge(
ICurves _curve,
uint256 _fromId,
uint256 _toId,
uint256 _fromAmount,
uint256 _toAmount,
uint256 _fromLevel,
uint256 _oldToLevel,
uint256 _newToLevel
) external;
function pendingTokens(uint256 _relicId)
external
view
returns (address[] memory, uint256[] memory);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;
import "./IRewarder.sol";
interface IRollingRewarder is IRewarder {
function fund(uint256 _amount) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
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.0.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 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 {
using Address for address;
/**
* @dev An operation with an ERC20 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 Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
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.
*/
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.
*/
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 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).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data);
if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
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 silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC721 compliant contract.
*/
interface IERC721 is IERC165 {
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
* a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must have been allowed to move this token by either {approve} or
* {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
* a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
* or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
* understand this adds an external call which potentially creates a reentrancy vulnerability.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function approve(address to, uint256 tokenId) external;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the address zero.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/
function isApprovedForAll(address owner, address operator) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error AddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedInnerCall();
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {FailedInnerCall} error.
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
* unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {FailedInnerCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
*/
function _revert(bytes memory returndata) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* 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[EIP 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
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
/**
* @dev Muldiv operation overflow.
*/
error MathOverflowedMulDiv();
enum Rounding {
Floor, // Toward negative infinity
Ceil, // Toward positive infinity
Trunc, // Toward zero
Expand // Away from zero
}
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an overflow flag.
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds towards infinity instead
* of rounding towards zero.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
if (b == 0) {
// Guarantee the same behavior as in a regular Solidity division.
return a / b;
}
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
* denominator == 0.
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
* Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0 = x * y; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
if (denominator <= prod1) {
revert MathOverflowedMulDiv();
}
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator.
// Always >= 1. See https://cs.stackexchange.com/q/138556/92363.
uint256 twos = denominator & (0 - denominator);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the 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.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
* towards zero.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256 of a positive value rounded towards zero.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
}
}
/**
* @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
*/
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
return uint8(rounding) % 2 == 1;
}
}{
"evmVersion": "shanghai",
"libraries": {},
"metadata": {
"appendCBOR": true,
"bytecodeHash": "ipfs",
"useLiteralContent": false
},
"optimizer": {
"enabled": true,
"runs": 800
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"remappings": [
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"base64/=lib/base64/",
"ds-test/=lib/solmate/lib/ds-test/src/",
"erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
"forge-std/=lib/forge-std/src/",
"solmate/=lib/solmate/src/",
"v2-core/=lib/v2-core/contracts/"
],
"viaIR": false
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_rewardToken","type":"address"},{"internalType":"address","name":"_reliquary","type":"address"},{"internalType":"uint8","name":"_poolId","type":"uint8"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"MathOverflowedMulDiv","type":"error"},{"inputs":[],"name":"RollingRewarder__NOT_OWNER","type":"error"},{"inputs":[],"name":"RollingRewarder__NOT_PARENT","type":"error"},{"inputs":[],"name":"RollingRewarder__ZERO_INPUT","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_newDistributionPeriod","type":"uint256"}],"name":"Fund","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_newDistributionPeriod","type":"uint256"}],"name":"Issue","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_relicId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_rewardAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"_to","type":"address"}],"name":"LogOnReward","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_newDistributionPeriod","type":"uint256"}],"name":"UpdateDistributionPeriod","type":"event"},{"inputs":[],"name":"accRewardPerShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"distributionPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"fund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_seconds","type":"uint256"}],"name":"getRewardAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastDistributionTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastIssuanceTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ICurves","name":"_curve","type":"address"},{"internalType":"uint256","name":"_relicId","type":"uint256"},{"internalType":"uint256","name":"_depositAmount","type":"uint256"},{"internalType":"uint256","name":"_oldAmount","type":"uint256"},{"internalType":"uint256","name":"_oldLevel","type":"uint256"},{"internalType":"uint256","name":"_newLevel","type":"uint256"}],"name":"onDeposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ICurves","name":"_curve","type":"address"},{"internalType":"uint256","name":"_fromId","type":"uint256"},{"internalType":"uint256","name":"_toId","type":"uint256"},{"internalType":"uint256","name":"_fromAmount","type":"uint256"},{"internalType":"uint256","name":"_toAmount","type":"uint256"},{"internalType":"uint256","name":"_fromLevel","type":"uint256"},{"internalType":"uint256","name":"_oldToLevel","type":"uint256"},{"internalType":"uint256","name":"_newToLevel","type":"uint256"}],"name":"onMerge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_relicId","type":"uint256"},{"internalType":"address","name":"_to","type":"address"}],"name":"onReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ICurves","name":"_curve","type":"address"},{"internalType":"uint256","name":"_fromId","type":"uint256"},{"internalType":"uint256","name":"_toId","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_oldFromAmount","type":"uint256"},{"internalType":"uint256","name":"_oldToAmount","type":"uint256"},{"internalType":"uint256","name":"_fromLevel","type":"uint256"},{"internalType":"uint256","name":"_oldToLevel","type":"uint256"},{"internalType":"uint256","name":"_newToLevel","type":"uint256"}],"name":"onShift","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ICurves","name":"_curve","type":"address"},{"internalType":"uint256","name":"_fromId","type":"uint256"},{"internalType":"uint256","name":"_newId","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_fromAmount","type":"uint256"},{"internalType":"uint256","name":"_level","type":"uint256"}],"name":"onSplit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ICurves","name":"_curve","type":"address"},{"internalType":"uint256","name":"_relicId","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_oldLevel","type":"uint256"},{"internalType":"uint256","name":"_newLevel","type":"uint256"}],"name":"onUpdate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ICurves","name":"_curve","type":"address"},{"internalType":"uint256","name":"_relicId","type":"uint256"},{"internalType":"uint256","name":"_withdrawalAmount","type":"uint256"},{"internalType":"uint256","name":"_oldAmount","type":"uint256"},{"internalType":"uint256","name":"_oldLevel","type":"uint256"},{"internalType":"uint256","name":"_newLevel","type":"uint256"}],"name":"onWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"parent","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_relicId","type":"uint256"}],"name":"pendingToken","outputs":[{"internalType":"uint256","name":"amount_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_relicId","type":"uint256"}],"name":"pendingTokens","outputs":[{"internalType":"address[]","name":"rewardTokens_","type":"address[]"},{"internalType":"uint256[]","name":"rewardAmounts_","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolId","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"reliquary","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardPerSecond","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newDistributionPeriod","type":"uint256"}],"name":"updateDistributionPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
61010060405234801562000011575f80fd5b5060405162002255380380620022558339810160408190526200003491620000c0565b60ff811660e052336080526001600160a01b0383811660c052821660a0526200006062093a8062000069565b5050506200010f565b60018190556040518181527f66e1dffea17302ec11b493c94870e341ef6b7d6cedeea746890cbe648c62b86b9060200160405180910390a150565b80516001600160a01b0381168114620000bb575f80fd5b919050565b5f805f60608486031215620000d3575f80fd5b620000de84620000a4565b9250620000ee60208501620000a4565b9150604084015160ff8116811462000104575f80fd5b809150509250925092565b60805160a05160c05160e05161208d620001c85f395f81816101dc01528181610e6501528181611002015261154901525f818161033a01528181610646015281816108ac01526113d501525f818161031301528181610e9801528181610f8001528181611036015261157c01525f818161023b0152818161037a015281816105d9015281816106c60152818161094a01528181610bc401528181610c8a015281816111a7015281816113190152611411015261208d5ff3fe608060405234801561000f575f80fd5b506004361061016e575f3560e01c80638f10369a116100d2578063b356366611610088578063e754de6311610063578063e754de631461030e578063f7c618c114610335578063f9d8011d1461035c575f80fd5b8063b3563666146102df578063c84993af146102e8578063ca1d209d146102fb575f80fd5b80639673d01b116100b85780639673d01b146102b05780639b501723146102c3578063abef68e4146102cc575f80fd5b80638f10369a1461029e578063939d6237146102a7575f80fd5b80634556c4911161012757806360f96a8f1161010d57806360f96a8f1461023657806375b17350146102755780638442e0fa1461028b575f80fd5b80634556c49114610210578063577fbd5f14610223575f80fd5b806329f64f6f1161015757806329f64f6f1461019a578063352fc85f146101ad5780633e0dc34e146101d7575f80fd5b80631856ce9e14610172578063191c4f5214610187575b5f80fd5b610185610180366004611a65565b61036f565b005b610185610195366004611ac7565b6105ce565b6101856101a8366004611af5565b6106bb565b6101c06101bb366004611b35565b610885565b6040516101ce929190611b4c565b60405180910390f35b6101fe7f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff90911681526020016101ce565b61018561021e366004611bce565b61093f565b610185610231366004611b35565b610bc2565b61025d7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016101ce565b61027d5f5481565b6040519081526020016101ce565b610185610299366004611c27565b610c7f565b61027d60035481565b61027d60045481565b61027d6102be366004611b35565b610e54565b61027d60015481565b6101856102da366004611c27565b61119c565b61027d60025481565b61027d6102f6366004611b35565b6112f5565b610185610309366004611b35565b611317565b61025d7f000000000000000000000000000000000000000000000000000000000000000081565b61025d7f000000000000000000000000000000000000000000000000000000000000000081565b61018561036a366004611c27565b611406565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146103b857604051633461661160e01b815260040160405180910390fd5b604051630e097de760e01b8152600481018490525f906001600160a01b038b1690630e097de790602401602060405180830381865afa1580156103fd573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104219190611c6f565b905061042b611538565b506004545f8a8152600560205260409020546104608861044b8486611c9a565b6b92efd1b8d0cf37be5aa1cae560291b61168c565b61046a9190611cb1565b5f8b81526006602052604081208054909190610487908490611cc4565b909155506104a4905061049a8989611cb1565b61044b8385611c9a565b60055f8c81526020019081526020015f208190555060055f8a81526020019081526020015f205461054787838e6001600160a01b0316630e097de7896040518263ffffffff1660e01b81526004016104fe91815260200190565b602060405180830381865afa158015610519573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061053d9190611c6f565b61044b9190611c9a565b6105519190611cb1565b5f8a8152600660205260408120805490919061056e908490611cc4565b909155506105b090506105818988611cc4565b604051630e097de760e01b81526004810186905283906001600160a01b038f1690630e097de7906024016104fe565b5f998a52600560205260409099209890985550505050505050505050565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461061757604051633461661160e01b815260040160405180910390fd5b5f8281526006602052604090205480156106b6575f8381526006602052604081205561066d6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016838361174c565b60408051848152602081018390526001600160a01b0384168183015290517fcdc9fd371154c559abac08b9dcd2ad4487ea53751ef20089b83d76f95badc8509181900360600190a15b505050565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461070457604051633461661160e01b815260040160405180910390fd5b604051630e097de760e01b8152600481018390525f906001600160a01b03871690630e097de790602401602060405180830381865afa158015610749573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061076d9190611c6f565b6107779085611c9a565b604051630e097de760e01b8152600481018490529091505f906001600160a01b03881690630e097de790602401602060405180830381865afa1580156107bf573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107e39190611c6f565b6107ed9086611c9a565b90506107f7611538565b506004545f8781526005602052604090205461082384836b92efd1b8d0cf37be5aa1cae560291b61168c565b61082d9190611cb1565b5f888152600660205260408120805490919061084a908490611cc4565b9091555061086a905082826b92efd1b8d0cf37be5aa1cae560291b61168c565b5f978852600560205260409097209690965550505050505050565b604080516001808252818301909252606091829190602080830190803683370190505091507f0000000000000000000000000000000000000000000000000000000000000000825f815181106108dd576108dd611ceb565b6001600160a01b039290921660209283029190910182015260408051600180825281830190925291828101908036833701905050905061091c83610e54565b815f8151811061092e5761092e611ceb565b602002602001018181525050915091565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461098857604051633461661160e01b815260040160405180910390fd5b604051630e097de760e01b8152600481018490525f906001600160a01b038a1690630e097de790602401602060405180830381865afa1580156109cd573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109f19190611c6f565b6109fb9087611c9a565b604051630e097de760e01b8152600481018590529091505f906001600160a01b038b1690630e097de790602401602060405180830381865afa158015610a43573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a679190611c6f565b610a719087611c9a565b604051630e097de760e01b8152600481018590529091505f906001600160a01b038c1690630e097de790602401602060405180830381865afa158015610ab9573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610add9190611c6f565b610ae78989611cc4565b610af19190611c9a565b9050610afb611538565b506004545f8a8152600560209081526040808320548e845281842054600690935290832054909190610b318561044b898b611cc4565b610b3b9190611cc4565b610b459190611cb1565b610b4f9190611cb1565b90508015610b7a575f8b81526006602052604081208054839290610b74908490611cc4565b90915550505b5f8c815260066020526040812055610ba283836b92efd1b8d0cf37be5aa1cae560291b61168c565b5f9b8c5260056020526040909b209a909a55505050505050505050505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c1e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c429190611d0f565b6001600160a01b0316336001600160a01b031614610c7357604051630d99ba6360e41b815260040160405180910390fd5b610c7c816117c0565b50565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610cc857604051633461661160e01b815260040160405180910390fd5b604051630e097de760e01b8152600481018390525f906001600160a01b03881690630e097de790602401602060405180830381865afa158015610d0d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d319190611c6f565b610d3b9085611c9a565b604051630e097de760e01b8152600481018490529091505f906001600160a01b03891690630e097de790602401602060405180830381865afa158015610d83573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610da79190611c6f565b610db18787611cb1565b610dbb9190611c9a565b9050610dc5611538565b506004545f88815260056020526040902054610df184836b92efd1b8d0cf37be5aa1cae560291b61168c565b610dfb9190611cb1565b5f8981526006602052604081208054909190610e18908490611cc4565b90915550610e38905082826b92efd1b8d0cf37be5aa1cae560291b61168c565b5f98895260056020526040909820979097555050505050505050565b604051631f22ecbf60e21b815260ff7f00000000000000000000000000000000000000000000000000000000000000001660048201525f9081906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690637c8bb2fc90602401602060405180830381865afa158015610edd573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f019190611c6f565b6002545f54600454929350909181831015610f68575f824211610f245742610f26565b825b90505f610f366102f68684611cb1565b90508515610f6557610f58816b92efd1b8d0cf37be5aa1cae560291b8861168c565b610f629084611cc4565b92505b50505b60405163e48dc13560e01b8152600481018790525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e48dc1359060240160c060405180830381865afa158015610fcd573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ff19190611d8b565b6040516375ed572560e11b815260ff7f00000000000000000000000000000000000000000000000000000000000000001660048201529091505f906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063ebdaae4a906024015f60405180830381865afa15801561107a573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526110a19190810190611ee0565b61014001516001600160a01b0316630e097de7836080015164ffffffffff166040518263ffffffff1660e01b81526004016110de91815260200190565b602060405180830381865afa1580156110f9573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061111d9190611c6f565b82604001516fffffffffffffffffffffffffffffffff1661113e9190611c9a565b5f898152600560205260408120549192509061116a83866b92efd1b8d0cf37be5aa1cae560291b61168c565b6111749190611cb1565b5f8a81526006602052604090205490915061118f9082611cc4565b9998505050505050505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146111e557604051633461661160e01b815260040160405180910390fd5b6111ed611538565b5060048054604051630e097de760e01b8152918201839052905f906001600160a01b03891690630e097de790602401602060405180830381865afa158015611237573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061125b9190611c6f565b5f8881526005602052604090205490915061127a8561044b8585611c9a565b6112849190611cb1565b5f88815260066020526040812080549091906112a1908490611cc4565b909155506112be90506112b48686611cb1565b61044b8484611c9a565b5f888152600560205260409020556112da8561044b8484611c9a565b5f968752600560205260409096209590955550505050505050565b5f612710826003546113079190611c9a565b6113119190612004565b92915050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611373573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113979190611d0f565b6001600160a01b0316336001600160a01b0316146113c857604051630d99ba6360e41b815260040160405180910390fd5b6113fd6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163330846117fb565b610c7c8161183a565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461144f57604051633461661160e01b815260040160405180910390fd5b604051630e097de760e01b8152600481018390525f906001600160a01b03881690630e097de790602401602060405180830381865afa158015611494573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114b89190611c6f565b6114c29085611c9a565b604051630e097de760e01b8152600481018490529091505f906001600160a01b03891690630e097de790602401602060405180830381865afa15801561150a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061152e9190611c6f565b610db18787611cc4565b604051631f22ecbf60e21b815260ff7f00000000000000000000000000000000000000000000000000000000000000001660048201525f9081906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690637c8bb2fc90602401602060405180830381865afa1580156115c1573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115e59190611c6f565b6002545f54919250908082101561164f575f8142116116045742611606565b815b90506116156102f68483611cb1565b9450831561164d57611637856b92efd1b8d0cf37be5aa1cae560291b8661168c565b60045f8282546116479190611cc4565b90915550505b505b426002556040518481527fcb8241adb0c3fdb35b70c24ce35c5eb0c17af7431c99f827d44a445ca624176a9060200160405180910390a150505090565b5f838302815f1985870982811083820303915050805f036116c0578382816116b6576116b6611ff0565b0492505050611745565b8084116116e05760405163227bc15360e01b815260040160405180910390fd5b5f848688095f868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150505b9392505050565b6040516001600160a01b038381166024830152604482018390526106b691859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506118e9565b60018190556040518181527f66e1dffea17302ec11b493c94870e341ef6b7d6cedeea746890cbe648c62b86b9060200160405180910390a150565b6040516001600160a01b0384811660248301528381166044830152606482018390526118349186918216906323b872dd90608401611779565b50505050565b805f0361185a576040516352b31e1560e01b815260040160405180910390fd5b6002545f548281831015611882576118756102f68484611cb1565b61187f9082611cc4565b90505b6001548061189261271084611c9a565b61189c9190612004565b6003556118a98142611cc4565b5f55426002556040518581527f27b2dc149fd3048bc27eadaaf660801a04305c72845da74066a17b72d6c5bb669060200160405180910390a15050505050565b5f6118fd6001600160a01b0384168361194f565b905080515f1415801561192157508080602001905181019061191f9190612023565b155b156106b657604051635274afe760e01b81526001600160a01b03841660048201526024015b60405180910390fd5b606061174583835f845f80856001600160a01b03168486604051611973919061203c565b5f6040518083038185875af1925050503d805f81146119ad576040519150601f19603f3d011682016040523d82523d5f602084013e6119b2565b606091505b50915091506119c28683836119cc565b9695505050505050565b6060826119e1576119dc82611a28565b611745565b81511580156119f857506001600160a01b0384163b155b15611a2157604051639996b31560e01b81526001600160a01b0385166004820152602401611946565b5080611745565b805115611a385780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b6001600160a01b0381168114610c7c575f80fd5b5f805f805f805f805f6101208a8c031215611a7e575f80fd5b8935611a8981611a51565b9b60208b01359b5060408b01359a60608101359a506080810135995060a0810135985060c0810135975060e081013596506101000135945092505050565b5f8060408385031215611ad8575f80fd5b823591506020830135611aea81611a51565b809150509250929050565b5f805f805f60a08688031215611b09575f80fd5b8535611b1481611a51565b97602087013597506040870135966060810135965060800135945092505050565b5f60208284031215611b45575f80fd5b5035919050565b604080825283519082018190525f906020906060840190828701845b82811015611b8d5781516001600160a01b031684529284019290840190600101611b68565b505050838103828501528451808252858301918301905f5b81811015611bc157835183529284019291840191600101611ba5565b5090979650505050505050565b5f805f805f805f80610100898b031215611be6575f80fd5b8835611bf181611a51565b9a60208a01359a5060408a013599606081013599506080810135985060a0810135975060c0810135965060e00135945092505050565b5f805f805f8060c08789031215611c3c575f80fd5b8635611c4781611a51565b9860208801359850604088013597606081013597506080810135965060a00135945092505050565b5f60208284031215611c7f575f80fd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b808202811582820484141761131157611311611c86565b8181038181111561131157611311611c86565b8082018082111561131157611311611c86565b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b8051611d0a81611a51565b919050565b5f60208284031215611d1f575f80fd5b815161174581611a51565b60405160c0810167ffffffffffffffff81118282101715611d4d57611d4d611cd7565b60405290565b604051610160810167ffffffffffffffff81118282101715611d4d57611d4d611cd7565b805164ffffffffff81168114611d0a575f80fd5b5f60c08284031215611d9b575f80fd5b611da3611d2a565b825181526020830151602082015260408301516fffffffffffffffffffffffffffffffff81168114611dd3575f80fd5b6040820152611de460608401611d77565b6060820152611df560808401611d77565b608082015260a083015160ff81168114611e0d575f80fd5b60a08201529392505050565b5f5b83811015611e33578181015183820152602001611e1b565b50505f910152565b5f82601f830112611e4a575f80fd5b815167ffffffffffffffff80821115611e6557611e65611cd7565b604051601f8301601f19908116603f01168101908282118183101715611e8d57611e8d611cd7565b81604052838152866020858801011115611ea5575f80fd5b6119c2846020830160208901611e19565b80518015158114611d0a575f80fd5b80516bffffffffffffffffffffffff81168114611d0a575f80fd5b5f60208284031215611ef0575f80fd5b815167ffffffffffffffff80821115611f07575f80fd5b908301906101608286031215611f1b575f80fd5b611f23611d53565b825182811115611f31575f80fd5b611f3d87828601611e3b565b8252506020830151602082015260408301516040820152611f6060608401611cff565b6060820152611f7160808401611cff565b6080820152611f8260a08401611cff565b60a0820152611f9360c08401611cff565b60c0820152611fa460e08401611d77565b60e08201526101009150611fb9828401611eb6565b828201526101209150611fcd828401611ec5565b828201526101409150611fe1828401611cff565b91810191909152949350505050565b634e487b7160e01b5f52601260045260245ffd5b5f8261201e57634e487b7160e01b5f52601260045260245ffd5b500490565b5f60208284031215612033575f80fd5b61174582611eb6565b5f825161204d818460208701611e19565b919091019291505056fea26469706673582212201dc2ea35c67cc7b02e7ce4462bbcb82884b1fde25470c7a8d9ea4357aaef27b464736f6c63430008170033000000000000000000000000d2b4c9b0d70e3da1fbdd98f469bd02e77e12fc79000000000000000000000000ff1b7120baaa89acde6e45ccfb2263a8416c20f00000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x608060405234801561000f575f80fd5b506004361061016e575f3560e01c80638f10369a116100d2578063b356366611610088578063e754de6311610063578063e754de631461030e578063f7c618c114610335578063f9d8011d1461035c575f80fd5b8063b3563666146102df578063c84993af146102e8578063ca1d209d146102fb575f80fd5b80639673d01b116100b85780639673d01b146102b05780639b501723146102c3578063abef68e4146102cc575f80fd5b80638f10369a1461029e578063939d6237146102a7575f80fd5b80634556c4911161012757806360f96a8f1161010d57806360f96a8f1461023657806375b17350146102755780638442e0fa1461028b575f80fd5b80634556c49114610210578063577fbd5f14610223575f80fd5b806329f64f6f1161015757806329f64f6f1461019a578063352fc85f146101ad5780633e0dc34e146101d7575f80fd5b80631856ce9e14610172578063191c4f5214610187575b5f80fd5b610185610180366004611a65565b61036f565b005b610185610195366004611ac7565b6105ce565b6101856101a8366004611af5565b6106bb565b6101c06101bb366004611b35565b610885565b6040516101ce929190611b4c565b60405180910390f35b6101fe7f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff90911681526020016101ce565b61018561021e366004611bce565b61093f565b610185610231366004611b35565b610bc2565b61025d7f000000000000000000000000f6d1cabe63237970b0e5fec45afc5b2c1312d8e081565b6040516001600160a01b0390911681526020016101ce565b61027d5f5481565b6040519081526020016101ce565b610185610299366004611c27565b610c7f565b61027d60035481565b61027d60045481565b61027d6102be366004611b35565b610e54565b61027d60015481565b6101856102da366004611c27565b61119c565b61027d60025481565b61027d6102f6366004611b35565b6112f5565b610185610309366004611b35565b611317565b61025d7f000000000000000000000000ff1b7120baaa89acde6e45ccfb2263a8416c20f081565b61025d7f000000000000000000000000d2b4c9b0d70e3da1fbdd98f469bd02e77e12fc7981565b61018561036a366004611c27565b611406565b336001600160a01b037f000000000000000000000000f6d1cabe63237970b0e5fec45afc5b2c1312d8e016146103b857604051633461661160e01b815260040160405180910390fd5b604051630e097de760e01b8152600481018490525f906001600160a01b038b1690630e097de790602401602060405180830381865afa1580156103fd573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104219190611c6f565b905061042b611538565b506004545f8a8152600560205260409020546104608861044b8486611c9a565b6b92efd1b8d0cf37be5aa1cae560291b61168c565b61046a9190611cb1565b5f8b81526006602052604081208054909190610487908490611cc4565b909155506104a4905061049a8989611cb1565b61044b8385611c9a565b60055f8c81526020019081526020015f208190555060055f8a81526020019081526020015f205461054787838e6001600160a01b0316630e097de7896040518263ffffffff1660e01b81526004016104fe91815260200190565b602060405180830381865afa158015610519573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061053d9190611c6f565b61044b9190611c9a565b6105519190611cb1565b5f8a8152600660205260408120805490919061056e908490611cc4565b909155506105b090506105818988611cc4565b604051630e097de760e01b81526004810186905283906001600160a01b038f1690630e097de7906024016104fe565b5f998a52600560205260409099209890985550505050505050505050565b336001600160a01b037f000000000000000000000000f6d1cabe63237970b0e5fec45afc5b2c1312d8e0161461061757604051633461661160e01b815260040160405180910390fd5b5f8281526006602052604090205480156106b6575f8381526006602052604081205561066d6001600160a01b037f000000000000000000000000d2b4c9b0d70e3da1fbdd98f469bd02e77e12fc7916838361174c565b60408051848152602081018390526001600160a01b0384168183015290517fcdc9fd371154c559abac08b9dcd2ad4487ea53751ef20089b83d76f95badc8509181900360600190a15b505050565b336001600160a01b037f000000000000000000000000f6d1cabe63237970b0e5fec45afc5b2c1312d8e0161461070457604051633461661160e01b815260040160405180910390fd5b604051630e097de760e01b8152600481018390525f906001600160a01b03871690630e097de790602401602060405180830381865afa158015610749573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061076d9190611c6f565b6107779085611c9a565b604051630e097de760e01b8152600481018490529091505f906001600160a01b03881690630e097de790602401602060405180830381865afa1580156107bf573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107e39190611c6f565b6107ed9086611c9a565b90506107f7611538565b506004545f8781526005602052604090205461082384836b92efd1b8d0cf37be5aa1cae560291b61168c565b61082d9190611cb1565b5f888152600660205260408120805490919061084a908490611cc4565b9091555061086a905082826b92efd1b8d0cf37be5aa1cae560291b61168c565b5f978852600560205260409097209690965550505050505050565b604080516001808252818301909252606091829190602080830190803683370190505091507f000000000000000000000000d2b4c9b0d70e3da1fbdd98f469bd02e77e12fc79825f815181106108dd576108dd611ceb565b6001600160a01b039290921660209283029190910182015260408051600180825281830190925291828101908036833701905050905061091c83610e54565b815f8151811061092e5761092e611ceb565b602002602001018181525050915091565b336001600160a01b037f000000000000000000000000f6d1cabe63237970b0e5fec45afc5b2c1312d8e0161461098857604051633461661160e01b815260040160405180910390fd5b604051630e097de760e01b8152600481018490525f906001600160a01b038a1690630e097de790602401602060405180830381865afa1580156109cd573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109f19190611c6f565b6109fb9087611c9a565b604051630e097de760e01b8152600481018590529091505f906001600160a01b038b1690630e097de790602401602060405180830381865afa158015610a43573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a679190611c6f565b610a719087611c9a565b604051630e097de760e01b8152600481018590529091505f906001600160a01b038c1690630e097de790602401602060405180830381865afa158015610ab9573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610add9190611c6f565b610ae78989611cc4565b610af19190611c9a565b9050610afb611538565b506004545f8a8152600560209081526040808320548e845281842054600690935290832054909190610b318561044b898b611cc4565b610b3b9190611cc4565b610b459190611cb1565b610b4f9190611cb1565b90508015610b7a575f8b81526006602052604081208054839290610b74908490611cc4565b90915550505b5f8c815260066020526040812055610ba283836b92efd1b8d0cf37be5aa1cae560291b61168c565b5f9b8c5260056020526040909b209a909a55505050505050505050505050565b7f000000000000000000000000f6d1cabe63237970b0e5fec45afc5b2c1312d8e06001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c1e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c429190611d0f565b6001600160a01b0316336001600160a01b031614610c7357604051630d99ba6360e41b815260040160405180910390fd5b610c7c816117c0565b50565b336001600160a01b037f000000000000000000000000f6d1cabe63237970b0e5fec45afc5b2c1312d8e01614610cc857604051633461661160e01b815260040160405180910390fd5b604051630e097de760e01b8152600481018390525f906001600160a01b03881690630e097de790602401602060405180830381865afa158015610d0d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d319190611c6f565b610d3b9085611c9a565b604051630e097de760e01b8152600481018490529091505f906001600160a01b03891690630e097de790602401602060405180830381865afa158015610d83573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610da79190611c6f565b610db18787611cb1565b610dbb9190611c9a565b9050610dc5611538565b506004545f88815260056020526040902054610df184836b92efd1b8d0cf37be5aa1cae560291b61168c565b610dfb9190611cb1565b5f8981526006602052604081208054909190610e18908490611cc4565b90915550610e38905082826b92efd1b8d0cf37be5aa1cae560291b61168c565b5f98895260056020526040909820979097555050505050505050565b604051631f22ecbf60e21b815260ff7f00000000000000000000000000000000000000000000000000000000000000001660048201525f9081906001600160a01b037f000000000000000000000000ff1b7120baaa89acde6e45ccfb2263a8416c20f01690637c8bb2fc90602401602060405180830381865afa158015610edd573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f019190611c6f565b6002545f54600454929350909181831015610f68575f824211610f245742610f26565b825b90505f610f366102f68684611cb1565b90508515610f6557610f58816b92efd1b8d0cf37be5aa1cae560291b8861168c565b610f629084611cc4565b92505b50505b60405163e48dc13560e01b8152600481018790525f907f000000000000000000000000ff1b7120baaa89acde6e45ccfb2263a8416c20f06001600160a01b03169063e48dc1359060240160c060405180830381865afa158015610fcd573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ff19190611d8b565b6040516375ed572560e11b815260ff7f00000000000000000000000000000000000000000000000000000000000000001660048201529091505f906001600160a01b037f000000000000000000000000ff1b7120baaa89acde6e45ccfb2263a8416c20f0169063ebdaae4a906024015f60405180830381865afa15801561107a573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526110a19190810190611ee0565b61014001516001600160a01b0316630e097de7836080015164ffffffffff166040518263ffffffff1660e01b81526004016110de91815260200190565b602060405180830381865afa1580156110f9573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061111d9190611c6f565b82604001516fffffffffffffffffffffffffffffffff1661113e9190611c9a565b5f898152600560205260408120549192509061116a83866b92efd1b8d0cf37be5aa1cae560291b61168c565b6111749190611cb1565b5f8a81526006602052604090205490915061118f9082611cc4565b9998505050505050505050565b336001600160a01b037f000000000000000000000000f6d1cabe63237970b0e5fec45afc5b2c1312d8e016146111e557604051633461661160e01b815260040160405180910390fd5b6111ed611538565b5060048054604051630e097de760e01b8152918201839052905f906001600160a01b03891690630e097de790602401602060405180830381865afa158015611237573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061125b9190611c6f565b5f8881526005602052604090205490915061127a8561044b8585611c9a565b6112849190611cb1565b5f88815260066020526040812080549091906112a1908490611cc4565b909155506112be90506112b48686611cb1565b61044b8484611c9a565b5f888152600560205260409020556112da8561044b8484611c9a565b5f968752600560205260409096209590955550505050505050565b5f612710826003546113079190611c9a565b6113119190612004565b92915050565b7f000000000000000000000000f6d1cabe63237970b0e5fec45afc5b2c1312d8e06001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611373573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113979190611d0f565b6001600160a01b0316336001600160a01b0316146113c857604051630d99ba6360e41b815260040160405180910390fd5b6113fd6001600160a01b037f000000000000000000000000d2b4c9b0d70e3da1fbdd98f469bd02e77e12fc79163330846117fb565b610c7c8161183a565b336001600160a01b037f000000000000000000000000f6d1cabe63237970b0e5fec45afc5b2c1312d8e0161461144f57604051633461661160e01b815260040160405180910390fd5b604051630e097de760e01b8152600481018390525f906001600160a01b03881690630e097de790602401602060405180830381865afa158015611494573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114b89190611c6f565b6114c29085611c9a565b604051630e097de760e01b8152600481018490529091505f906001600160a01b03891690630e097de790602401602060405180830381865afa15801561150a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061152e9190611c6f565b610db18787611cc4565b604051631f22ecbf60e21b815260ff7f00000000000000000000000000000000000000000000000000000000000000001660048201525f9081906001600160a01b037f000000000000000000000000ff1b7120baaa89acde6e45ccfb2263a8416c20f01690637c8bb2fc90602401602060405180830381865afa1580156115c1573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115e59190611c6f565b6002545f54919250908082101561164f575f8142116116045742611606565b815b90506116156102f68483611cb1565b9450831561164d57611637856b92efd1b8d0cf37be5aa1cae560291b8661168c565b60045f8282546116479190611cc4565b90915550505b505b426002556040518481527fcb8241adb0c3fdb35b70c24ce35c5eb0c17af7431c99f827d44a445ca624176a9060200160405180910390a150505090565b5f838302815f1985870982811083820303915050805f036116c0578382816116b6576116b6611ff0565b0492505050611745565b8084116116e05760405163227bc15360e01b815260040160405180910390fd5b5f848688095f868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150505b9392505050565b6040516001600160a01b038381166024830152604482018390526106b691859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506118e9565b60018190556040518181527f66e1dffea17302ec11b493c94870e341ef6b7d6cedeea746890cbe648c62b86b9060200160405180910390a150565b6040516001600160a01b0384811660248301528381166044830152606482018390526118349186918216906323b872dd90608401611779565b50505050565b805f0361185a576040516352b31e1560e01b815260040160405180910390fd5b6002545f548281831015611882576118756102f68484611cb1565b61187f9082611cc4565b90505b6001548061189261271084611c9a565b61189c9190612004565b6003556118a98142611cc4565b5f55426002556040518581527f27b2dc149fd3048bc27eadaaf660801a04305c72845da74066a17b72d6c5bb669060200160405180910390a15050505050565b5f6118fd6001600160a01b0384168361194f565b905080515f1415801561192157508080602001905181019061191f9190612023565b155b156106b657604051635274afe760e01b81526001600160a01b03841660048201526024015b60405180910390fd5b606061174583835f845f80856001600160a01b03168486604051611973919061203c565b5f6040518083038185875af1925050503d805f81146119ad576040519150601f19603f3d011682016040523d82523d5f602084013e6119b2565b606091505b50915091506119c28683836119cc565b9695505050505050565b6060826119e1576119dc82611a28565b611745565b81511580156119f857506001600160a01b0384163b155b15611a2157604051639996b31560e01b81526001600160a01b0385166004820152602401611946565b5080611745565b805115611a385780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b6001600160a01b0381168114610c7c575f80fd5b5f805f805f805f805f6101208a8c031215611a7e575f80fd5b8935611a8981611a51565b9b60208b01359b5060408b01359a60608101359a506080810135995060a0810135985060c0810135975060e081013596506101000135945092505050565b5f8060408385031215611ad8575f80fd5b823591506020830135611aea81611a51565b809150509250929050565b5f805f805f60a08688031215611b09575f80fd5b8535611b1481611a51565b97602087013597506040870135966060810135965060800135945092505050565b5f60208284031215611b45575f80fd5b5035919050565b604080825283519082018190525f906020906060840190828701845b82811015611b8d5781516001600160a01b031684529284019290840190600101611b68565b505050838103828501528451808252858301918301905f5b81811015611bc157835183529284019291840191600101611ba5565b5090979650505050505050565b5f805f805f805f80610100898b031215611be6575f80fd5b8835611bf181611a51565b9a60208a01359a5060408a013599606081013599506080810135985060a0810135975060c0810135965060e00135945092505050565b5f805f805f8060c08789031215611c3c575f80fd5b8635611c4781611a51565b9860208801359850604088013597606081013597506080810135965060a00135945092505050565b5f60208284031215611c7f575f80fd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b808202811582820484141761131157611311611c86565b8181038181111561131157611311611c86565b8082018082111561131157611311611c86565b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b8051611d0a81611a51565b919050565b5f60208284031215611d1f575f80fd5b815161174581611a51565b60405160c0810167ffffffffffffffff81118282101715611d4d57611d4d611cd7565b60405290565b604051610160810167ffffffffffffffff81118282101715611d4d57611d4d611cd7565b805164ffffffffff81168114611d0a575f80fd5b5f60c08284031215611d9b575f80fd5b611da3611d2a565b825181526020830151602082015260408301516fffffffffffffffffffffffffffffffff81168114611dd3575f80fd5b6040820152611de460608401611d77565b6060820152611df560808401611d77565b608082015260a083015160ff81168114611e0d575f80fd5b60a08201529392505050565b5f5b83811015611e33578181015183820152602001611e1b565b50505f910152565b5f82601f830112611e4a575f80fd5b815167ffffffffffffffff80821115611e6557611e65611cd7565b604051601f8301601f19908116603f01168101908282118183101715611e8d57611e8d611cd7565b81604052838152866020858801011115611ea5575f80fd5b6119c2846020830160208901611e19565b80518015158114611d0a575f80fd5b80516bffffffffffffffffffffffff81168114611d0a575f80fd5b5f60208284031215611ef0575f80fd5b815167ffffffffffffffff80821115611f07575f80fd5b908301906101608286031215611f1b575f80fd5b611f23611d53565b825182811115611f31575f80fd5b611f3d87828601611e3b565b8252506020830151602082015260408301516040820152611f6060608401611cff565b6060820152611f7160808401611cff565b6080820152611f8260a08401611cff565b60a0820152611f9360c08401611cff565b60c0820152611fa460e08401611d77565b60e08201526101009150611fb9828401611eb6565b828201526101209150611fcd828401611ec5565b828201526101409150611fe1828401611cff565b91810191909152949350505050565b634e487b7160e01b5f52601260045260245ffd5b5f8261201e57634e487b7160e01b5f52601260045260245ffd5b500490565b5f60208284031215612033575f80fd5b61174582611eb6565b5f825161204d818460208701611e19565b919091019291505056fea26469706673582212201dc2ea35c67cc7b02e7ce4462bbcb82884b1fde25470c7a8d9ea4357aaef27b464736f6c63430008170033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000d2b4c9b0d70e3da1fbdd98f469bd02e77e12fc79000000000000000000000000ff1b7120baaa89acde6e45ccfb2263a8416c20f00000000000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : _rewardToken (address): 0xD2B4C9B0d70e3Da1fBDD98f469bD02E77E12FC79
Arg [1] : _reliquary (address): 0xfF1B7120BaAA89ACDE6e45Ccfb2263A8416C20F0
Arg [2] : _poolId (uint8): 0
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000d2b4c9b0d70e3da1fbdd98f469bd02e77e12fc79
Arg [1] : 000000000000000000000000ff1b7120baaa89acde6e45ccfb2263a8416c20f0
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in MNT
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.