Source Code
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
VotiumStrategy
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
import {Ownable} from "solady/src/auth/Ownable.sol";
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import {TrackedAllowances, Allowance} from "../utils/TrackedAllowances.sol";
import {FixedPointMathLib} from "solady/src/utils/FixedPointMathLib.sol";
import {SafeTransferLib} from "solady/src/utils/SafeTransferLib.sol";
import {CvxEthOracleLib} from "../utils/CvxEthOracleLib.sol";
import {SafeCastLib} from "solady/src/utils/SafeCastLib.sol";
import {HashLib} from "../utils/HashLib.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {ILockedCvx, LOCKED_CVX} from "../interfaces/curve-convex/ILockedCvx.sol";
import {IVotiumStrategy} from "../interfaces/afeth/IVotiumStrategy.sol";
import {IVotiumMerkleStash, VOTIUM_MERKLE_STASH} from "../interfaces/curve-convex/IVotiumMerkleStash.sol";
import {ISnapshotDelegationRegistry} from "../interfaces/curve-convex/ISnapshotDelegationRegistry.sol";
import {CVX_ETH_POOL, ETH_COIN_INDEX, CVX_COIN_INDEX} from "../interfaces/curve-convex/ICvxEthPool.sol";
import {LOCKED_CVX} from "../interfaces/curve-convex/ILockedCvx.sol";
import {ZAP_CLAIM} from "../interfaces/IClaimZap.sol";
import {CVX} from "../interfaces/curve-convex/Constants.sol";
import {IAfEth} from "../interfaces/afeth/IAfEth.sol";
/// @title Votium Strategy Token
/// @author Asymmetry Finance
contract VotiumStrategy is IVotiumStrategy, Ownable, TrackedAllowances, UUPSUpgradeable {
using FixedPointMathLib for uint256;
using SafeTransferLib for address;
using SafeCastLib for uint256;
using HashLib for string;
address public constant SNAPSHOT_DELEGATE_REGISTRY = 0x469788fE6E9E9681C6ebF3bF78e7Fd26Fc015446;
bytes32 internal constant VOTE_DELEGATION_ID = "cvx.eth";
address internal constant VOTE_PROXY = 0xde1E6A7ED0ad3F61D531a8a78E83CcDdbd6E0c49;
bytes32 internal immutable LCVX_NO_EXP_LOCKS_ERROR_HASH = keccak256("no exp locks");
bytes32 internal immutable LCVX_SHUTDOWN_ERROR_HASH = keccak256("shutdown");
struct Swap {
address target;
bytes callData;
}
address public immutable manager;
address public rewarder;
/// @dev Tracks the total amount of CVX unlock obligations the contract has ever had.
uint128 internal cumulativeCvxUnlockObligations;
/// @dev Tracks the total amount of CVX that has ever been unlocked.
uint128 internal cumulativeCvxUnlocked;
uint256 public unprocessedRewards;
mapping(address => mapping(uint256 => uint256)) public withdrawableAfterUnlocked;
receive() external payable {}
modifier onlyRewarder() {
if (msg.sender != rewarder) revert Unauthorized();
_;
}
modifier onlyManager() {
if (msg.sender != manager) revert Unauthorized();
_;
}
modifier notShutdown() {
if (rewarder == address(0)) revert Shutdown();
_;
}
// As recommended by https://docs.openzeppelin.com/upgrades-plugins/1.x/writing-upgradeable
/// @custom:oz-upgrades-unsafe-allow constructor
constructor(address afEth) {
_disableInitializers();
manager = afEth;
}
/**
* @notice - Function to initialize values for the contracts
* @dev - This replaces- the constructor for upgradeable contracts
* @param initialOwner Address of the owner of the contract (asym multisig)
* @param initialRewarder Address of the rewarder contract (reward oracle)
*/
function initialize(address initialOwner, address initialRewarder) external initializer {
ISnapshotDelegationRegistry(SNAPSHOT_DELEGATE_REGISTRY).setDelegate(VOTE_DELEGATION_ID, VOTE_PROXY);
rewarder = initialRewarder;
_initializeOwner(initialOwner);
__UUPSUpgradeable_init();
// Approve once to save gas later by avoiding having to re-approve every time.
_grantAndTrackInfiniteAllowance(Allowance({spender: address(LOCKED_CVX), token: CVX}));
_grantAndTrackInfiniteAllowance(Allowance({spender: address(CVX_ETH_POOL), token: CVX}));
emit RewarderSet(initialRewarder);
}
/**
* @dev Allows the owner of the contract to upgrade to *any* new address.
*/
function _authorizeUpgrade(address /* newImplementation */ ) internal view override onlyOwner {}
/**
* @notice - Function to set the Votium delegate address
* @param _delegate Address of the delegate
* @param _id ID of the delegate
*/
function setDelegate(address _delegate, bytes32 _id) external onlyOwner {
ISnapshotDelegationRegistry(SNAPSHOT_DELEGATE_REGISTRY).setDelegate(_id, _delegate);
}
/**
* @notice - Function to set the address of the rewarder account that periodically claims rewards
* @param newRewarder Address of the rewarder account
*/
function setRewarder(address newRewarder) external onlyOwner {
rewarder = newRewarder;
emit RewarderSet(newRewarder);
}
/**
* @dev Call in emergencies incase you need to stop all calls and transfers until further notice
*/
function emergencyShutdown() external {
if (!(msg.sender == owner() || msg.sender == manager)) revert Unauthorized();
rewarder = address(0);
_emergencyRevokeAllAllowances();
emit RewarderSet(address(0));
emit EmergencyShutdown();
}
/**
* @dev Using this function on its own is **unsafe** as it does not set a minimum out. Only use
* in conjunction with some price checking mechanism.
* @notice Deposit eth to mint this token at current price
* @return cvxAmount Amount of CVX bought
*/
function deposit() external payable returns (uint256 cvxAmount) {
cvxAmount = deposit(0);
}
/**
* @notice Sells amount of ETH from votium contract for CVX.
* @param cvxMinOut Minimum amount of CVX to receive
*/
function deposit(uint256 cvxMinOut) public payable onlyManager returns (uint256 cvxAmount) {
cvxAmount = unsafeBuyCvx(msg.value);
if (cvxAmount < cvxMinOut) revert ExchangeOutputBelowMin();
(,, uint256 totalUnlockObligations) = getObligations();
if (cvxAmount >= totalUnlockObligations) {
_processExpiredLocks(true);
unchecked {
uint256 lockAmount = cvxAmount - totalUnlockObligations;
if (lockAmount > 0) _lock(lockAmount);
}
} else {
uint256 unlocked = _unlockAvailable();
if (unlocked > totalUnlockObligations) {
unchecked {
_lock(unlocked - totalUnlockObligations);
}
}
}
}
/**
* @notice Request to withdraw from strategy emits event with eligible withdraw epoch
* @notice Burns afEth tokens and determines equivilent amount of cvx to start unlocking
* @param share Share of total CVX to be withdrawn in WAD.
* @return locked Whether the amount to withdraw is still locked.
* @return ethOutNow The amount of ETH that was withdrawn now (0 if locked).
* @return cumulativeUnlockThreshold The cumulative unlock amount at which the amount will be
* withdrawable.
*/
function requestWithdraw(uint256 share, address to)
external
onlyManager
returns (bool locked, uint256 ethOutNow, uint256 cumulativeUnlockThreshold)
{
if (share == 0) return (false, 0, 0);
(, uint256 cumCvxUnlockObligations, uint256 totalUnlockObligations) = getObligations();
uint256 unlockedCvx = _unlockAvailable();
uint256 lockedCvx = _lockedBalance();
uint256 netCvx = lockedCvx + unlockedCvx - totalUnlockObligations;
uint256 cvxAmount = netCvx.mulWad(share);
totalUnlockObligations += cvxAmount;
if (unlockedCvx >= totalUnlockObligations) {
ethOutNow = unsafeSellCvx(cvxAmount);
unchecked {
uint256 lockAmount = unlockedCvx - totalUnlockObligations;
if (lockAmount > 0) _lock(lockAmount);
}
} else {
locked = true;
cumulativeUnlockThreshold = uint128(cumCvxUnlockObligations) + cvxAmount.toUint128();
// Have to increment in case `cvxAmount` right after another request.
withdrawableAfterUnlocked[to][cumulativeUnlockThreshold] += cvxAmount;
cumulativeCvxUnlockObligations = uint128(cumulativeUnlockThreshold);
}
if (ethOutNow > 0) msg.sender.safeTransferETH(ethOutNow);
}
/**
* @notice Withdraws from requested withdraw if eligible epoch has passed
* @param cumulativeUnlockThreshold The unlock amount threshold at which the CVX is meant to unlock.
* @param minOut The minimum ETH to receive when swapping the CVX to withdraw to ETH. Will
* transfer the CVX itself if set to 0.
* @param deadline Timestamp after which the withdraw call should become invalid.
*/
function withdrawLocked(uint256 cumulativeUnlockThreshold, uint256 minOut, uint256 deadline)
external
notShutdown
returns (uint256 ethReceived)
{
if (block.timestamp > deadline) revert StaleAction();
uint256 cvxAmount = withdrawableAfterUnlocked[msg.sender][cumulativeUnlockThreshold];
if (cvxAmount == 0) return ethReceived;
(uint256 cumCvxUnlocked,, uint256 totalUnlockObligations) = getObligations();
uint256 unlockedCvx = _unlockAvailable();
// Check if unlock threshold has already been reached, otherwise ensure there's sufficient
// liquid CVX to cover the delta.
if (cumulativeUnlockThreshold > cumCvxUnlocked) {
unchecked {
uint256 minUnlock = cumulativeUnlockThreshold - cumCvxUnlocked;
if (unlockedCvx < minUnlock) revert WithdrawalStillLocked();
}
}
delete withdrawableAfterUnlocked[msg.sender][cumulativeUnlockThreshold];
cumulativeCvxUnlocked = uint128(cumCvxUnlocked) + cvxAmount.toUint128();
if (unlockedCvx > totalUnlockObligations) {
unchecked {
_lock(unlockedCvx - totalUnlockObligations);
}
}
if (minOut == 0) {
CVX.safeTransfer(msg.sender, cvxAmount);
} else {
ethReceived = unsafeSellCvx(cvxAmount);
if (ethReceived < minOut) revert ExchangeOutputBelowMin();
if (ethReceived > 0) msg.sender.safeTransferETH(ethReceived);
}
}
/**
* @notice Relock on behalf of entire lock.
* @dev Needs to be called every few weeks if regular deposits / withdrawals aren't
* happening to prevent receiving losses from kick penalties.
*/
function processAndRelock() external {
(,, uint256 totalUnlockObligations) = getObligations();
uint256 unlockedCvx = _unlockAvailable();
if (unlockedCvx > totalUnlockObligations) {
unchecked {
_lock(unlockedCvx - totalUnlockObligations);
}
}
}
/**
* @notice Allow rewarder oracle account to claim rewards
* @param claimProofs - Array of claim proofs
*/
function claimRewards(IVotiumMerkleStash.ClaimParam[] calldata claimProofs) external onlyRewarder {
uint256 cvxBalanceBefore = CVX.balanceOf(address(this));
try VOTIUM_MERKLE_STASH.claimMulti(address(this), claimProofs) {} catch {}
address[] memory emptyArray;
try ZAP_CLAIM.claimRewards(emptyArray, emptyArray, emptyArray, emptyArray, 0, 0, 0, 0, 8) {} catch {}
// Assumes neither claim function can reenter, reentrancy would allow for double-counting
// rewards and allow the rewarder to drain any unlocked CVX.
uint256 newRewards = CVX.balanceOf(address(this)) - cvxBalanceBefore;
if (newRewards > 0) {
unprocessedRewards += newRewards;
// CVX is already liquid, just ensures that withdraw/deposit don't use the reward amount so
// it's already available for swapping.
cumulativeCvxUnlockObligations += newRewards.toUint128();
}
}
/**
* @dev Grant additional allowances required for the {applyRewards} function to actually be able
* to execute various swaps on behalf of this contract. Allowance are tracked and can be revoked
* all together via the {emergencyShutdown} function.
*/
function grantAddedAllowances(Allowance[] calldata allowances) external onlyOwner {
uint256 totalAllowances = allowances.length;
for (uint256 i = 0; i < totalAllowances; i++) {
_grantAndTrackInfiniteAllowance(allowances[i]);
}
}
function revokeSingleAllowance(Allowance calldata allowance) external onlyOwner {
_revokeSingleAllowance(allowance);
}
/**
* @notice Function for rewarder to sell all claimed token rewards and buy & lock more cvx
* @dev Causes price to go up
* @param swaps Array of Swap structs for 0x swaps.
* @param cvxPerEthMin Minimum accepted ETH/CVX price when converting ETH to CVX.
* @param sfrxPerEthMin Minimum accepted ETH/sfrxETH price when converting ETH to sfrxETH.
* @param ethPerSfrxMin Maximum accepted ETH/sfrxETH price when converting sfrxETH to ETH.
* @param deadline Minimum amount of cvx to mint from rewards
*/
function swapRewards(
Swap[] calldata swaps,
uint256 cvxPerEthMin,
uint256 sfrxPerEthMin,
uint256 ethPerSfrxMin,
uint256 deadline
) external onlyRewarder {
if (block.timestamp > deadline) revert StaleAction();
address manager_ = manager;
uint256 cvxBalanceBefore = CVX.balanceOf(address(this));
uint256 totalSwaps = swaps.length;
for (uint256 i = 0; i < totalSwaps; i++) {
Swap calldata swap = swaps[i];
address target = swap.target;
_checkTargetAuthorized(manager_, target);
(bool success,) = target.call(swap.callData);
if (!success) emit FailedToSell(i);
}
// Ensure CVX isn't indirectly stolen via approved addresses.
uint256 cvxBalanceAfter = CVX.balanceOf(address(this));
if (cvxBalanceBefore > cvxBalanceAfter) {
uint256 cvxSwapped;
unchecked {
cvxSwapped = cvxBalanceBefore - cvxBalanceAfter;
}
// Implicit underflow check ensures only rewards are spent.
unprocessedRewards -= cvxSwapped;
cumulativeCvxUnlocked += cvxSwapped.toUint128();
}
IAfEth(manager_).depositRewardsAndRebalance{value: address(this).balance}(
IAfEth.RebalanceParams({
cvxPerEthMin: cvxPerEthMin,
sfrxPerEthMin: sfrxPerEthMin,
ethPerSfrxMin: ethPerSfrxMin,
deadline: block.timestamp
})
);
}
/**
* @notice The amount of CVX in the entire system
* @return Amount of CVX in the entire system
*/
function availableCvx() public view returns (uint256) {
(,, uint256 totalUnlockObligations) = getObligations();
uint256 lockedCvx = _lockedBalance();
uint256 unlockedCvx = CVX.balanceOf(address(this));
return lockedCvx + unlockedCvx - totalUnlockObligations;
}
function totalEthValue() external view returns (uint256 value, uint256 price) {
price = CvxEthOracleLib.ethCvxPrice();
value = availableCvx().mulWad(price);
}
function getObligations()
public
view
returns (uint256 cumCvxUnlocked, uint256 cumCvxUnlockObligations, uint256 totalUnlockObligations)
{
cumCvxUnlocked = cumulativeCvxUnlocked;
cumCvxUnlockObligations = cumulativeCvxUnlockObligations;
totalUnlockObligations = cumCvxUnlockObligations - cumCvxUnlocked;
}
/**
* @dev Swaps `ethAmountIn` ETH for CVX. Unsafe as it does not check min out, must be checked
* by caller.
* @param ethAmountIn Amount of ETH to spend
* @return cvxAmountOut Amount of CVX bought
*/
function unsafeBuyCvx(uint256 ethAmountIn) internal returns (uint256 cvxAmountOut) {
cvxAmountOut =
CVX_ETH_POOL.exchange_underlying{value: ethAmountIn}(ETH_COIN_INDEX, CVX_COIN_INDEX, ethAmountIn, 0);
}
/**
* @dev Swaps `cvxAmountIn` CVX for ETH. Unsafe as it does not check min out, must be checked
* by caller.
* @param cvxAmountIn Amount of ETH to spend
* @return ethAmountOut Amount of CVX bought
*/
function unsafeSellCvx(uint256 cvxAmountIn) internal returns (uint256 ethAmountOut) {
ethAmountOut = CVX_ETH_POOL.exchange_underlying(CVX_COIN_INDEX, ETH_COIN_INDEX, cvxAmountIn, 0);
}
function _unlockAvailable() internal returns (uint256 totalUnlocked) {
_processExpiredLocks(false);
totalUnlocked = CVX.balanceOf(address(this));
}
function _lock(uint256 amount) internal {
try LOCKED_CVX.lock(address(this), amount, 0) {}
catch Error(string memory err) {
if (err.hash() != LCVX_SHUTDOWN_ERROR_HASH) revert UnexpectedLockedCvxError();
}
}
function _lockedBalance() internal view returns (uint256) {
return LOCKED_CVX.lockedBalanceOf(address(this));
}
function _processExpiredLocks(bool relock) internal {
if (_lockedBalance() > 0) {
try LOCKED_CVX.processExpiredLocks({relock: relock}) {}
catch Error(string memory err) {
if (err.hash() != LCVX_NO_EXP_LOCKS_ERROR_HASH) revert UnexpectedLockedCvxError();
}
}
}
function _checkTargetAuthorized(address manager_, address target) internal view {
// Ensure compromised rewarder can't directly steal CVX.
if (target == manager_ || target == address(LOCKED_CVX) || target == address(CVX) || target == address(this)) {
revert UnauthorizedTarget();
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Simple single owner authorization mixin.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol)
///
/// @dev Note:
/// This implementation does NOT auto-initialize the owner to `msg.sender`.
/// You MUST call the `_initializeOwner` in the constructor / initializer.
///
/// While the ownable portion follows
/// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility,
/// the nomenclature for the 2-step ownership handover may be unique to this codebase.
abstract contract Ownable {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The caller is not authorized to call the function.
error Unauthorized();
/// @dev The `newOwner` cannot be the zero address.
error NewOwnerIsZeroAddress();
/// @dev The `pendingOwner` does not have a valid handover request.
error NoHandoverRequest();
/// @dev Cannot double-initialize.
error AlreadyInitialized();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EVENTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The ownership is transferred from `oldOwner` to `newOwner`.
/// This event is intentionally kept the same as OpenZeppelin's Ownable to be
/// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173),
/// despite it not being as lightweight as a single argument event.
event OwnershipTransferred(address indexed oldOwner, address indexed newOwner);
/// @dev An ownership handover to `pendingOwner` has been requested.
event OwnershipHandoverRequested(address indexed pendingOwner);
/// @dev The ownership handover to `pendingOwner` has been canceled.
event OwnershipHandoverCanceled(address indexed pendingOwner);
/// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`.
uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE =
0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0;
/// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`.
uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE =
0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d;
/// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`.
uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE =
0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STORAGE */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The owner slot is given by:
/// `bytes32(~uint256(uint32(bytes4(keccak256("_OWNER_SLOT_NOT")))))`.
/// It is intentionally chosen to be a high value
/// to avoid collision with lower slots.
/// The choice of manual storage layout is to enable compatibility
/// with both regular and upgradeable contracts.
bytes32 internal constant _OWNER_SLOT =
0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927;
/// The ownership handover slot of `newOwner` is given by:
/// ```
/// mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED))
/// let handoverSlot := keccak256(0x00, 0x20)
/// ```
/// It stores the expiry timestamp of the two-step ownership handover.
uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INTERNAL FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Override to return true to make `_initializeOwner` prevent double-initialization.
function _guardInitializeOwner() internal pure virtual returns (bool guard) {}
/// @dev Initializes the owner directly without authorization guard.
/// This function must be called upon initialization,
/// regardless of whether the contract is upgradeable or not.
/// This is to enable generalization to both regular and upgradeable contracts,
/// and to save gas in case the initial owner is not the caller.
/// For performance reasons, this function will not check if there
/// is an existing owner.
function _initializeOwner(address newOwner) internal virtual {
if (_guardInitializeOwner()) {
/// @solidity memory-safe-assembly
assembly {
let ownerSlot := _OWNER_SLOT
if sload(ownerSlot) {
mstore(0x00, 0x0dc149f0) // `AlreadyInitialized()`.
revert(0x1c, 0x04)
}
// Clean the upper 96 bits.
newOwner := shr(96, shl(96, newOwner))
// Store the new value.
sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner))))
// Emit the {OwnershipTransferred} event.
log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)
}
} else {
/// @solidity memory-safe-assembly
assembly {
// Clean the upper 96 bits.
newOwner := shr(96, shl(96, newOwner))
// Store the new value.
sstore(_OWNER_SLOT, newOwner)
// Emit the {OwnershipTransferred} event.
log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)
}
}
}
/// @dev Sets the owner directly without authorization guard.
function _setOwner(address newOwner) internal virtual {
if (_guardInitializeOwner()) {
/// @solidity memory-safe-assembly
assembly {
let ownerSlot := _OWNER_SLOT
// Clean the upper 96 bits.
newOwner := shr(96, shl(96, newOwner))
// Emit the {OwnershipTransferred} event.
log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)
// Store the new value.
sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner))))
}
} else {
/// @solidity memory-safe-assembly
assembly {
let ownerSlot := _OWNER_SLOT
// Clean the upper 96 bits.
newOwner := shr(96, shl(96, newOwner))
// Emit the {OwnershipTransferred} event.
log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)
// Store the new value.
sstore(ownerSlot, newOwner)
}
}
}
/// @dev Throws if the sender is not the owner.
function _checkOwner() internal view virtual {
/// @solidity memory-safe-assembly
assembly {
// If the caller is not the stored owner, revert.
if iszero(eq(caller(), sload(_OWNER_SLOT))) {
mstore(0x00, 0x82b42900) // `Unauthorized()`.
revert(0x1c, 0x04)
}
}
}
/// @dev Returns how long a two-step ownership handover is valid for in seconds.
/// Override to return a different value if needed.
/// Made internal to conserve bytecode. Wrap it in a public function if needed.
function _ownershipHandoverValidFor() internal view virtual returns (uint64) {
return 48 * 3600;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* PUBLIC UPDATE FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Allows the owner to transfer the ownership to `newOwner`.
function transferOwnership(address newOwner) public payable virtual onlyOwner {
/// @solidity memory-safe-assembly
assembly {
if iszero(shl(96, newOwner)) {
mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`.
revert(0x1c, 0x04)
}
}
_setOwner(newOwner);
}
/// @dev Allows the owner to renounce their ownership.
function renounceOwnership() public payable virtual onlyOwner {
_setOwner(address(0));
}
/// @dev Request a two-step ownership handover to the caller.
/// The request will automatically expire in 48 hours (172800 seconds) by default.
function requestOwnershipHandover() public payable virtual {
unchecked {
uint256 expires = block.timestamp + _ownershipHandoverValidFor();
/// @solidity memory-safe-assembly
assembly {
// Compute and set the handover slot to `expires`.
mstore(0x0c, _HANDOVER_SLOT_SEED)
mstore(0x00, caller())
sstore(keccak256(0x0c, 0x20), expires)
// Emit the {OwnershipHandoverRequested} event.
log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller())
}
}
}
/// @dev Cancels the two-step ownership handover to the caller, if any.
function cancelOwnershipHandover() public payable virtual {
/// @solidity memory-safe-assembly
assembly {
// Compute and set the handover slot to 0.
mstore(0x0c, _HANDOVER_SLOT_SEED)
mstore(0x00, caller())
sstore(keccak256(0x0c, 0x20), 0)
// Emit the {OwnershipHandoverCanceled} event.
log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller())
}
}
/// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`.
/// Reverts if there is no existing ownership handover requested by `pendingOwner`.
function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner {
/// @solidity memory-safe-assembly
assembly {
// Compute and set the handover slot to 0.
mstore(0x0c, _HANDOVER_SLOT_SEED)
mstore(0x00, pendingOwner)
let handoverSlot := keccak256(0x0c, 0x20)
// If the handover does not exist, or has expired.
if gt(timestamp(), sload(handoverSlot)) {
mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`.
revert(0x1c, 0x04)
}
// Set the handover slot to 0.
sstore(handoverSlot, 0)
}
_setOwner(pendingOwner);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* PUBLIC READ FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the owner of the contract.
function owner() public view virtual returns (address result) {
/// @solidity memory-safe-assembly
assembly {
result := sload(_OWNER_SLOT)
}
}
/// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`.
function ownershipHandoverExpiresAt(address pendingOwner)
public
view
virtual
returns (uint256 result)
{
/// @solidity memory-safe-assembly
assembly {
// Compute the handover slot.
mstore(0x0c, _HANDOVER_SLOT_SEED)
mstore(0x00, pendingOwner)
// Load the handover slot.
result := sload(keccak256(0x0c, 0x20))
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* MODIFIERS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Marks a function as only callable by the owner.
modifier onlyOwner() virtual {
_checkOwner();
_;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/UUPSUpgradeable.sol)
pragma solidity ^0.8.20;
import {IERC1822Proxiable} from "@openzeppelin/contracts/interfaces/draft-IERC1822.sol";
import {ERC1967Utils} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol";
import {Initializable} from "./Initializable.sol";
/**
* @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
* {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
*
* A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
* reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
* `UUPSUpgradeable` with a custom implementation of upgrades.
*
* The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
*/
abstract contract UUPSUpgradeable is Initializable, IERC1822Proxiable {
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
address private immutable __self = address(this);
/**
* @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgradeTo(address)`
* and `upgradeToAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called,
* while `upgradeToAndCall` will invoke the `receive` function if the second argument is the empty byte string.
* If the getter returns `"5.0.0"`, only `upgradeToAndCall(address,bytes)` is present, and the second argument must
* be the empty byte string if no function should be called, making it impossible to invoke the `receive` function
* during an upgrade.
*/
string public constant UPGRADE_INTERFACE_VERSION = "5.0.0";
/**
* @dev The call is from an unauthorized context.
*/
error UUPSUnauthorizedCallContext();
/**
* @dev The storage `slot` is unsupported as a UUID.
*/
error UUPSUnsupportedProxiableUUID(bytes32 slot);
/**
* @dev Check that the execution is being performed through a delegatecall call and that the execution context is
* a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case
* for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
* function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
* fail.
*/
modifier onlyProxy() {
_checkProxy();
_;
}
/**
* @dev Check that the execution is not being performed through a delegate call. This allows a function to be
* callable on the implementing contract but not through proxies.
*/
modifier notDelegated() {
_checkNotDelegated();
_;
}
function __UUPSUpgradeable_init() internal onlyInitializing {
}
function __UUPSUpgradeable_init_unchained() internal onlyInitializing {
}
/**
* @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the
* implementation. It is used to validate the implementation's compatibility when performing an upgrade.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
*/
function proxiableUUID() external view virtual notDelegated returns (bytes32) {
return ERC1967Utils.IMPLEMENTATION_SLOT;
}
/**
* @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
* encoded in `data`.
*
* Calls {_authorizeUpgrade}.
*
* Emits an {Upgraded} event.
*
* @custom:oz-upgrades-unsafe-allow-reachable delegatecall
*/
function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy {
_authorizeUpgrade(newImplementation);
_upgradeToAndCallUUPS(newImplementation, data);
}
/**
* @dev Reverts if the execution is not performed via delegatecall or the execution
* context is not of a proxy with an ERC1967-compliant implementation pointing to self.
* See {_onlyProxy}.
*/
function _checkProxy() internal view virtual {
if (
address(this) == __self || // Must be called through delegatecall
ERC1967Utils.getImplementation() != __self // Must be called through an active proxy
) {
revert UUPSUnauthorizedCallContext();
}
}
/**
* @dev Reverts if the execution is performed via delegatecall.
* See {notDelegated}.
*/
function _checkNotDelegated() internal view virtual {
if (address(this) != __self) {
// Must not be called through delegatecall
revert UUPSUnauthorizedCallContext();
}
}
/**
* @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
* {upgradeToAndCall}.
*
* Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
*
* ```solidity
* function _authorizeUpgrade(address) internal onlyOwner {}
* ```
*/
function _authorizeUpgrade(address newImplementation) internal virtual;
/**
* @dev Performs an implementation upgrade with a security check for UUPS proxies, and additional setup call.
*
* As a security check, {proxiableUUID} is invoked in the new implementation, and the return value
* is expected to be the implementation slot in ERC1967.
*
* Emits an {IERC1967-Upgraded} event.
*/
function _upgradeToAndCallUUPS(address newImplementation, bytes memory data) private {
try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
if (slot != ERC1967Utils.IMPLEMENTATION_SLOT) {
revert UUPSUnsupportedProxiableUUID(slot);
}
ERC1967Utils.upgradeToAndCall(newImplementation, data);
} catch {
// The implementation is not UUPS
revert ERC1967Utils.ERC1967InvalidImplementation(newImplementation);
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {SafeTransferLib} from "solady/src/utils/SafeTransferLib.sol";
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
struct Allowance {
address spender;
address token;
}
/**
* @author philogy <https://github.com/philogy>
* @dev Tracks the list of addresses that have received an allowance from this contract
*/
abstract contract TrackedAllowances {
using EnumerableSet for EnumerableSet.Bytes32Set;
using SafeTransferLib for address;
/// @dev Derived from `keccak256("afeth.TrackedAllowances.storage") - 1`
uint256 internal constant TRACKED_ALLOWANCES_SLOT =
0x6628618d7bc4d0dd1eb0a5bb53ba475441105535e20645110834c8c5d548ddb4;
struct TrackedAllowanceStorage {
/**
* @dev While using extra gas, the enumerable set allows all allowances to be enumerated
* atomatically without relying on any additional indexing or log querying. This can be
* particularly useful in emergencies when allowances need to be revoked en-mass with minimal
* effort.
*/
EnumerableSet.Bytes32Set allowanceKeys;
mapping(bytes32 => Allowance) allowances;
}
function _emergencyRevokeAllAllowances() internal {
TrackedAllowanceStorage storage s = _storage();
uint256 totalAllowances = s.allowanceKeys.length();
for (uint256 i = 0; i < totalAllowances; i++) {
bytes32 allowanceKey = s.allowanceKeys.at(i);
Allowance storage allowance = s.allowances[allowanceKey];
allowance.token.safeApproveWithRetry(allowance.spender, 0);
}
// Could remove keys now that allowance is revoked but want to reduce gas to be spend in
// emergencies beyond what is directly needed for ease-of-use.
}
function _revokeSingleAllowance(Allowance memory allowance) internal {
TrackedAllowanceStorage storage s = _storage();
bytes32 allowanceKey = _allowanceKey(allowance);
s.allowanceKeys.remove(allowanceKey);
allowance.token.safeApproveWithRetry(allowance.spender, 0);
}
function _grantAndTrackInfiniteAllowance(Allowance memory allowance) internal {
TrackedAllowanceStorage storage s = _storage();
bytes32 allowanceKey = _allowanceKey(allowance);
s.allowanceKeys.add(allowanceKey);
s.allowances[allowanceKey] = allowance;
allowance.token.safeApproveWithRetry(allowance.spender, type(uint256).max);
}
function _allowanceKey(Allowance memory allowance) internal pure returns (bytes32) {
return keccak256(abi.encode(allowance));
}
function _storage() internal pure returns (TrackedAllowanceStorage storage s) {
/// @solidity memory-safe-assembly
assembly {
s.slot := TRACKED_ALLOWANCES_SLOT
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Arithmetic library with operations for fixed-point numbers.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/FixedPointMathLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol)
library FixedPointMathLib {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The operation failed, as the output exceeds the maximum value of uint256.
error ExpOverflow();
/// @dev The operation failed, as the output exceeds the maximum value of uint256.
error FactorialOverflow();
/// @dev The operation failed, due to an overflow.
error RPowOverflow();
/// @dev The mantissa is too big to fit.
error MantissaOverflow();
/// @dev The operation failed, due to an multiplication overflow.
error MulWadFailed();
/// @dev The operation failed, due to an multiplication overflow.
error SMulWadFailed();
/// @dev The operation failed, either due to a multiplication overflow, or a division by a zero.
error DivWadFailed();
/// @dev The operation failed, either due to a multiplication overflow, or a division by a zero.
error SDivWadFailed();
/// @dev The operation failed, either due to a multiplication overflow, or a division by a zero.
error MulDivFailed();
/// @dev The division failed, as the denominator is zero.
error DivFailed();
/// @dev The full precision multiply-divide operation failed, either due
/// to the result being larger than 256 bits, or a division by a zero.
error FullMulDivFailed();
/// @dev The output is undefined, as the input is less-than-or-equal to zero.
error LnWadUndefined();
/// @dev The input outside the acceptable domain.
error OutOfDomain();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The scalar of ETH and most ERC20s.
uint256 internal constant WAD = 1e18;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* SIMPLIFIED FIXED POINT OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Equivalent to `(x * y) / WAD` rounded down.
function mulWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to `require(y == 0 || x <= type(uint256).max / y)`.
if mul(y, gt(x, div(not(0), y))) {
mstore(0x00, 0xbac65e5b) // `MulWadFailed()`.
revert(0x1c, 0x04)
}
z := div(mul(x, y), WAD)
}
}
/// @dev Equivalent to `(x * y) / WAD` rounded down.
function sMulWad(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(x, y)
// Equivalent to `require((x == 0 || z / x == y) && !(x == -1 && y == type(int256).min))`.
if iszero(gt(or(iszero(x), eq(sdiv(z, x), y)), lt(not(x), eq(y, shl(255, 1))))) {
mstore(0x00, 0xedcd4dd4) // `SMulWadFailed()`.
revert(0x1c, 0x04)
}
z := sdiv(z, WAD)
}
}
/// @dev Equivalent to `(x * y) / WAD` rounded down, but without overflow checks.
function rawMulWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := div(mul(x, y), WAD)
}
}
/// @dev Equivalent to `(x * y) / WAD` rounded down, but without overflow checks.
function rawSMulWad(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := sdiv(mul(x, y), WAD)
}
}
/// @dev Equivalent to `(x * y) / WAD` rounded up.
function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to `require(y == 0 || x <= type(uint256).max / y)`.
if mul(y, gt(x, div(not(0), y))) {
mstore(0x00, 0xbac65e5b) // `MulWadFailed()`.
revert(0x1c, 0x04)
}
z := add(iszero(iszero(mod(mul(x, y), WAD))), div(mul(x, y), WAD))
}
}
/// @dev Equivalent to `(x * y) / WAD` rounded up, but without overflow checks.
function rawMulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := add(iszero(iszero(mod(mul(x, y), WAD))), div(mul(x, y), WAD))
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded down.
function divWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to `require(y != 0 && (WAD == 0 || x <= type(uint256).max / WAD))`.
if iszero(mul(y, iszero(mul(WAD, gt(x, div(not(0), WAD)))))) {
mstore(0x00, 0x7c5f487d) // `DivWadFailed()`.
revert(0x1c, 0x04)
}
z := div(mul(x, WAD), y)
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded down.
function sDivWad(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(x, WAD)
// Equivalent to `require(y != 0 && ((x * WAD) / WAD == x))`.
if iszero(and(iszero(iszero(y)), eq(sdiv(z, WAD), x))) {
mstore(0x00, 0x5c43740d) // `SDivWadFailed()`.
revert(0x1c, 0x04)
}
z := sdiv(mul(x, WAD), y)
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded down, but without overflow and divide by zero checks.
function rawDivWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := div(mul(x, WAD), y)
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded down, but without overflow and divide by zero checks.
function rawSDivWad(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := sdiv(mul(x, WAD), y)
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded up.
function divWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to `require(y != 0 && (WAD == 0 || x <= type(uint256).max / WAD))`.
if iszero(mul(y, iszero(mul(WAD, gt(x, div(not(0), WAD)))))) {
mstore(0x00, 0x7c5f487d) // `DivWadFailed()`.
revert(0x1c, 0x04)
}
z := add(iszero(iszero(mod(mul(x, WAD), y))), div(mul(x, WAD), y))
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded up, but without overflow and divide by zero checks.
function rawDivWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := add(iszero(iszero(mod(mul(x, WAD), y))), div(mul(x, WAD), y))
}
}
/// @dev Equivalent to `x` to the power of `y`.
/// because `x ** y = (e ** ln(x)) ** y = e ** (ln(x) * y)`.
function powWad(int256 x, int256 y) internal pure returns (int256) {
// Using `ln(x)` means `x` must be greater than 0.
return expWad((lnWad(x) * y) / int256(WAD));
}
/// @dev Returns `exp(x)`, denominated in `WAD`.
/// Credit to Remco Bloemen under MIT license: https://2π.com/21/exp-ln
function expWad(int256 x) internal pure returns (int256 r) {
unchecked {
// When the result is less than 0.5 we return zero.
// This happens when `x <= floor(log(0.5e18) * 1e18) ≈ -42e18`.
if (x <= -41446531673892822313) return r;
/// @solidity memory-safe-assembly
assembly {
// When the result is greater than `(2**255 - 1) / 1e18` we can not represent it as
// an int. This happens when `x >= floor(log((2**255 - 1) / 1e18) * 1e18) ≈ 135`.
if iszero(slt(x, 135305999368893231589)) {
mstore(0x00, 0xa37bfec9) // `ExpOverflow()`.
revert(0x1c, 0x04)
}
}
// `x` is now in the range `(-42, 136) * 1e18`. Convert to `(-42, 136) * 2**96`
// for more intermediate precision and a binary basis. This base conversion
// is a multiplication by 1e18 / 2**96 = 5**18 / 2**78.
x = (x << 78) / 5 ** 18;
// Reduce range of x to (-½ ln 2, ½ ln 2) * 2**96 by factoring out powers
// of two such that exp(x) = exp(x') * 2**k, where k is an integer.
// Solving this gives k = round(x / log(2)) and x' = x - k * log(2).
int256 k = ((x << 96) / 54916777467707473351141471128 + 2 ** 95) >> 96;
x = x - k * 54916777467707473351141471128;
// `k` is in the range `[-61, 195]`.
// Evaluate using a (6, 7)-term rational approximation.
// `p` is made monic, we'll multiply by a scale factor later.
int256 y = x + 1346386616545796478920950773328;
y = ((y * x) >> 96) + 57155421227552351082224309758442;
int256 p = y + x - 94201549194550492254356042504812;
p = ((p * y) >> 96) + 28719021644029726153956944680412240;
p = p * x + (4385272521454847904659076985693276 << 96);
// We leave `p` in `2**192` basis so we don't need to scale it back up for the division.
int256 q = x - 2855989394907223263936484059900;
q = ((q * x) >> 96) + 50020603652535783019961831881945;
q = ((q * x) >> 96) - 533845033583426703283633433725380;
q = ((q * x) >> 96) + 3604857256930695427073651918091429;
q = ((q * x) >> 96) - 14423608567350463180887372962807573;
q = ((q * x) >> 96) + 26449188498355588339934803723976023;
/// @solidity memory-safe-assembly
assembly {
// Div in assembly because solidity adds a zero check despite the unchecked.
// The q polynomial won't have zeros in the domain as all its roots are complex.
// No scaling is necessary because p is already `2**96` too large.
r := sdiv(p, q)
}
// r should be in the range `(0.09, 0.25) * 2**96`.
// We now need to multiply r by:
// - The scale factor `s ≈ 6.031367120`.
// - The `2**k` factor from the range reduction.
// - The `1e18 / 2**96` factor for base conversion.
// We do this all at once, with an intermediate result in `2**213`
// basis, so the final right shift is always by a positive amount.
r = int256(
(uint256(r) * 3822833074963236453042738258902158003155416615667) >> uint256(195 - k)
);
}
}
/// @dev Returns `ln(x)`, denominated in `WAD`.
/// Credit to Remco Bloemen under MIT license: https://2π.com/21/exp-ln
function lnWad(int256 x) internal pure returns (int256 r) {
/// @solidity memory-safe-assembly
assembly {
// We want to convert `x` from `10**18` fixed point to `2**96` fixed point.
// We do this by multiplying by `2**96 / 10**18`. But since
// `ln(x * C) = ln(x) + ln(C)`, we can simply do nothing here
// and add `ln(2**96 / 10**18)` at the end.
// Compute `k = log2(x) - 96`, `r = 159 - k = 255 - log2(x) = 255 ^ log2(x)`.
r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
// We place the check here for more optimal stack operations.
if iszero(sgt(x, 0)) {
mstore(0x00, 0x1615e638) // `LnWadUndefined()`.
revert(0x1c, 0x04)
}
// forgefmt: disable-next-item
r := xor(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),
0xf8f9f9faf9fdfafbf9fdfcfdfafbfcfef9fafdfafcfcfbfefafafcfbffffffff))
// Reduce range of x to (1, 2) * 2**96
// ln(2^k * x) = k * ln(2) + ln(x)
x := shr(159, shl(r, x))
// Evaluate using a (8, 8)-term rational approximation.
// `p` is made monic, we will multiply by a scale factor later.
// forgefmt: disable-next-item
let p := sub( // This heavily nested expression is to avoid stack-too-deep for via-ir.
sar(96, mul(add(43456485725739037958740375743393,
sar(96, mul(add(24828157081833163892658089445524,
sar(96, mul(add(3273285459638523848632254066296,
x), x))), x))), x)), 11111509109440967052023855526967)
p := sub(sar(96, mul(p, x)), 45023709667254063763336534515857)
p := sub(sar(96, mul(p, x)), 14706773417378608786704636184526)
p := sub(mul(p, x), shl(96, 795164235651350426258249787498))
// We leave `p` in `2**192` basis so we don't need to scale it back up for the division.
// `q` is monic by convention.
let q := add(5573035233440673466300451813936, x)
q := add(71694874799317883764090561454958, sar(96, mul(x, q)))
q := add(283447036172924575727196451306956, sar(96, mul(x, q)))
q := add(401686690394027663651624208769553, sar(96, mul(x, q)))
q := add(204048457590392012362485061816622, sar(96, mul(x, q)))
q := add(31853899698501571402653359427138, sar(96, mul(x, q)))
q := add(909429971244387300277376558375, sar(96, mul(x, q)))
// `p / q` is in the range `(0, 0.125) * 2**96`.
// Finalization, we need to:
// - Multiply by the scale factor `s = 5.549…`.
// - Add `ln(2**96 / 10**18)`.
// - Add `k * ln(2)`.
// - Multiply by `10**18 / 2**96 = 5**18 >> 78`.
// The q polynomial is known not to have zeros in the domain.
// No scaling required because p is already `2**96` too large.
p := sdiv(p, q)
// Multiply by the scaling factor: `s * 5**18 * 2**96`, base is now `5**18 * 2**192`.
p := mul(1677202110996718588342820967067443963516166, p)
// Add `ln(2) * k * 5**18 * 2**192`.
// forgefmt: disable-next-item
p := add(mul(16597577552685614221487285958193947469193820559219878177908093499208371, sub(159, r)), p)
// Add `ln(2**96 / 10**18) * 5**18 * 2**192`.
p := add(600920179829731861736702779321621459595472258049074101567377883020018308, p)
// Base conversion: mul `2**18 / 2**192`.
r := sar(174, p)
}
}
/// @dev Returns `W_0(x)`, denominated in `WAD`.
/// See: https://en.wikipedia.org/wiki/Lambert_W_function
/// a.k.a. Product log function. This is an approximation of the principal branch.
function lambertW0Wad(int256 x) internal pure returns (int256 w) {
// forgefmt: disable-next-item
unchecked {
if ((w = x) <= -367879441171442322) revert OutOfDomain(); // `x` less than `-1/e`.
int256 wad = int256(WAD);
int256 p = x;
uint256 c; // Whether we need to avoid catastrophic cancellation.
uint256 i = 4; // Number of iterations.
if (w <= 0x1ffffffffffff) {
if (-0x4000000000000 <= w) {
i = 1; // Inputs near zero only take one step to converge.
} else if (w <= -0x3ffffffffffffff) {
i = 32; // Inputs near `-1/e` take very long to converge.
}
} else if (w >> 63 == 0) {
/// @solidity memory-safe-assembly
assembly {
// Inline log2 for more performance, since the range is small.
let v := shr(49, w)
let l := shl(3, lt(0xff, v))
l := add(or(l, byte(and(0x1f, shr(shr(l, v), 0x8421084210842108cc6318c6db6d54be)),
0x0706060506020504060203020504030106050205030304010505030400000000)), 49)
w := sdiv(shl(l, 7), byte(sub(l, 31), 0x0303030303030303040506080c13))
c := gt(l, 60)
i := add(2, add(gt(l, 53), c))
}
} else {
int256 ll = lnWad(w = lnWad(w));
/// @solidity memory-safe-assembly
assembly {
// `w = ln(x) - ln(ln(x)) + b * ln(ln(x)) / ln(x)`.
w := add(sdiv(mul(ll, 1023715080943847266), w), sub(w, ll))
i := add(3, iszero(shr(68, x)))
c := iszero(shr(143, x))
}
if (c == 0) {
do { // If `x` is big, use Newton's so that intermediate values won't overflow.
int256 e = expWad(w);
/// @solidity memory-safe-assembly
assembly {
let t := mul(w, div(e, wad))
w := sub(w, sdiv(sub(t, x), div(add(e, t), wad)))
}
if (p <= w) break;
p = w;
} while (--i != 0);
/// @solidity memory-safe-assembly
assembly {
w := sub(w, sgt(w, 2))
}
return w;
}
}
do { // Otherwise, use Halley's for faster convergence.
int256 e = expWad(w);
/// @solidity memory-safe-assembly
assembly {
let t := add(w, wad)
let s := sub(mul(w, e), mul(x, wad))
w := sub(w, sdiv(mul(s, wad), sub(mul(e, t), sdiv(mul(add(t, wad), s), add(t, t)))))
}
if (p <= w) break;
p = w;
} while (--i != c);
/// @solidity memory-safe-assembly
assembly {
w := sub(w, sgt(w, 2))
}
// For certain ranges of `x`, we'll use the quadratic-rate recursive formula of
// R. Iacono and J.P. Boyd for the last iteration, to avoid catastrophic cancellation.
if (c != 0) {
int256 t = w | 1;
/// @solidity memory-safe-assembly
assembly {
x := sdiv(mul(x, wad), t)
}
x = (t * (wad + lnWad(x)));
/// @solidity memory-safe-assembly
assembly {
w := sdiv(x, add(wad, t))
}
}
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* GENERAL NUMBER UTILITIES */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Calculates `floor(a * b / d)` with full precision.
/// Throws if result overflows a uint256 or when `d` is zero.
/// Credit to Remco Bloemen under MIT license: https://2π.com/21/muldiv
function fullMulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 result) {
/// @solidity memory-safe-assembly
assembly {
for {} 1 {} {
// 512-bit multiply `[p1 p0] = x * y`.
// Compute the product mod `2**256` and mod `2**256 - 1`
// then use the Chinese Remainder Theorem to reconstruct
// the 512 bit result. The result is stored in two 256
// variables such that `product = p1 * 2**256 + p0`.
// Least significant 256 bits of the product.
result := mul(x, y) // Temporarily use `result` as `p0` to save gas.
let mm := mulmod(x, y, not(0))
// Most significant 256 bits of the product.
let p1 := sub(mm, add(result, lt(mm, result)))
// Handle non-overflow cases, 256 by 256 division.
if iszero(p1) {
if iszero(d) {
mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
revert(0x1c, 0x04)
}
result := div(result, d)
break
}
// Make sure the result is less than `2**256`. Also prevents `d == 0`.
if iszero(gt(d, p1)) {
mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
revert(0x1c, 0x04)
}
/*------------------- 512 by 256 division --------------------*/
// Make division exact by subtracting the remainder from `[p1 p0]`.
// Compute remainder using mulmod.
let r := mulmod(x, y, d)
// `t` is the least significant bit of `d`.
// Always greater or equal to 1.
let t := and(d, sub(0, d))
// Divide `d` by `t`, which is a power of two.
d := div(d, t)
// Invert `d mod 2**256`
// Now that `d` is an odd number, it has an inverse
// modulo `2**256` such that `d * inv = 1 mod 2**256`.
// Compute the inverse by starting with a seed that is correct
// correct for four bits. That is, `d * inv = 1 mod 2**4`.
let inv := xor(2, mul(3, d))
// Now use Newton-Raphson iteration to improve the precision.
// Thanks to Hensel's lifting lemma, this also works in modular
// arithmetic, doubling the correct bits in each step.
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**8
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**16
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**32
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**64
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**128
result :=
mul(
// Divide [p1 p0] by the factors of two.
// Shift in bits from `p1` into `p0`. For this we need
// to flip `t` such that it is `2**256 / t`.
or(
mul(sub(p1, gt(r, result)), add(div(sub(0, t), t), 1)),
div(sub(result, r), t)
),
// inverse mod 2**256
mul(inv, sub(2, mul(d, inv)))
)
break
}
}
}
/// @dev Calculates `floor(x * y / d)` with full precision, rounded up.
/// Throws if result overflows a uint256 or when `d` is zero.
/// Credit to Uniswap-v3-core under MIT license:
/// https://github.com/Uniswap/v3-core/blob/contracts/libraries/FullMath.sol
function fullMulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 result) {
result = fullMulDiv(x, y, d);
/// @solidity memory-safe-assembly
assembly {
if mulmod(x, y, d) {
result := add(result, 1)
if iszero(result) {
mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
revert(0x1c, 0x04)
}
}
}
}
/// @dev Returns `floor(x * y / d)`.
/// Reverts if `x * y` overflows, or `d` is zero.
function mulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to require(d != 0 && (y == 0 || x <= type(uint256).max / y))
if iszero(mul(d, iszero(mul(y, gt(x, div(not(0), y)))))) {
mstore(0x00, 0xad251c27) // `MulDivFailed()`.
revert(0x1c, 0x04)
}
z := div(mul(x, y), d)
}
}
/// @dev Returns `ceil(x * y / d)`.
/// Reverts if `x * y` overflows, or `d` is zero.
function mulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to require(d != 0 && (y == 0 || x <= type(uint256).max / y))
if iszero(mul(d, iszero(mul(y, gt(x, div(not(0), y)))))) {
mstore(0x00, 0xad251c27) // `MulDivFailed()`.
revert(0x1c, 0x04)
}
z := add(iszero(iszero(mod(mul(x, y), d))), div(mul(x, y), d))
}
}
/// @dev Returns `ceil(x / d)`.
/// Reverts if `d` is zero.
function divUp(uint256 x, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
if iszero(d) {
mstore(0x00, 0x65244e4e) // `DivFailed()`.
revert(0x1c, 0x04)
}
z := add(iszero(iszero(mod(x, d))), div(x, d))
}
}
/// @dev Returns `max(0, x - y)`.
function zeroFloorSub(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(gt(x, y), sub(x, y))
}
}
/// @dev Exponentiate `x` to `y` by squaring, denominated in base `b`.
/// Reverts if the computation overflows.
function rpow(uint256 x, uint256 y, uint256 b) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(b, iszero(y)) // `0 ** 0 = 1`. Otherwise, `0 ** n = 0`.
if x {
z := xor(b, mul(xor(b, x), and(y, 1))) // `z = isEven(y) ? scale : x`
let half := shr(1, b) // Divide `b` by 2.
// Divide `y` by 2 every iteration.
for { y := shr(1, y) } y { y := shr(1, y) } {
let xx := mul(x, x) // Store x squared.
let xxRound := add(xx, half) // Round to the nearest number.
// Revert if `xx + half` overflowed, or if `x ** 2` overflows.
if or(lt(xxRound, xx), shr(128, x)) {
mstore(0x00, 0x49f7642b) // `RPowOverflow()`.
revert(0x1c, 0x04)
}
x := div(xxRound, b) // Set `x` to scaled `xxRound`.
// If `y` is odd:
if and(y, 1) {
let zx := mul(z, x) // Compute `z * x`.
let zxRound := add(zx, half) // Round to the nearest number.
// If `z * x` overflowed or `zx + half` overflowed:
if or(xor(div(zx, x), z), lt(zxRound, zx)) {
// Revert if `x` is non-zero.
if iszero(iszero(x)) {
mstore(0x00, 0x49f7642b) // `RPowOverflow()`.
revert(0x1c, 0x04)
}
}
z := div(zxRound, b) // Return properly scaled `zxRound`.
}
}
}
}
}
/// @dev Returns the square root of `x`.
function sqrt(uint256 x) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// `floor(sqrt(2**15)) = 181`. `sqrt(2**15) - 181 = 2.84`.
z := 181 // The "correct" value is 1, but this saves a multiplication later.
// This segment is to get a reasonable initial estimate for the Babylonian method. With a bad
// start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.
// Let `y = x / 2**r`. We check `y >= 2**(k + 8)`
// but shift right by `k` bits to ensure that if `x >= 256`, then `y >= 256`.
let r := shl(7, lt(0xffffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffffff, shr(r, x))))
z := shl(shr(1, r), z)
// Goal was to get `z*z*y` within a small factor of `x`. More iterations could
// get y in a tighter range. Currently, we will have y in `[256, 256*(2**16))`.
// We ensured `y >= 256` so that the relative difference between `y` and `y+1` is small.
// That's not possible if `x < 256` but we can just verify those cases exhaustively.
// Now, `z*z*y <= x < z*z*(y+1)`, and `y <= 2**(16+8)`, and either `y >= 256`, or `x < 256`.
// Correctness can be checked exhaustively for `x < 256`, so we assume `y >= 256`.
// Then `z*sqrt(y)` is within `sqrt(257)/sqrt(256)` of `sqrt(x)`, or about 20bps.
// For `s` in the range `[1/256, 256]`, the estimate `f(s) = (181/1024) * (s+1)`
// is in the range `(1/2.84 * sqrt(s), 2.84 * sqrt(s))`,
// with largest error when `s = 1` and when `s = 256` or `1/256`.
// Since `y` is in `[256, 256*(2**16))`, let `a = y/65536`, so that `a` is in `[1/256, 256)`.
// Then we can estimate `sqrt(y)` using
// `sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2**18`.
// There is no overflow risk here since `y < 2**136` after the first branch above.
z := shr(18, mul(z, add(shr(r, x), 65536))) // A `mul()` is saved from starting `z` at 181.
// Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
// If `x+1` is a perfect square, the Babylonian method cycles between
// `floor(sqrt(x))` and `ceil(sqrt(x))`. This statement ensures we return floor.
// See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division
z := sub(z, lt(div(x, z), z))
}
}
/// @dev Returns the cube root of `x`.
/// Credit to bout3fiddy and pcaversaccio under AGPLv3 license:
/// https://github.com/pcaversaccio/snekmate/blob/main/src/utils/Math.vy
function cbrt(uint256 x) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
let r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
z := div(shl(div(r, 3), shl(lt(0xf, shr(r, x)), 0xf)), xor(7, mod(r, 3)))
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := sub(z, lt(div(x, mul(z, z)), z))
}
}
/// @dev Returns the square root of `x`, denominated in `WAD`.
function sqrtWad(uint256 x) internal pure returns (uint256 z) {
unchecked {
z = 10 ** 9;
if (x <= type(uint256).max / 10 ** 36 - 1) {
x *= 10 ** 18;
z = 1;
}
z *= sqrt(x);
}
}
/// @dev Returns the cube root of `x`, denominated in `WAD`.
function cbrtWad(uint256 x) internal pure returns (uint256 z) {
unchecked {
z = 10 ** 12;
if (x <= (type(uint256).max / 10 ** 36) * 10 ** 18 - 1) {
if (x >= type(uint256).max / 10 ** 36) {
x *= 10 ** 18;
z = 10 ** 6;
} else {
x *= 10 ** 36;
z = 1;
}
}
z *= cbrt(x);
}
}
/// @dev Returns the factorial of `x`.
function factorial(uint256 x) internal pure returns (uint256 result) {
/// @solidity memory-safe-assembly
assembly {
if iszero(lt(x, 58)) {
mstore(0x00, 0xaba0f2a2) // `FactorialOverflow()`.
revert(0x1c, 0x04)
}
for { result := 1 } x { x := sub(x, 1) } { result := mul(result, x) }
}
}
/// @dev Returns the log2 of `x`.
/// Equivalent to computing the index of the most significant bit (MSB) of `x`.
/// Returns 0 if `x` is zero.
function log2(uint256 x) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
// forgefmt: disable-next-item
r := or(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),
0x0706060506020504060203020504030106050205030304010505030400000000))
}
}
/// @dev Returns the log2 of `x`, rounded up.
/// Returns 0 if `x` is zero.
function log2Up(uint256 x) internal pure returns (uint256 r) {
r = log2(x);
/// @solidity memory-safe-assembly
assembly {
r := add(r, lt(shl(r, 1), x))
}
}
/// @dev Returns the log10 of `x`.
/// Returns 0 if `x` is zero.
function log10(uint256 x) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
if iszero(lt(x, 100000000000000000000000000000000000000)) {
x := div(x, 100000000000000000000000000000000000000)
r := 38
}
if iszero(lt(x, 100000000000000000000)) {
x := div(x, 100000000000000000000)
r := add(r, 20)
}
if iszero(lt(x, 10000000000)) {
x := div(x, 10000000000)
r := add(r, 10)
}
if iszero(lt(x, 100000)) {
x := div(x, 100000)
r := add(r, 5)
}
r := add(r, add(gt(x, 9), add(gt(x, 99), add(gt(x, 999), gt(x, 9999)))))
}
}
/// @dev Returns the log10 of `x`, rounded up.
/// Returns 0 if `x` is zero.
function log10Up(uint256 x) internal pure returns (uint256 r) {
r = log10(x);
/// @solidity memory-safe-assembly
assembly {
r := add(r, lt(exp(10, r), x))
}
}
/// @dev Returns the log256 of `x`.
/// Returns 0 if `x` is zero.
function log256(uint256 x) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(shr(3, r), lt(0xff, shr(r, x)))
}
}
/// @dev Returns the log256 of `x`, rounded up.
/// Returns 0 if `x` is zero.
function log256Up(uint256 x) internal pure returns (uint256 r) {
r = log256(x);
/// @solidity memory-safe-assembly
assembly {
r := add(r, lt(shl(shl(3, r), 1), x))
}
}
/// @dev Returns the scientific notation format `mantissa * 10 ** exponent` of `x`.
/// Useful for compressing prices (e.g. using 25 bit mantissa and 7 bit exponent).
function sci(uint256 x) internal pure returns (uint256 mantissa, uint256 exponent) {
/// @solidity memory-safe-assembly
assembly {
mantissa := x
if mantissa {
if iszero(mod(mantissa, 1000000000000000000000000000000000)) {
mantissa := div(mantissa, 1000000000000000000000000000000000)
exponent := 33
}
if iszero(mod(mantissa, 10000000000000000000)) {
mantissa := div(mantissa, 10000000000000000000)
exponent := add(exponent, 19)
}
if iszero(mod(mantissa, 1000000000000)) {
mantissa := div(mantissa, 1000000000000)
exponent := add(exponent, 12)
}
if iszero(mod(mantissa, 1000000)) {
mantissa := div(mantissa, 1000000)
exponent := add(exponent, 6)
}
if iszero(mod(mantissa, 10000)) {
mantissa := div(mantissa, 10000)
exponent := add(exponent, 4)
}
if iszero(mod(mantissa, 100)) {
mantissa := div(mantissa, 100)
exponent := add(exponent, 2)
}
if iszero(mod(mantissa, 10)) {
mantissa := div(mantissa, 10)
exponent := add(exponent, 1)
}
}
}
}
/// @dev Convenience function for packing `x` into a smaller number using `sci`.
/// The `mantissa` will be in bits [7..255] (the upper 249 bits).
/// The `exponent` will be in bits [0..6] (the lower 7 bits).
/// Use `SafeCastLib` to safely ensure that the `packed` number is small
/// enough to fit in the desired unsigned integer type:
/// ```
/// uint32 packed = SafeCastLib.toUint32(FixedPointMathLib.packSci(777 ether));
/// ```
function packSci(uint256 x) internal pure returns (uint256 packed) {
(x, packed) = sci(x); // Reuse for `mantissa` and `exponent`.
/// @solidity memory-safe-assembly
assembly {
if shr(249, x) {
mstore(0x00, 0xce30380c) // `MantissaOverflow()`.
revert(0x1c, 0x04)
}
packed := or(shl(7, x), packed)
}
}
/// @dev Convenience function for unpacking a packed number from `packSci`.
function unpackSci(uint256 packed) internal pure returns (uint256 unpacked) {
unchecked {
unpacked = (packed >> 7) * 10 ** (packed & 0x7f);
}
}
/// @dev Returns the average of `x` and `y`.
function avg(uint256 x, uint256 y) internal pure returns (uint256 z) {
unchecked {
z = (x & y) + ((x ^ y) >> 1);
}
}
/// @dev Returns the average of `x` and `y`.
function avg(int256 x, int256 y) internal pure returns (int256 z) {
unchecked {
z = (x >> 1) + (y >> 1) + (((x & 1) + (y & 1)) >> 1);
}
}
/// @dev Returns the absolute value of `x`.
function abs(int256 x) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(sub(0, shr(255, x)), add(sub(0, shr(255, x)), x))
}
}
/// @dev Returns the absolute distance between `x` and `y`.
function dist(int256 x, int256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(mul(xor(sub(y, x), sub(x, y)), sgt(x, y)), sub(y, x))
}
}
/// @dev Returns the minimum of `x` and `y`.
function min(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, y), lt(y, x)))
}
}
/// @dev Returns the minimum of `x` and `y`.
function min(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, y), slt(y, x)))
}
}
/// @dev Returns the maximum of `x` and `y`.
function max(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, y), gt(y, x)))
}
}
/// @dev Returns the maximum of `x` and `y`.
function max(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, y), sgt(y, x)))
}
}
/// @dev Returns `x`, bounded to `minValue` and `maxValue`.
function clamp(uint256 x, uint256 minValue, uint256 maxValue)
internal
pure
returns (uint256 z)
{
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, minValue), gt(minValue, x)))
z := xor(z, mul(xor(z, maxValue), lt(maxValue, z)))
}
}
/// @dev Returns `x`, bounded to `minValue` and `maxValue`.
function clamp(int256 x, int256 minValue, int256 maxValue) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, minValue), sgt(minValue, x)))
z := xor(z, mul(xor(z, maxValue), slt(maxValue, z)))
}
}
/// @dev Returns greatest common divisor of `x` and `y`.
function gcd(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
for { z := x } y {} {
let t := y
y := mod(z, y)
z := t
}
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* RAW NUMBER OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns `x + y`, without checking for overflow.
function rawAdd(uint256 x, uint256 y) internal pure returns (uint256 z) {
unchecked {
z = x + y;
}
}
/// @dev Returns `x + y`, without checking for overflow.
function rawAdd(int256 x, int256 y) internal pure returns (int256 z) {
unchecked {
z = x + y;
}
}
/// @dev Returns `x - y`, without checking for underflow.
function rawSub(uint256 x, uint256 y) internal pure returns (uint256 z) {
unchecked {
z = x - y;
}
}
/// @dev Returns `x - y`, without checking for underflow.
function rawSub(int256 x, int256 y) internal pure returns (int256 z) {
unchecked {
z = x - y;
}
}
/// @dev Returns `x * y`, without checking for overflow.
function rawMul(uint256 x, uint256 y) internal pure returns (uint256 z) {
unchecked {
z = x * y;
}
}
/// @dev Returns `x * y`, without checking for overflow.
function rawMul(int256 x, int256 y) internal pure returns (int256 z) {
unchecked {
z = x * y;
}
}
/// @dev Returns `x / y`, returning 0 if `y` is zero.
function rawDiv(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := div(x, y)
}
}
/// @dev Returns `x / y`, returning 0 if `y` is zero.
function rawSDiv(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := sdiv(x, y)
}
}
/// @dev Returns `x % y`, returning 0 if `y` is zero.
function rawMod(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mod(x, y)
}
}
/// @dev Returns `x % y`, returning 0 if `y` is zero.
function rawSMod(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := smod(x, y)
}
}
/// @dev Returns `(x + y) % d`, return 0 if `d` if zero.
function rawAddMod(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := addmod(x, y, d)
}
}
/// @dev Returns `(x * y) % d`, return 0 if `d` if zero.
function rawMulMod(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mulmod(x, y, d)
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeTransferLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
///
/// @dev Note:
/// - For ETH transfers, please use `forceSafeTransferETH` for DoS protection.
/// - For ERC20s, this implementation won't check that a token has code,
/// responsibility is delegated to the caller.
library SafeTransferLib {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The ETH transfer has failed.
error ETHTransferFailed();
/// @dev The ERC20 `transferFrom` has failed.
error TransferFromFailed();
/// @dev The ERC20 `transfer` has failed.
error TransferFailed();
/// @dev The ERC20 `approve` has failed.
error ApproveFailed();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Suggested gas stipend for contract receiving ETH that disallows any storage writes.
uint256 internal constant GAS_STIPEND_NO_STORAGE_WRITES = 2300;
/// @dev Suggested gas stipend for contract receiving ETH to perform a few
/// storage reads and writes, but low enough to prevent griefing.
uint256 internal constant GAS_STIPEND_NO_GRIEF = 100000;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ETH OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
// If the ETH transfer MUST succeed with a reasonable gas budget, use the force variants.
//
// The regular variants:
// - Forwards all remaining gas to the target.
// - Reverts if the target reverts.
// - Reverts if the current contract has insufficient balance.
//
// The force variants:
// - Forwards with an optional gas stipend
// (defaults to `GAS_STIPEND_NO_GRIEF`, which is sufficient for most cases).
// - If the target reverts, or if the gas stipend is exhausted,
// creates a temporary contract to force send the ETH via `SELFDESTRUCT`.
// Future compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758.
// - Reverts if the current contract has insufficient balance.
//
// The try variants:
// - Forwards with a mandatory gas stipend.
// - Instead of reverting, returns whether the transfer succeeded.
/// @dev Sends `amount` (in wei) ETH to `to`.
function safeTransferETH(address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
if iszero(call(gas(), to, amount, codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
revert(0x1c, 0x04)
}
}
}
/// @dev Sends all the ETH in the current contract to `to`.
function safeTransferAllETH(address to) internal {
/// @solidity memory-safe-assembly
assembly {
// Transfer all the ETH and check if it succeeded or not.
if iszero(call(gas(), to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
revert(0x1c, 0x04)
}
}
}
/// @dev Force sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
function forceSafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal {
/// @solidity memory-safe-assembly
assembly {
if lt(selfbalance(), amount) {
mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
revert(0x1c, 0x04)
}
if iszero(call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, to) // Store the address in scratch space.
mstore8(0x0b, 0x73) // Opcode `PUSH20`.
mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
}
}
}
/// @dev Force sends all the ETH in the current contract to `to`, with a `gasStipend`.
function forceSafeTransferAllETH(address to, uint256 gasStipend) internal {
/// @solidity memory-safe-assembly
assembly {
if iszero(call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, to) // Store the address in scratch space.
mstore8(0x0b, 0x73) // Opcode `PUSH20`.
mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
}
}
}
/// @dev Force sends `amount` (in wei) ETH to `to`, with `GAS_STIPEND_NO_GRIEF`.
function forceSafeTransferETH(address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
if lt(selfbalance(), amount) {
mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
revert(0x1c, 0x04)
}
if iszero(call(GAS_STIPEND_NO_GRIEF, to, amount, codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, to) // Store the address in scratch space.
mstore8(0x0b, 0x73) // Opcode `PUSH20`.
mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
}
}
}
/// @dev Force sends all the ETH in the current contract to `to`, with `GAS_STIPEND_NO_GRIEF`.
function forceSafeTransferAllETH(address to) internal {
/// @solidity memory-safe-assembly
assembly {
// forgefmt: disable-next-item
if iszero(call(GAS_STIPEND_NO_GRIEF, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, to) // Store the address in scratch space.
mstore8(0x0b, 0x73) // Opcode `PUSH20`.
mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
}
}
}
/// @dev Sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
function trySafeTransferETH(address to, uint256 amount, uint256 gasStipend)
internal
returns (bool success)
{
/// @solidity memory-safe-assembly
assembly {
success := call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)
}
}
/// @dev Sends all the ETH in the current contract to `to`, with a `gasStipend`.
function trySafeTransferAllETH(address to, uint256 gasStipend)
internal
returns (bool success)
{
/// @solidity memory-safe-assembly
assembly {
success := call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ERC20 OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Sends `amount` of ERC20 `token` from `from` to `to`.
/// Reverts upon failure.
///
/// The `from` account must have at least `amount` approved for
/// the current contract to manage.
function safeTransferFrom(address token, address from, address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x60, amount) // Store the `amount` argument.
mstore(0x40, to) // Store the `to` argument.
mstore(0x2c, shl(96, from)) // Store the `from` argument.
mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`.
// Perform the transfer, reverting upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
)
) {
mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
revert(0x1c, 0x04)
}
mstore(0x60, 0) // Restore the zero slot to zero.
mstore(0x40, m) // Restore the free memory pointer.
}
}
/// @dev Sends all of ERC20 `token` from `from` to `to`.
/// Reverts upon failure.
///
/// The `from` account must have their entire balance approved for
/// the current contract to manage.
function safeTransferAllFrom(address token, address from, address to)
internal
returns (uint256 amount)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x40, to) // Store the `to` argument.
mstore(0x2c, shl(96, from)) // Store the `from` argument.
mstore(0x0c, 0x70a08231000000000000000000000000) // `balanceOf(address)`.
// Read the balance, reverting upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
gt(returndatasize(), 0x1f), // At least 32 bytes returned.
staticcall(gas(), token, 0x1c, 0x24, 0x60, 0x20)
)
) {
mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
revert(0x1c, 0x04)
}
mstore(0x00, 0x23b872dd) // `transferFrom(address,address,uint256)`.
amount := mload(0x60) // The `amount` is already at 0x60. We'll need to return it.
// Perform the transfer, reverting upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
)
) {
mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
revert(0x1c, 0x04)
}
mstore(0x60, 0) // Restore the zero slot to zero.
mstore(0x40, m) // Restore the free memory pointer.
}
}
/// @dev Sends `amount` of ERC20 `token` from the current contract to `to`.
/// Reverts upon failure.
function safeTransfer(address token, address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x14, to) // Store the `to` argument.
mstore(0x34, amount) // Store the `amount` argument.
mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.
// Perform the transfer, reverting upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
)
) {
mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
revert(0x1c, 0x04)
}
mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
}
}
/// @dev Sends all of ERC20 `token` from the current contract to `to`.
/// Reverts upon failure.
function safeTransferAll(address token, address to) internal returns (uint256 amount) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`.
mstore(0x20, address()) // Store the address of the current contract.
// Read the balance, reverting upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
gt(returndatasize(), 0x1f), // At least 32 bytes returned.
staticcall(gas(), token, 0x1c, 0x24, 0x34, 0x20)
)
) {
mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
revert(0x1c, 0x04)
}
mstore(0x14, to) // Store the `to` argument.
amount := mload(0x34) // The `amount` is already at 0x34. We'll need to return it.
mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.
// Perform the transfer, reverting upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
)
) {
mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
revert(0x1c, 0x04)
}
mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
}
}
/// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
/// Reverts upon failure.
function safeApprove(address token, address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x14, to) // Store the `to` argument.
mstore(0x34, amount) // Store the `amount` argument.
mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
// Perform the approval, reverting upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
)
) {
mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.
revert(0x1c, 0x04)
}
mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
}
}
/// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
/// If the initial attempt to approve fails, attempts to reset the approved amount to zero,
/// then retries the approval again (some tokens, e.g. USDT, requires this).
/// Reverts upon failure.
function safeApproveWithRetry(address token, address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x14, to) // Store the `to` argument.
mstore(0x34, amount) // Store the `amount` argument.
mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
// Perform the approval, retrying upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
)
) {
mstore(0x34, 0) // Store 0 for the `amount`.
mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
pop(call(gas(), token, 0, 0x10, 0x44, codesize(), 0x00)) // Reset the approval.
mstore(0x34, amount) // Store back the original `amount`.
// Retry the approval, reverting upon failure.
if iszero(
and(
or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
)
) {
mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.
revert(0x1c, 0x04)
}
}
mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
}
}
/// @dev Returns the amount of ERC20 `token` owned by `account`.
/// Returns zero if the `token` does not exist.
function balanceOf(address token, address account) internal view returns (uint256 amount) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x14, account) // Store the `account` argument.
mstore(0x00, 0x70a08231000000000000000000000000) // `balanceOf(address)`.
amount :=
mul(
mload(0x20),
and( // The arguments of `and` are evaluated from right to left.
gt(returndatasize(), 0x1f), // At least 32 bytes returned.
staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20)
)
)
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {AggregatorV3Interface} from "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
import {FixedPointMathLib} from "solady/src/utils/FixedPointMathLib.sol";
/// @author philogy <https://github.com/philogy>
library CvxEthOracleLib {
using FixedPointMathLib for uint256;
AggregatorV3Interface internal constant CVX_ETH_ORACLE =
AggregatorV3Interface(0xC9CbF687f43176B302F03f5e58470b77D07c61c6);
error InvalidOracleData();
error OracleDataStale();
/// @dev Heartbeat of CVX-ETH oracle is 24h according to [Chainlink](https://data.chain.link/ethereum/mainnet/crypto-eth/cvx-eth)
uint256 internal constant ORACLE_STALENESS_WINDOW = 25 hours;
/// @dev For reference purposes, assumed to remain constant
uint256 internal constant ORACLE_DECIMALs = 18;
/**
* @notice Returns the ETH/CVX price
* @return ETH/CVX Price denominated in {ORACLE_DECIMALs} decimals.
*/
function ethCvxPrice() internal view returns (uint256) {
(uint80 roundId, int256 answer, /* startedAt */, uint256 updatedAt, /* answeredInRound */ ) =
CVX_ETH_ORACLE.latestRoundData();
if (roundId == 0 || answer < 0) revert InvalidOracleData();
if (block.timestamp - updatedAt > ORACLE_STALENESS_WINDOW) revert OracleDataStale();
return uint256(answer);
}
function convertToCvx(uint256 ethAmount) internal view returns (uint256) {
return ethAmount.divWad(ethCvxPrice());
}
function convertToEth(uint256 cvxAmount) internal view returns (uint256) {
// Can use Solady because oracle decimals are 18 (WAD).
return cvxAmount.mulWad(ethCvxPrice());
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Safe integer casting library that reverts on overflow.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeCastLib.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/SafeCast.sol)
library SafeCastLib {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
error Overflow();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* UNSIGNED INTEGER SAFE CASTING OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
function toUint8(uint256 x) internal pure returns (uint8) {
if (x >= 1 << 8) _revertOverflow();
return uint8(x);
}
function toUint16(uint256 x) internal pure returns (uint16) {
if (x >= 1 << 16) _revertOverflow();
return uint16(x);
}
function toUint24(uint256 x) internal pure returns (uint24) {
if (x >= 1 << 24) _revertOverflow();
return uint24(x);
}
function toUint32(uint256 x) internal pure returns (uint32) {
if (x >= 1 << 32) _revertOverflow();
return uint32(x);
}
function toUint40(uint256 x) internal pure returns (uint40) {
if (x >= 1 << 40) _revertOverflow();
return uint40(x);
}
function toUint48(uint256 x) internal pure returns (uint48) {
if (x >= 1 << 48) _revertOverflow();
return uint48(x);
}
function toUint56(uint256 x) internal pure returns (uint56) {
if (x >= 1 << 56) _revertOverflow();
return uint56(x);
}
function toUint64(uint256 x) internal pure returns (uint64) {
if (x >= 1 << 64) _revertOverflow();
return uint64(x);
}
function toUint72(uint256 x) internal pure returns (uint72) {
if (x >= 1 << 72) _revertOverflow();
return uint72(x);
}
function toUint80(uint256 x) internal pure returns (uint80) {
if (x >= 1 << 80) _revertOverflow();
return uint80(x);
}
function toUint88(uint256 x) internal pure returns (uint88) {
if (x >= 1 << 88) _revertOverflow();
return uint88(x);
}
function toUint96(uint256 x) internal pure returns (uint96) {
if (x >= 1 << 96) _revertOverflow();
return uint96(x);
}
function toUint104(uint256 x) internal pure returns (uint104) {
if (x >= 1 << 104) _revertOverflow();
return uint104(x);
}
function toUint112(uint256 x) internal pure returns (uint112) {
if (x >= 1 << 112) _revertOverflow();
return uint112(x);
}
function toUint120(uint256 x) internal pure returns (uint120) {
if (x >= 1 << 120) _revertOverflow();
return uint120(x);
}
function toUint128(uint256 x) internal pure returns (uint128) {
if (x >= 1 << 128) _revertOverflow();
return uint128(x);
}
function toUint136(uint256 x) internal pure returns (uint136) {
if (x >= 1 << 136) _revertOverflow();
return uint136(x);
}
function toUint144(uint256 x) internal pure returns (uint144) {
if (x >= 1 << 144) _revertOverflow();
return uint144(x);
}
function toUint152(uint256 x) internal pure returns (uint152) {
if (x >= 1 << 152) _revertOverflow();
return uint152(x);
}
function toUint160(uint256 x) internal pure returns (uint160) {
if (x >= 1 << 160) _revertOverflow();
return uint160(x);
}
function toUint168(uint256 x) internal pure returns (uint168) {
if (x >= 1 << 168) _revertOverflow();
return uint168(x);
}
function toUint176(uint256 x) internal pure returns (uint176) {
if (x >= 1 << 176) _revertOverflow();
return uint176(x);
}
function toUint184(uint256 x) internal pure returns (uint184) {
if (x >= 1 << 184) _revertOverflow();
return uint184(x);
}
function toUint192(uint256 x) internal pure returns (uint192) {
if (x >= 1 << 192) _revertOverflow();
return uint192(x);
}
function toUint200(uint256 x) internal pure returns (uint200) {
if (x >= 1 << 200) _revertOverflow();
return uint200(x);
}
function toUint208(uint256 x) internal pure returns (uint208) {
if (x >= 1 << 208) _revertOverflow();
return uint208(x);
}
function toUint216(uint256 x) internal pure returns (uint216) {
if (x >= 1 << 216) _revertOverflow();
return uint216(x);
}
function toUint224(uint256 x) internal pure returns (uint224) {
if (x >= 1 << 224) _revertOverflow();
return uint224(x);
}
function toUint232(uint256 x) internal pure returns (uint232) {
if (x >= 1 << 232) _revertOverflow();
return uint232(x);
}
function toUint240(uint256 x) internal pure returns (uint240) {
if (x >= 1 << 240) _revertOverflow();
return uint240(x);
}
function toUint248(uint256 x) internal pure returns (uint248) {
if (x >= 1 << 248) _revertOverflow();
return uint248(x);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* SIGNED INTEGER SAFE CASTING OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
function toInt8(int256 x) internal pure returns (int8) {
int8 y = int8(x);
if (x != y) _revertOverflow();
return y;
}
function toInt16(int256 x) internal pure returns (int16) {
int16 y = int16(x);
if (x != y) _revertOverflow();
return y;
}
function toInt24(int256 x) internal pure returns (int24) {
int24 y = int24(x);
if (x != y) _revertOverflow();
return y;
}
function toInt32(int256 x) internal pure returns (int32) {
int32 y = int32(x);
if (x != y) _revertOverflow();
return y;
}
function toInt40(int256 x) internal pure returns (int40) {
int40 y = int40(x);
if (x != y) _revertOverflow();
return y;
}
function toInt48(int256 x) internal pure returns (int48) {
int48 y = int48(x);
if (x != y) _revertOverflow();
return y;
}
function toInt56(int256 x) internal pure returns (int56) {
int56 y = int56(x);
if (x != y) _revertOverflow();
return y;
}
function toInt64(int256 x) internal pure returns (int64) {
int64 y = int64(x);
if (x != y) _revertOverflow();
return y;
}
function toInt72(int256 x) internal pure returns (int72) {
int72 y = int72(x);
if (x != y) _revertOverflow();
return y;
}
function toInt80(int256 x) internal pure returns (int80) {
int80 y = int80(x);
if (x != y) _revertOverflow();
return y;
}
function toInt88(int256 x) internal pure returns (int88) {
int88 y = int88(x);
if (x != y) _revertOverflow();
return y;
}
function toInt96(int256 x) internal pure returns (int96) {
int96 y = int96(x);
if (x != y) _revertOverflow();
return y;
}
function toInt104(int256 x) internal pure returns (int104) {
int104 y = int104(x);
if (x != y) _revertOverflow();
return y;
}
function toInt112(int256 x) internal pure returns (int112) {
int112 y = int112(x);
if (x != y) _revertOverflow();
return y;
}
function toInt120(int256 x) internal pure returns (int120) {
int120 y = int120(x);
if (x != y) _revertOverflow();
return y;
}
function toInt128(int256 x) internal pure returns (int128) {
int128 y = int128(x);
if (x != y) _revertOverflow();
return y;
}
function toInt136(int256 x) internal pure returns (int136) {
int136 y = int136(x);
if (x != y) _revertOverflow();
return y;
}
function toInt144(int256 x) internal pure returns (int144) {
int144 y = int144(x);
if (x != y) _revertOverflow();
return y;
}
function toInt152(int256 x) internal pure returns (int152) {
int152 y = int152(x);
if (x != y) _revertOverflow();
return y;
}
function toInt160(int256 x) internal pure returns (int160) {
int160 y = int160(x);
if (x != y) _revertOverflow();
return y;
}
function toInt168(int256 x) internal pure returns (int168) {
int168 y = int168(x);
if (x != y) _revertOverflow();
return y;
}
function toInt176(int256 x) internal pure returns (int176) {
int176 y = int176(x);
if (x != y) _revertOverflow();
return y;
}
function toInt184(int256 x) internal pure returns (int184) {
int184 y = int184(x);
if (x != y) _revertOverflow();
return y;
}
function toInt192(int256 x) internal pure returns (int192) {
int192 y = int192(x);
if (x != y) _revertOverflow();
return y;
}
function toInt200(int256 x) internal pure returns (int200) {
int200 y = int200(x);
if (x != y) _revertOverflow();
return y;
}
function toInt208(int256 x) internal pure returns (int208) {
int208 y = int208(x);
if (x != y) _revertOverflow();
return y;
}
function toInt216(int256 x) internal pure returns (int216) {
int216 y = int216(x);
if (x != y) _revertOverflow();
return y;
}
function toInt224(int256 x) internal pure returns (int224) {
int224 y = int224(x);
if (x != y) _revertOverflow();
return y;
}
function toInt232(int256 x) internal pure returns (int232) {
int232 y = int232(x);
if (x != y) _revertOverflow();
return y;
}
function toInt240(int256 x) internal pure returns (int240) {
int240 y = int240(x);
if (x != y) _revertOverflow();
return y;
}
function toInt248(int256 x) internal pure returns (int248) {
int248 y = int248(x);
if (x != y) _revertOverflow();
return y;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* OTHER SAFE CASTING OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
function toInt256(uint256 x) internal pure returns (int256) {
if (x >= 1 << 255) _revertOverflow();
return int256(x);
}
function toUint256(int256 x) internal pure returns (uint256) {
if (x < 0) _revertOverflow();
return uint256(x);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* PRIVATE HELPERS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
function _revertOverflow() private pure {
/// @solidity memory-safe-assembly
assembly {
// Store the function selector of `Overflow()`.
mstore(0x00, 0x35278d12)
// Revert with (offset, size).
revert(0x1c, 0x04)
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
library HashLib {
function hash(string memory str) internal pure returns (bytes32 strHash) {
/// @solidity memory-safe-assembly
assembly {
strHash := keccak256(add(str, 0x20), mload(str))
}
}
}// 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
pragma solidity ^0.8.0;
ILockedCvx constant LOCKED_CVX = ILockedCvx(0x72a19342e8F1838460eBFCCEf09F6585e32db86E);
interface ILockedCvx {
struct LockedBalance {
uint112 amount;
uint112 boosted;
uint32 unlockTime;
}
function lock(address _account, uint256 _amount, uint256 _spendRatio) external;
function processExpiredLocks(bool relock) external;
function getReward(address _account, bool _stake) external;
function findEpochId(uint256 _time) external view returns (uint256);
function balanceAtEpochOf(uint256 _epoch, address _user) external view returns (uint256 amount);
function totalSupplyAtEpoch(uint256 _epoch) external view returns (uint256 supply);
function epochCount() external view returns (uint256);
function epochs(uint256 _id) external view returns (uint224, uint32);
function checkpointEpoch() external;
function balanceOf(address _account) external view returns (uint256);
function lockedBalanceOf(address _user) external view returns (uint256 amount);
function pendingLockOf(address _user) external view returns (uint256 amount);
function pendingLockAtEpochOf(uint256 _epoch, address _user) external view returns (uint256 amount);
function totalSupply() external view returns (uint256 supply);
function lockDuration() external view returns (uint256);
function lockedBalances(address _user)
external
view
returns (uint256 total, uint256 unlockable, uint256 locked, LockedBalance[] memory lockData);
function addReward(address _rewardsToken, address _distributor, bool _useBoost) external;
function approveRewardDistributor(address _rewardsToken, address _distributor, bool _approved) external;
function setStakeLimits(uint256 _minimum, uint256 _maximum) external;
function setBoost(uint256 _max, uint256 _rate, address _receivingAddress) external;
function setKickIncentive(uint256 _rate, uint256 _delay) external;
function shutdown() external;
function recoverERC20(address _tokenAddress, uint256 _tokenAmount) external;
function rewardsDuration() external view returns (uint256);
function isShutdown() external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IVotiumStrategy {
event FailedToSell(uint256 failedSwapIndex);
event RewarderSet(address indexed newRewarder);
event EmergencyShutdown();
error ExchangeOutputBelowMin();
error StaleAction();
error WithdrawalStillLocked();
error UnexpectedLockedCvxError();
error UnauthorizedTarget();
error NonRewardCvxSpent();
error Shutdown();
function emergencyShutdown() external;
function deposit() external payable returns (uint256 mintedCvx);
function requestWithdraw(uint256 share, address to)
external
returns (bool locked, uint256 ethOutNow, uint256 cumulativeUnlockThreshold);
function deposit(uint256 cvxMinOut) external payable returns (uint256 cvxAmount);
function totalEthValue() external view returns (uint256 totalValue, uint256 ethCvxPrice);
function getObligations()
external
view
returns (uint256 cumCvxUnlocked, uint256 cumCvxUnlockObligations, uint256 totalUnlockObligations);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
IVotiumMerkleStash constant VOTIUM_MERKLE_STASH = IVotiumMerkleStash(0x378Ba9B73309bE80BF4C2c027aAD799766a7ED5A);
interface IVotiumMerkleStash {
struct ClaimParam {
address token;
uint256 index;
uint256 amount;
bytes32[] merkleProof;
}
function claimMulti(address account, ClaimParam[] calldata claims) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface ISnapshotDelegationRegistry {
function setDelegate(bytes32 id, address delegate) external;
function clearDelegate(bytes32 id) external;
function delegation(bytes32 id, address owner) external returns (address);
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
ICvxEthPool constant CVX_ETH_POOL = ICvxEthPool(payable(0xB576491F1E6e5E62f1d8F26062Ee822B40B0E0d4));
uint256 constant ETH_COIN_INDEX = 0;
uint256 constant CVX_COIN_INDEX = 1;
interface ICvxEthPool {
event AddLiquidity(address indexed provider, uint256[2] token_amounts, uint256 fee, uint256 token_supply);
event ClaimAdminFee(address indexed admin, uint256 tokens);
event CommitNewAdmin(uint256 indexed deadline, address indexed admin);
event CommitNewParameters(
uint256 indexed deadline,
uint256 admin_fee,
uint256 mid_fee,
uint256 out_fee,
uint256 fee_gamma,
uint256 allowed_extra_profit,
uint256 adjustment_step,
uint256 ma_half_time
);
event NewAdmin(address indexed admin);
event NewParameters(
uint256 admin_fee,
uint256 mid_fee,
uint256 out_fee,
uint256 fee_gamma,
uint256 allowed_extra_profit,
uint256 adjustment_step,
uint256 ma_half_time
);
event RampAgamma(
uint256 initial_A,
uint256 future_A,
uint256 initial_gamma,
uint256 future_gamma,
uint256 initial_time,
uint256 future_time
);
event RemoveLiquidity(address indexed provider, uint256[2] token_amounts, uint256 token_supply);
event RemoveLiquidityOne(address indexed provider, uint256 token_amount, uint256 coin_index, uint256 coin_amount);
event StopRampA(uint256 current_A, uint256 current_gamma, uint256 time);
event TokenExchange(
address indexed buyer, uint256 sold_id, uint256 tokens_sold, uint256 bought_id, uint256 tokens_bought
);
fallback() external payable;
receive() external payable;
function A() external view returns (uint256);
function D() external view returns (uint256);
function add_liquidity(uint256[2] memory amounts, uint256 min_mint_amount) external payable returns (uint256);
function add_liquidity(uint256[2] memory amounts, uint256 min_mint_amount, bool use_eth)
external
payable
returns (uint256);
function adjustment_step() external view returns (uint256);
function admin_actions_deadline() external view returns (uint256);
function admin_fee() external view returns (uint256);
function admin_fee_receiver() external view returns (address);
function allowed_extra_profit() external view returns (uint256);
function apply_new_parameters() external;
function apply_transfer_ownership() external;
function balances(uint256 arg0) external view returns (uint256);
function calc_token_amount(uint256[2] memory amounts) external view returns (uint256);
function calc_withdraw_one_coin(uint256 token_amount, uint256 i) external view returns (uint256);
function claim_admin_fees() external;
function coins(uint256 i) external view returns (address);
function commit_new_parameters(
uint256 _new_mid_fee,
uint256 _new_out_fee,
uint256 _new_admin_fee,
uint256 _new_fee_gamma,
uint256 _new_allowed_extra_profit,
uint256 _new_adjustment_step,
uint256 _new_ma_half_time
) external;
function commit_transfer_ownership(address _owner) external;
function exchange(uint256 i, uint256 j, uint256 dx, uint256 min_dy) external payable returns (uint256);
function exchange(uint256 i, uint256 j, uint256 dx, uint256 min_dy, bool use_eth)
external
payable
returns (uint256);
function exchange_underlying(uint256 i, uint256 j, uint256 dx, uint256 min_dy) external payable returns (uint256);
function fee() external view returns (uint256);
function fee_gamma() external view returns (uint256);
function future_A_gamma() external view returns (uint256);
function future_A_gamma_time() external view returns (uint256);
function future_adjustment_step() external view returns (uint256);
function future_admin_fee() external view returns (uint256);
function future_allowed_extra_profit() external view returns (uint256);
function future_fee_gamma() external view returns (uint256);
function future_ma_half_time() external view returns (uint256);
function future_mid_fee() external view returns (uint256);
function future_out_fee() external view returns (uint256);
function future_owner() external view returns (address);
function gamma() external view returns (uint256);
function get_dy(uint256 i, uint256 j, uint256 dx) external view returns (uint256);
function get_virtual_price() external view returns (uint256);
function initial_A_gamma() external view returns (uint256);
function initial_A_gamma_time() external view returns (uint256);
function is_killed() external view returns (bool);
function kill_deadline() external view returns (uint256);
function kill_me() external;
function last_prices() external view returns (uint256);
function last_prices_timestamp() external view returns (uint256);
function lp_price() external view returns (uint256);
function ma_half_time() external view returns (uint256);
function mid_fee() external view returns (uint256);
function out_fee() external view returns (uint256);
function owner() external view returns (address);
function price_oracle() external view returns (uint256);
function price_scale() external view returns (uint256);
function ramp_A_gamma(uint256 future_A, uint256 future_gamma, uint256 future_time) external;
function remove_liquidity(uint256 _amount, uint256[2] memory min_amounts) external;
function remove_liquidity(uint256 _amount, uint256[2] memory min_amounts, bool use_eth) external;
function remove_liquidity_one_coin(uint256 token_amount, uint256 i, uint256 min_amount)
external
returns (uint256);
function remove_liquidity_one_coin(uint256 token_amount, uint256 i, uint256 min_amount, bool use_eth)
external
returns (uint256);
function revert_new_parameters() external;
function revert_transfer_ownership() external;
function set_admin_fee_receiver(address _admin_fee_receiver) external;
function stop_ramp_A_gamma() external;
function token() external view returns (address);
function transfer_ownership_deadline() external view returns (uint256);
function unkill_me() external;
function virtual_price() external view returns (uint256);
function xcp_profit() external view returns (uint256);
function xcp_profit_a() external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
IClaimZap constant ZAP_CLAIM = IClaimZap(0x3f29cB4111CbdA8081642DA1f75B3c12DECf2516);
interface IClaimZap {
function claimRewards(
address[] calldata rewardContracts,
address[] calldata extraRewardContracts,
address[] calldata tokenRewardContracts,
address[] calldata tokenRewardTokens,
uint256 depositCrvMaxAmount,
uint256 minAmountOut,
uint256 depositCvxMaxAmount,
uint256 spendCvxAmount,
uint256 options
) external;
}// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; address constant CVX = 0x4e3FBD56CD56c3e72c1403e103b45Db9da5B9D2B;
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IAfEth is IERC20 {
error StrategyAlreadyAdded();
error InvalidFee();
error Paused();
error WithdrawingLockedRewards();
error BelowMinOut();
error AboveMaxIn();
error StaleAction();
error NotAuthorizedToRebalance();
error InvalidShare();
error InitialDepositBelowMinOut();
error TooMuchInitializationEth();
error AboveActionMax();
event SetRewarder(address indexed newAddress);
event SetSfrxStrategyShare(uint256 indexed newShare);
event SetProtocolFee(uint256 indexed newProtocolFee);
event EmergencyShutdown();
event Deposit(address indexed recipient, uint256 afEthAmount, uint256 ethAmount);
event FullWithdraw(address indexed recipient, uint256 ethAmount);
event PartialWithdraw(address indexed recipient, uint256 ethAmountNow, uint256 cumulativeUnlockThreshold);
event DepositRewards(address indexed recipient, uint256 afEthAmount, uint256 ethAmount);
event QuickActionsConfigured(
uint256 stakeFeeBps, uint256 unstakeFeeBps, uint256 maxSingleQuickStake, uint256 maxSingleQuickUnstake
);
function deposit(uint256 minDepositValue, uint256 deadline) external payable returns (uint256 shares);
function deposit(address to, uint256 minDepositValue, uint256 deadline) external payable returns (uint256 shares);
/**
* @param cvxPerEthMin Minimum accepted CVX/ETH price when converting ETH to CVX.
* @param sfrxPerEthMin Minimum accepted sfrxETH/ETH price when converting ETH to sfrxETH.
* @param ethPerSfrxMin Minimum accepted ETH/sfrxETH price when converting sfrxETH to ETH.
* @param deadline Last timestamp at which this call will be valid.
*/
struct RebalanceParams {
uint256 cvxPerEthMin;
uint256 sfrxPerEthMin;
uint256 ethPerSfrxMin;
uint256 deadline;
}
function depositRewardsAndRebalance(RebalanceParams calldata params) external payable;
function quickDeposit(uint256 minOut, uint256 deadline) external payable returns (uint256 afEthOut);
function quickDeposit(address to, uint256 minOut, uint256 deadline) external payable returns (uint256 afEthOut);
function quickWithdraw(uint256 amount, uint256 minOut, uint256 deadline) external returns (uint256 ethOut);
function quickWithdraw(address to, uint256 amount, uint256 minOut, uint256 deadline)
external
returns (uint256 ethOut);
function reportValue()
external
view
returns (
uint256 activeSfrxRatio,
uint256 sfrxStrategyValue,
uint256 votiumValue,
uint256 unlockedInactiveRewards,
uint256 lockedRewards
);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC1822.sol)
pragma solidity ^0.8.20;
/**
* @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
* proxy whose upgrades are fully controlled by the current implementation.
*/
interface IERC1822Proxiable {
/**
* @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
* address.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy.
*/
function proxiableUUID() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Utils.sol)
pragma solidity ^0.8.20;
import {IBeacon} from "../beacon/IBeacon.sol";
import {Address} from "../../utils/Address.sol";
import {StorageSlot} from "../../utils/StorageSlot.sol";
/**
* @dev This abstract contract provides getters and event emitting update functions for
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
*/
library ERC1967Utils {
// We re-declare ERC-1967 events here because they can't be used directly from IERC1967.
// This will be fixed in Solidity 0.8.21. At that point we should remove these events.
/**
* @dev Emitted when the implementation is upgraded.
*/
event Upgraded(address indexed implementation);
/**
* @dev Emitted when the admin account has changed.
*/
event AdminChanged(address previousAdmin, address newAdmin);
/**
* @dev Emitted when the beacon is changed.
*/
event BeaconUpgraded(address indexed beacon);
/**
* @dev Storage slot with the address of the current implementation.
* This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1.
*/
// solhint-disable-next-line private-vars-leading-underscore
bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/**
* @dev The `implementation` of the proxy is invalid.
*/
error ERC1967InvalidImplementation(address implementation);
/**
* @dev The `admin` of the proxy is invalid.
*/
error ERC1967InvalidAdmin(address admin);
/**
* @dev The `beacon` of the proxy is invalid.
*/
error ERC1967InvalidBeacon(address beacon);
/**
* @dev An upgrade function sees `msg.value > 0` that may be lost.
*/
error ERC1967NonPayable();
/**
* @dev Returns the current implementation address.
*/
function getImplementation() internal view returns (address) {
return StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 implementation slot.
*/
function _setImplementation(address newImplementation) private {
if (newImplementation.code.length == 0) {
revert ERC1967InvalidImplementation(newImplementation);
}
StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation;
}
/**
* @dev Performs implementation upgrade with additional setup call if data is nonempty.
* This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
* to avoid stuck value in the contract.
*
* Emits an {IERC1967-Upgraded} event.
*/
function upgradeToAndCall(address newImplementation, bytes memory data) internal {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
if (data.length > 0) {
Address.functionDelegateCall(newImplementation, data);
} else {
_checkNonPayable();
}
}
/**
* @dev Storage slot with the admin of the contract.
* This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1.
*/
// solhint-disable-next-line private-vars-leading-underscore
bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
/**
* @dev Returns the current admin.
*
* TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using
* the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
* `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
*/
function getAdmin() internal view returns (address) {
return StorageSlot.getAddressSlot(ADMIN_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 admin slot.
*/
function _setAdmin(address newAdmin) private {
if (newAdmin == address(0)) {
revert ERC1967InvalidAdmin(address(0));
}
StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin;
}
/**
* @dev Changes the admin of the proxy.
*
* Emits an {IERC1967-AdminChanged} event.
*/
function changeAdmin(address newAdmin) internal {
emit AdminChanged(getAdmin(), newAdmin);
_setAdmin(newAdmin);
}
/**
* @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
* This is the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1.
*/
// solhint-disable-next-line private-vars-leading-underscore
bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
/**
* @dev Returns the current beacon.
*/
function getBeacon() internal view returns (address) {
return StorageSlot.getAddressSlot(BEACON_SLOT).value;
}
/**
* @dev Stores a new beacon in the EIP1967 beacon slot.
*/
function _setBeacon(address newBeacon) private {
if (newBeacon.code.length == 0) {
revert ERC1967InvalidBeacon(newBeacon);
}
StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon;
address beaconImplementation = IBeacon(newBeacon).implementation();
if (beaconImplementation.code.length == 0) {
revert ERC1967InvalidImplementation(beaconImplementation);
}
}
/**
* @dev Change the beacon and trigger a setup call if data is nonempty.
* This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
* to avoid stuck value in the contract.
*
* Emits an {IERC1967-BeaconUpgraded} event.
*
* CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since
* it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for
* efficiency.
*/
function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal {
_setBeacon(newBeacon);
emit BeaconUpgraded(newBeacon);
if (data.length > 0) {
Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
} else {
_checkNonPayable();
}
}
/**
* @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract
* if an upgrade doesn't perform an initialization call.
*/
function _checkNonPayable() private {
if (msg.value > 0) {
revert ERC1967NonPayable();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.20;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Storage of the initializable contract.
*
* It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
* when using with upgradeable contracts.
*
* @custom:storage-location erc7201:openzeppelin.storage.Initializable
*/
struct InitializableStorage {
/**
* @dev Indicates that the contract has been initialized.
*/
uint64 _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
/**
* @dev The contract is already initialized.
*/
error InvalidInitialization();
/**
* @dev The contract is not initializing.
*/
error NotInitializing();
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint64 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
* number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
* production.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
// Cache values to avoid duplicated sloads
bool isTopLevelCall = !$._initializing;
uint64 initialized = $._initialized;
// Allowed calls:
// - initialSetup: the contract is not in the initializing state and no previous version was
// initialized
// - construction: the contract is initialized at version 1 (no reininitialization) and the
// current contract is just being deployed
bool initialSetup = initialized == 0 && isTopLevelCall;
bool construction = initialized == 1 && address(this).code.length == 0;
if (!initialSetup && !construction) {
revert InvalidInitialization();
}
$._initialized = 1;
if (isTopLevelCall) {
$._initializing = true;
}
_;
if (isTopLevelCall) {
$._initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint64 version) {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing || $._initialized >= version) {
revert InvalidInitialization();
}
$._initialized = version;
$._initializing = true;
_;
$._initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
_checkInitializing();
_;
}
/**
* @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
*/
function _checkInitializing() internal view virtual {
if (!_isInitializing()) {
revert NotInitializing();
}
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing) {
revert InvalidInitialization();
}
if ($._initialized != type(uint64).max) {
$._initialized = type(uint64).max;
emit Initialized(type(uint64).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint64) {
return _getInitializableStorage()._initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _getInitializableStorage()._initializing;
}
/**
* @dev Returns a pointer to the storage namespace.
*/
// solhint-disable-next-line var-name-mixedcase
function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
assembly {
$.slot := INITIALIZABLE_STORAGE
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
pragma solidity ^0.8.20;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```solidity
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position is the index of the value in the `values` array plus 1.
// Position 0 is used to mean a value is not in the set.
mapping(bytes32 value => uint256) _positions;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._positions[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We cache the value's position to prevent multiple reads from the same storage slot
uint256 position = set._positions[value];
if (position != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 valueIndex = position - 1;
uint256 lastIndex = set._values.length - 1;
if (valueIndex != lastIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the lastValue to the index where the value to delete is
set._values[valueIndex] = lastValue;
// Update the tracked position of the lastValue (that was just moved)
set._positions[lastValue] = position;
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the tracked position for the deleted slot
delete set._positions[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._positions[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface AggregatorV3Interface {
function decimals() external view returns (uint8);
function description() external view returns (string memory);
function version() external view returns (uint256);
function getRoundData(
uint80 _roundId
) external view returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);
function latestRoundData()
external
view
returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol)
pragma solidity ^0.8.20;
/**
* @dev This is the interface that {BeaconProxy} expects of its beacon.
*/
interface IBeacon {
/**
* @dev Must return an address that can be used as a delegate call target.
*
* {UpgradeableBeacon} will check that this address is a contract.
*/
function implementation() external view returns (address);
}// 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.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity ^0.8.20;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```solidity
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(newImplementation.code.length > 0);
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` representation of the string storage pointer `store`.
*/
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
/**
* @dev Returns an `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
*/
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
}{
"remappings": [
"@chainlink/=node_modules/@chainlink/",
"@eth-optimism/=node_modules/@eth-optimism/",
"@openzeppelin/=node_modules/@openzeppelin/",
"ds-test/=lib/forge-std/lib/ds-test/src/",
"forge-std/=lib/forge-std/src/",
"solady/=node_modules/solady/",
"solmate/=node_modules/solmate/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "paris",
"viaIR": false,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"afEth","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[{"internalType":"address","name":"implementation","type":"address"}],"name":"ERC1967InvalidImplementation","type":"error"},{"inputs":[],"name":"ERC1967NonPayable","type":"error"},{"inputs":[],"name":"ExchangeOutputBelowMin","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"InvalidOracleData","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoHandoverRequest","type":"error"},{"inputs":[],"name":"NonRewardCvxSpent","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"OracleDataStale","type":"error"},{"inputs":[],"name":"Shutdown","type":"error"},{"inputs":[],"name":"StaleAction","type":"error"},{"inputs":[],"name":"UUPSUnauthorizedCallContext","type":"error"},{"inputs":[{"internalType":"bytes32","name":"slot","type":"bytes32"}],"name":"UUPSUnsupportedProxiableUUID","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"UnauthorizedTarget","type":"error"},{"inputs":[],"name":"UnexpectedLockedCvxError","type":"error"},{"inputs":[],"name":"WithdrawalStillLocked","type":"error"},{"anonymous":false,"inputs":[],"name":"EmergencyShutdown","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"failedSwapIndex","type":"uint256"}],"name":"FailedToSell","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newRewarder","type":"address"}],"name":"RewarderSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"inputs":[],"name":"SNAPSHOT_DELEGATE_REGISTRY","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UPGRADE_INTERFACE_VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"availableCvx","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cancelOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes32[]","name":"merkleProof","type":"bytes32[]"}],"internalType":"struct IVotiumMerkleStash.ClaimParam[]","name":"claimProofs","type":"tuple[]"}],"name":"claimRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"completeOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"cvxMinOut","type":"uint256"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"cvxAmount","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"deposit","outputs":[{"internalType":"uint256","name":"cvxAmount","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"emergencyShutdown","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getObligations","outputs":[{"internalType":"uint256","name":"cumCvxUnlocked","type":"uint256"},{"internalType":"uint256","name":"cumCvxUnlockObligations","type":"uint256"},{"internalType":"uint256","name":"totalUnlockObligations","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"address","name":"token","type":"address"}],"internalType":"struct Allowance[]","name":"allowances","type":"tuple[]"}],"name":"grantAddedAllowances","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"initialOwner","type":"address"},{"internalType":"address","name":"initialRewarder","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"manager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"ownershipHandoverExpiresAt","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"processAndRelock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"requestOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"share","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"requestWithdraw","outputs":[{"internalType":"bool","name":"locked","type":"bool"},{"internalType":"uint256","name":"ethOutNow","type":"uint256"},{"internalType":"uint256","name":"cumulativeUnlockThreshold","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"address","name":"token","type":"address"}],"internalType":"struct Allowance","name":"allowance","type":"tuple"}],"name":"revokeSingleAllowance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewarder","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_delegate","type":"address"},{"internalType":"bytes32","name":"_id","type":"bytes32"}],"name":"setDelegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newRewarder","type":"address"}],"name":"setRewarder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"}],"internalType":"struct VotiumStrategy.Swap[]","name":"swaps","type":"tuple[]"},{"internalType":"uint256","name":"cvxPerEthMin","type":"uint256"},{"internalType":"uint256","name":"sfrxPerEthMin","type":"uint256"},{"internalType":"uint256","name":"ethPerSfrxMin","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalEthValue","outputs":[{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"unprocessedRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"cumulativeUnlockThreshold","type":"uint256"},{"internalType":"uint256","name":"minOut","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"withdrawLocked","outputs":[{"internalType":"uint256","name":"ethReceived","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"withdrawableAfterUnlocked","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
610100604052306080527f5f1d62cf240065b40cd9a62cce3108c9ed3b4fa2b2b0dd7805f31c7eae23413760a0527fc65f40fc7078beb3b353668ff8733b25201df0cd149aba86eee41d90cd57991860c0523480156200005e57600080fd5b5060405162002dc238038062002dc2833981016040819052620000819162000151565b6200008b6200009d565b6001600160a01b031660e05262000183565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000900460ff1615620000ee5760405163f92ee8a960e01b815260040160405180910390fd5b80546001600160401b03908116146200014e5780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b6000602082840312156200016457600080fd5b81516001600160a01b03811681146200017c57600080fd5b9392505050565b60805160a05160c05160e051612bdb620001e7600039600081816102b90152818161082501528181610d5501528181610e5901526112070152600061169b01526000611dfb015260008181611967015281816119900152611ad60152612bdb6000f3fe6080604052600436106101dc5760003560e01c806388cf4d2b11610102578063d0e30db011610095578063ee258bca11610064578063ee258bca14610537578063f04e283e14610567578063f2fde38b1461057a578063fee81cf41461058d57600080fd5b8063d0e30db0146104cf578063dcc3e06e146104d7578063e656be9d146104f7578063ea0889db1461051757600080fd5b8063adc3f30a116100d1578063adc3f30a14610442578063b6b55f251461046a578063c9c59f9c1461047d578063ccc143b81461049257600080fd5b806388cf4d2b146103a15780638da5cb5b146103c1578063928ac517146103da578063ad3cb1cc1461040457600080fd5b8063485cc9551161017a5780636436e3b7116101495780636436e3b71461034357806364dd179a1461035957806367b3219914610379578063715018a61461039957600080fd5b8063485cc955146102f35780634f1ef2861461031357806352d1902d1461032657806354d1f13d1461033b57600080fd5b80633403c2fc116101b65780633403c2fc1461023a5780633a6462e41461024f5780633ec8c0981461026f578063481c6a75146102a757600080fd5b80631115464b146101e857806325692962146102105780633194c9c51461021a57600080fd5b366101e357005b600080fd5b3480156101f457600080fd5b506101fd6105c0565b6040519081526020015b60405180910390f35b61021861061a565b005b34801561022657600080fd5b506101fd610235366004612340565b610669565b34801561024657600080fd5b506102186107f9565b34801561025b57600080fd5b5061021861026a366004612388565b6108d1565b34801561027b57600080fd5b506101fd61028a3660046123a3565b600360209081526000928352604080842090915290825290205481565b3480156102b357600080fd5b506102db7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610207565b3480156102ff57600080fd5b5061021861030e3660046123cd565b610921565b610218610321366004612442565b610b98565b34801561033257600080fd5b506101fd610bb7565b610218610bd5565b34801561034f57600080fd5b506101fd60025481565b34801561036557600080fd5b506102186103743660046123a3565b610c11565b34801561038557600080fd5b506102186103943660046124eb565b610c91565b610218610cb3565b3480156103ad57600080fd5b506102186103bc3660046124fd565b610cc7565b3480156103cd57600080fd5b50638b78c6d819546102db565b3480156103e657600080fd5b506103ef610d23565b60408051928352602083019190915201610207565b34801561041057600080fd5b50610435604051806040016040528060058152602001640352e302e360dc1b81525081565b6040516102079190612595565b34801561044e57600080fd5b506102db73469788fe6e9e9681c6ebf3bf78e7fd26fc01544681565b6101fd6104783660046125c8565b610d48565b34801561048957600080fd5b50610218610e1d565b34801561049e57600080fd5b506104b26104ad3660046125e1565b610e4a565b604080519315158452602084019290925290820152606001610207565b6101fd610fe2565b3480156104e357600080fd5b506000546102db906001600160a01b031681565b34801561050357600080fd5b5061021861051236600461264f565b610ff3565b34801561052357600080fd5b50610218610532366004612690565b6111ba565b34801561054357600080fd5b5061054c61148a565b60408051938452602084019290925290820152606001610207565b610218610575366004612388565b6114b3565b610218610588366004612388565b6114f0565b34801561059957600080fd5b506101fd6105a8366004612388565b63389a75e1600c908152600091909152602090205490565b6000806105cb61148a565b9250505060006105d9611517565b905060006105fb734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b3061158d565b9050826106088284612707565b610612919061271a565b935050505090565b60006202a3006001600160401b03164201905063389a75e1600c5233600052806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b600080546001600160a01b031661069357604051634426aa1f60e01b815260040160405180910390fd5b814211156106b457604051635d91de8560e01b815260040160405180910390fd5b336000908152600360209081526040808320878452909152812054908190036106dd57506107f2565b6000806106e861148a565b925050915060006106f76115b9565b905082881115610727578288038082101561072557604051638ba11fb360e01b815260040160405180910390fd5b505b3360009081526003602090815260408083208b845290915281205561074b846115e3565b610755908461272d565b600180546001600160801b03928316600160801b02921691909117905581811115610785576107858282036115fc565b866000036107b1576107ac734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b33866116e6565b6107ed565b6107ba8461172c565b9450868510156107dd57604051630175a68960e01b815260040160405180910390fd5b84156107ed576107ed33866117c0565b505050505b9392505050565b638b78c6d819546001600160a01b0316336001600160a01b031614806108475750336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145b610863576040516282b42960e81b815260040160405180910390fd5b600080546001600160a01b031916905561087b6117dc565b6040516000907f988fe7f79eda939055038334a107450a164e53747eb8ff449cf8f16f54f26ddd908290a26040517ff443ecad8d837e188abcabbbd02f1057b0d94896a09d5b97b2eb4bb445b94de890600090a1565b6108d9611871565b600080546001600160a01b0319166001600160a01b038316908117825560405190917f988fe7f79eda939055038334a107450a164e53747eb8ff449cf8f16f54f26ddd91a250565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff1615906001600160401b03166000811580156109665750825b90506000826001600160401b031660011480156109825750303b155b905081158015610990575080155b156109ae5760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff1916600117855583156109d857845460ff60401b1916600160401b1785555b6040516317b0dca160e31b8152660c6ecf05ccae8d60cb1b600482015273de1e6a7ed0ad3f61d531a8a78e83ccddbd6e0c49602482015273469788fe6e9e9681c6ebf3bf78e7fd26fc0154469063bd86e50890604401600060405180830381600087803b158015610a4857600080fd5b505af1158015610a5c573d6000803e3d6000fd5b5050600080546001600160a01b0319166001600160a01b038a1617905550610a8590508761188c565b610a8d6118c8565b604080518082019091527372a19342e8f1838460ebfccef09f6585e32db86e8152734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b6020820152610ad1906118d0565b6040805180820190915273b576491f1e6e5e62f1d8f26062ee822b40b0e0d48152734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b6020820152610b15906118d0565b6040516001600160a01b038716907f988fe7f79eda939055038334a107450a164e53747eb8ff449cf8f16f54f26ddd90600090a28315610b8f57845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50505050505050565b610ba061195c565b610ba982611a01565b610bb38282611a09565b5050565b6000610bc1611acb565b50600080516020612b868339815191525b90565b63389a75e1600c523360005260006020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b610c19611871565b6040516317b0dca160e31b8152600481018290526001600160a01b038316602482015273469788fe6e9e9681c6ebf3bf78e7fd26fc0154469063bd86e50890604401600060405180830381600087803b158015610c7557600080fd5b505af1158015610c89573d6000803e3d6000fd5b505050505050565b610c99611871565b610cb0610cab3683900383018361274d565b611b14565b50565b610cbb611871565b610cc56000611b6b565b565b610ccf611871565b8060005b81811015610d1d57610d0b848483818110610cf057610cf06127a7565b905060400201803603810190610d06919061274d565b6118d0565b80610d15816127bd565b915050610cd3565b50505050565b600080610d2e611ba9565b9050610d4281610d3c6105c0565b90611c9a565b91509091565b6000336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610d92576040516282b42960e81b815260040160405180910390fd5b610d9b34611cc8565b905081811015610dbe57604051630175a68960e01b815260040160405180910390fd5b6000610dc861148a565b92505050808210610df657610ddd6001611d58565b808203828214610df057610df0816115fc565b50610e17565b6000610e006115b9565b905081811115610e1557610e158282036115fc565b505b50919050565b6000610e2761148a565b925050506000610e356115b9565b905081811115610bb357610bb38282036115fc565b60008080336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610e96576040516282b42960e81b815260040160405180910390fd5b84600003610eac57506000915081905080610fdb565b600080610eb761148a565b92509250506000610ec66115b9565b90506000610ed2611517565b9050600083610ee18484612707565b610eeb919061271a565b90506000610ef9828c611c9a565b9050610f058186612707565b9450848410610f3257610f178161172c565b9750848403848614610f2c57610f2c816115fc565b50610fc4565b60019850610f3f816115e3565b610f49908761272d565b6001600160801b0316965080600360008c6001600160a01b03166001600160a01b0316815260200190815260200160002060008981526020019081526020016000206000828254610f9a9190612707565b9091555050600180546fffffffffffffffffffffffffffffffff19166001600160801b0389161790555b8715610fd457610fd433896117c0565b5050505050505b9250925092565b6000610fee6000610d48565b905090565b6000546001600160a01b0316331461101d576040516282b42960e81b815260040160405180910390fd5b600061103d734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b3061158d565b604051631067326f60e11b815290915073378ba9b73309be80bf4c2c027aad799766a7ed5a906320ce64de9061107b90309087908790600401612808565b600060405180830381600087803b15801561109557600080fd5b505af19250505080156110a6575060015b50604051632d3dc3f960e11b8152606090733f29cb4111cbda8081642da1f75b3c12decf251690635a7b87f2906110f3908490819081908190600090819081908190600890600401612942565b600060405180830381600087803b15801561110d57600080fd5b505af192505050801561111e575060015b50600082611140734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b3061158d565b61114a919061271a565b905080156111b35780600260008282546111649190612707565b909155506111739050816115e3565b6001805460009061118e9084906001600160801b031661272d565b92506101000a8154816001600160801b0302191690836001600160801b031602179055505b5050505050565b6000546001600160a01b031633146111e4576040516282b42960e81b815260040160405180910390fd5b8042111561120557604051635d91de8560e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006000611246734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b3061158d565b90508660005b8181101561135257368a8a83818110611267576112676127a7565b905060200281019061127991906129c0565b9050600061128a6020830183612388565b90506112968682611e20565b60006001600160a01b0382166112af60208501856129e0565b6040516112bd929190612a26565b6000604051808303816000865af19150503d80600081146112fa576040519150601f19603f3d011682016040523d82523d6000602084013e6112ff565b606091505b505090508061133c576040518481527fa362a1fca10d1593e1b865fbe33ff052006aaceff9cd835e7c5904fef347be929060200160405180910390a15b505050808061134a906127bd565b91505061124c565b506000611373734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b3061158d565b9050808311156113ed57600081840390508060026000828254611396919061271a565b909155506113a59050816115e3565b600180546010906113c7908490600160801b90046001600160801b031661272d565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550505b604080516080810182528981526020810189815281830189815242606084019081529351632990265b60e01b81529251600484015290516024830152516044820152905160648201526001600160a01b03851690632990265b9047906084016000604051808303818588803b15801561146557600080fd5b505af1158015611479573d6000803e3d6000fd5b505050505050505050505050505050565b6001546001600160801b03600160801b82048116911660006114ac838361271a565b9050909192565b6114bb611871565b63389a75e1600c52806000526020600c2080544211156114e357636f5e88186000526004601cfd5b60009055610cb081611b6b565b6114f8611871565b8060601b61150e57637448fbae6000526004601cfd5b610cb081611b6b565b604051632c9aab9b60e11b81523060048201526000907372a19342e8f1838460ebfccef09f6585e32db86e90635935573690602401602060405180830381865afa158015611569573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fee9190612a36565b6000816014526370a0823160601b60005260208060246010865afa601f3d111660205102905092915050565b60006115c56000611d58565b610fee734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b3061158d565b6000600160801b82106115f8576115f8611eb4565b5090565b60405163e2ab691d60e01b815230600482015260248101829052600060448201527372a19342e8f1838460ebfccef09f6585e32db86e9063e2ab691d90606401600060405180830381600087803b15801561165657600080fd5b505af1925050508015611667575060015b610cb057611673612a4f565b806308c379a0036116da5750611687612a6a565b8061169257506116dc565b805160208201207f0000000000000000000000000000000000000000000000000000000000000000905b14610bb35760405163b36c03f560e01b815260040160405180910390fd5b505b3d6000803e3d6000fd5b816014528060345263a9059cbb60601b60005260206000604460106000875af13d156001600051141716611722576390b8ec186000526004601cfd5b6000603452505050565b6040516365b2489b60e01b81526001600482015260006024820181905260448201839052606482018190529073b576491f1e6e5e62f1d8f26062ee822b40b0e0d4906365b2489b906084016020604051808303816000875af1158015611796573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117ba9190612a36565b92915050565b60003860003884865af1610bb35763b12d13eb6000526004601cfd5b7f6628618d7bc4d0dd1eb0a5bb53ba475441105535e20645110834c8c5d548ddb4600061180882611ec2565b905060005b8181101561186c5760006118218483611ecc565b60008181526002860160205260408120805460018201549394509092611857926001600160a01b03918216929190911690611ed8565b50508080611864906127bd565b91505061180d565b505050565b638b78c6d819543314610cc5576382b429006000526004601cfd5b6001600160a01b0316638b78c6d8198190558060007f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a350565b610cc5611f50565b7f6628618d7bc4d0dd1eb0a5bb53ba475441105535e20645110834c8c5d548ddb460006118fc83611f99565b90506119088282611fe7565b5060008181526002830160209081526040909120845181546001600160a01b038083166001600160a01b03199283161784559387015160019093018054939094169216821790925561186c91600019611ed8565b306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806119e357507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166119d7600080516020612b86833981519152546001600160a01b031690565b6001600160a01b031614155b15610cc55760405163703e46dd60e11b815260040160405180910390fd5b610cb0611871565b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015611a63575060408051601f3d908101601f19168201909252611a6091810190612a36565b60015b611a9057604051634c9c8ce360e01b81526001600160a01b03831660048201526024015b60405180910390fd5b600080516020612b868339815191528114611ac157604051632a87526960e21b815260048101829052602401611a87565b61186c8383611ff3565b306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610cc55760405163703e46dd60e11b815260040160405180910390fd5b7f6628618d7bc4d0dd1eb0a5bb53ba475441105535e20645110834c8c5d548ddb46000611b4083611f99565b9050611b4c8282612049565b508251602084015161186c916001600160a01b03909116906000611ed8565b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b60008060008073c9cbf687f43176b302f03f5e58470b77d07c61c66001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015611c01573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c259190612b0d565b50935050925092508269ffffffffffffffffffff1660001480611c485750600082125b15611c66576040516378de663960e11b815260040160405180910390fd5b62015f90611c74824261271a565b1115611c9357604051630e4e2b8f60e21b815260040160405180910390fd5b5092915050565b600081600019048311820215611cb85763bac65e5b6000526004601cfd5b50670de0b6b3a764000091020490565b6040516365b2489b60e01b81526000600482018190526001602483015260448201839052606482018190529073b576491f1e6e5e62f1d8f26062ee822b40b0e0d4906365b2489b90849060840160206040518083038185885af1158015611d33573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906117ba9190612a36565b6000611d62611517565b1115610cb05760405163312ff83960e01b815281151560048201527372a19342e8f1838460ebfccef09f6585e32db86e9063312ff83990602401600060405180830381600087803b158015611db657600080fd5b505af1925050508015611dc7575060015b610cb057611dd3612a4f565b806308c379a0036116da5750611de7612a6a565b80611df257506116dc565b805160208201207f0000000000000000000000000000000000000000000000000000000000000000906116bc565b816001600160a01b0316816001600160a01b03161480611e5c57506001600160a01b0381167372a19342e8f1838460ebfccef09f6585e32db86e145b80611e8357506001600160a01b038116734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b145b80611e9657506001600160a01b03811630145b15610bb3576040516385f92ca960e01b815260040160405180910390fd5b6335278d126000526004601cfd5b60006117ba825490565b60006107f28383612055565b816014528060345263095ea7b360601b60005260206000604460106000875af13d15600160005114171661172257600060345263095ea7b360601b600052600038604460106000875af1508060345260206000604460106000875af13d15600160005114171661172257633e3f8f736000526004601cfd5b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff16610cc557604051631afcd79f60e31b815260040160405180910390fd5b600081604051602001611fca919081516001600160a01b039081168252602092830151169181019190915260400190565b604051602081830303815290604052805190602001209050919050565b60006107f2838361207f565b611ffc826120ce565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a28051156120415761186c8282612133565b610bb36121a9565b60006107f283836121c8565b600082600001828154811061206c5761206c6127a7565b9060005260206000200154905092915050565b60008181526001830160205260408120546120c6575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556117ba565b5060006117ba565b806001600160a01b03163b60000361210457604051634c9c8ce360e01b81526001600160a01b0382166004820152602401611a87565b600080516020612b8683398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b6060600080846001600160a01b0316846040516121509190612b5d565b600060405180830381855af49150503d806000811461218b576040519150601f19603f3d011682016040523d82523d6000602084013e612190565b606091505b50915091506121a08583836122bb565b95945050505050565b3415610cc55760405163b398979f60e01b815260040160405180910390fd5b600081815260018301602052604081205480156122b15760006121ec60018361271a565b85549091506000906122009060019061271a565b9050808214612265576000866000018281548110612220576122206127a7565b9060005260206000200154905080876000018481548110612243576122436127a7565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061227657612276612b6f565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506117ba565b60009150506117ba565b6060826122d0576122cb82612317565b6107f2565b81511580156122e757506001600160a01b0384163b155b1561231057604051639996b31560e01b81526001600160a01b0385166004820152602401611a87565b50806107f2565b8051156123275780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b60008060006060848603121561235557600080fd5b505081359360208301359350604090920135919050565b80356001600160a01b038116811461238357600080fd5b919050565b60006020828403121561239a57600080fd5b6107f28261236c565b600080604083850312156123b657600080fd5b6123bf8361236c565b946020939093013593505050565b600080604083850312156123e057600080fd5b6123e98361236c565b91506123f76020840161236c565b90509250929050565b634e487b7160e01b600052604160045260246000fd5b601f8201601f191681016001600160401b038111828210171561243b5761243b612400565b6040525050565b6000806040838503121561245557600080fd5b61245e8361236c565b91506020808401356001600160401b038082111561247b57600080fd5b818601915086601f83011261248f57600080fd5b8135818111156124a1576124a1612400565b60405191506124b9601f8201601f1916850183612416565b80825287848285010111156124cd57600080fd5b80848401858401376000848284010152508093505050509250929050565b600060408284031215610e1757600080fd5b6000806020838503121561251057600080fd5b82356001600160401b038082111561252757600080fd5b818501915085601f83011261253b57600080fd5b81358181111561254a57600080fd5b8660208260061b850101111561255f57600080fd5b60209290920196919550909350505050565b60005b8381101561258c578181015183820152602001612574565b50506000910152565b60208152600082518060208401526125b4816040850160208701612571565b601f01601f19169190910160400192915050565b6000602082840312156125da57600080fd5b5035919050565b600080604083850312156125f457600080fd5b823591506123f76020840161236c565b60008083601f84011261261657600080fd5b5081356001600160401b0381111561262d57600080fd5b6020830191508360208260051b850101111561264857600080fd5b9250929050565b6000806020838503121561266257600080fd5b82356001600160401b0381111561267857600080fd5b61268485828601612604565b90969095509350505050565b60008060008060008060a087890312156126a957600080fd5b86356001600160401b038111156126bf57600080fd5b6126cb89828a01612604565b909a90995060208901359860408101359850606081013597506080013595509350505050565b634e487b7160e01b600052601160045260246000fd5b808201808211156117ba576117ba6126f1565b818103818111156117ba576117ba6126f1565b6001600160801b03818116838216019080821115611c9357611c936126f1565b60006040828403121561275f57600080fd5b604051604081018181106001600160401b038211171561278157612781612400565b60405261278d8361236c565b815261279b6020840161236c565b60208201529392505050565b634e487b7160e01b600052603260045260246000fd5b6000600182016127cf576127cf6126f1565b5060010190565b81835260006001600160fb1b038311156127ef57600080fd5b8260051b80836020870137939093016020019392505050565b6001600160a01b03848116825260406020808401829052838201859052600092606091828601600588811b880185018a885b8b8110156128ec578a8303605f190185528135368e9003607e1901811261286057600080fd5b8d0160808861286e8361236c565b16855287820135888601528a8201358b86015289820135601e1983360301811261289757600080fd5b9091018781019190356001600160401b038111156128b457600080fd5b80871b36038313156128c557600080fd5b818b8701526128d782870182856127d6565b9789019795505050918601915060010161283a565b50909c9b505050505050505050505050565b600081518084526020808501945080840160005b838110156129375781516001600160a01b031687529582019590820190600101612912565b509495945050505050565b60006101208083526129568184018d6128fe565b9050828103602084015261296a818c6128fe565b9050828103604084015261297e818b6128fe565b90508281036060840152612992818a6128fe565b6080840198909852505060a081019490945260c084019290925260e083015261010090910152949350505050565b60008235603e198336030181126129d657600080fd5b9190910192915050565b6000808335601e198436030181126129f757600080fd5b8301803591506001600160401b03821115612a1157600080fd5b60200191503681900382131561264857600080fd5b8183823760009101908152919050565b600060208284031215612a4857600080fd5b5051919050565b600060033d1115610bd25760046000803e5060005160e01c90565b600060443d1015612a785790565b6040516003193d81016004833e81513d6001600160401b038160248401118184111715612aa757505050505090565b8285019150815181811115612abf5750505050505090565b843d8701016020828501011115612ad95750505050505090565b612ae860208286010187612416565b509095945050505050565b805169ffffffffffffffffffff8116811461238357600080fd5b600080600080600060a08688031215612b2557600080fd5b612b2e86612af3565b9450602086015193506040860151925060608601519150612b5160808701612af3565b90509295509295909350565b600082516129d6818460208701612571565b634e487b7160e01b600052603160045260246000fdfe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca26469706673582212204c9ed3a6495e59b7bdc8ea52235c49efbe1fedd7ee61df8ac7f4852fcaf6fdfd64736f6c634300081400330000000000000000000000000000000016e6cb3038203c1129c8b4aee7af7a11
Deployed Bytecode
0x6080604052600436106101dc5760003560e01c806388cf4d2b11610102578063d0e30db011610095578063ee258bca11610064578063ee258bca14610537578063f04e283e14610567578063f2fde38b1461057a578063fee81cf41461058d57600080fd5b8063d0e30db0146104cf578063dcc3e06e146104d7578063e656be9d146104f7578063ea0889db1461051757600080fd5b8063adc3f30a116100d1578063adc3f30a14610442578063b6b55f251461046a578063c9c59f9c1461047d578063ccc143b81461049257600080fd5b806388cf4d2b146103a15780638da5cb5b146103c1578063928ac517146103da578063ad3cb1cc1461040457600080fd5b8063485cc9551161017a5780636436e3b7116101495780636436e3b71461034357806364dd179a1461035957806367b3219914610379578063715018a61461039957600080fd5b8063485cc955146102f35780634f1ef2861461031357806352d1902d1461032657806354d1f13d1461033b57600080fd5b80633403c2fc116101b65780633403c2fc1461023a5780633a6462e41461024f5780633ec8c0981461026f578063481c6a75146102a757600080fd5b80631115464b146101e857806325692962146102105780633194c9c51461021a57600080fd5b366101e357005b600080fd5b3480156101f457600080fd5b506101fd6105c0565b6040519081526020015b60405180910390f35b61021861061a565b005b34801561022657600080fd5b506101fd610235366004612340565b610669565b34801561024657600080fd5b506102186107f9565b34801561025b57600080fd5b5061021861026a366004612388565b6108d1565b34801561027b57600080fd5b506101fd61028a3660046123a3565b600360209081526000928352604080842090915290825290205481565b3480156102b357600080fd5b506102db7f0000000000000000000000000000000016e6cb3038203c1129c8b4aee7af7a1181565b6040516001600160a01b039091168152602001610207565b3480156102ff57600080fd5b5061021861030e3660046123cd565b610921565b610218610321366004612442565b610b98565b34801561033257600080fd5b506101fd610bb7565b610218610bd5565b34801561034f57600080fd5b506101fd60025481565b34801561036557600080fd5b506102186103743660046123a3565b610c11565b34801561038557600080fd5b506102186103943660046124eb565b610c91565b610218610cb3565b3480156103ad57600080fd5b506102186103bc3660046124fd565b610cc7565b3480156103cd57600080fd5b50638b78c6d819546102db565b3480156103e657600080fd5b506103ef610d23565b60408051928352602083019190915201610207565b34801561041057600080fd5b50610435604051806040016040528060058152602001640352e302e360dc1b81525081565b6040516102079190612595565b34801561044e57600080fd5b506102db73469788fe6e9e9681c6ebf3bf78e7fd26fc01544681565b6101fd6104783660046125c8565b610d48565b34801561048957600080fd5b50610218610e1d565b34801561049e57600080fd5b506104b26104ad3660046125e1565b610e4a565b604080519315158452602084019290925290820152606001610207565b6101fd610fe2565b3480156104e357600080fd5b506000546102db906001600160a01b031681565b34801561050357600080fd5b5061021861051236600461264f565b610ff3565b34801561052357600080fd5b50610218610532366004612690565b6111ba565b34801561054357600080fd5b5061054c61148a565b60408051938452602084019290925290820152606001610207565b610218610575366004612388565b6114b3565b610218610588366004612388565b6114f0565b34801561059957600080fd5b506101fd6105a8366004612388565b63389a75e1600c908152600091909152602090205490565b6000806105cb61148a565b9250505060006105d9611517565b905060006105fb734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b3061158d565b9050826106088284612707565b610612919061271a565b935050505090565b60006202a3006001600160401b03164201905063389a75e1600c5233600052806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b600080546001600160a01b031661069357604051634426aa1f60e01b815260040160405180910390fd5b814211156106b457604051635d91de8560e01b815260040160405180910390fd5b336000908152600360209081526040808320878452909152812054908190036106dd57506107f2565b6000806106e861148a565b925050915060006106f76115b9565b905082881115610727578288038082101561072557604051638ba11fb360e01b815260040160405180910390fd5b505b3360009081526003602090815260408083208b845290915281205561074b846115e3565b610755908461272d565b600180546001600160801b03928316600160801b02921691909117905581811115610785576107858282036115fc565b866000036107b1576107ac734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b33866116e6565b6107ed565b6107ba8461172c565b9450868510156107dd57604051630175a68960e01b815260040160405180910390fd5b84156107ed576107ed33866117c0565b505050505b9392505050565b638b78c6d819546001600160a01b0316336001600160a01b031614806108475750336001600160a01b037f0000000000000000000000000000000016e6cb3038203c1129c8b4aee7af7a1116145b610863576040516282b42960e81b815260040160405180910390fd5b600080546001600160a01b031916905561087b6117dc565b6040516000907f988fe7f79eda939055038334a107450a164e53747eb8ff449cf8f16f54f26ddd908290a26040517ff443ecad8d837e188abcabbbd02f1057b0d94896a09d5b97b2eb4bb445b94de890600090a1565b6108d9611871565b600080546001600160a01b0319166001600160a01b038316908117825560405190917f988fe7f79eda939055038334a107450a164e53747eb8ff449cf8f16f54f26ddd91a250565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff1615906001600160401b03166000811580156109665750825b90506000826001600160401b031660011480156109825750303b155b905081158015610990575080155b156109ae5760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff1916600117855583156109d857845460ff60401b1916600160401b1785555b6040516317b0dca160e31b8152660c6ecf05ccae8d60cb1b600482015273de1e6a7ed0ad3f61d531a8a78e83ccddbd6e0c49602482015273469788fe6e9e9681c6ebf3bf78e7fd26fc0154469063bd86e50890604401600060405180830381600087803b158015610a4857600080fd5b505af1158015610a5c573d6000803e3d6000fd5b5050600080546001600160a01b0319166001600160a01b038a1617905550610a8590508761188c565b610a8d6118c8565b604080518082019091527372a19342e8f1838460ebfccef09f6585e32db86e8152734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b6020820152610ad1906118d0565b6040805180820190915273b576491f1e6e5e62f1d8f26062ee822b40b0e0d48152734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b6020820152610b15906118d0565b6040516001600160a01b038716907f988fe7f79eda939055038334a107450a164e53747eb8ff449cf8f16f54f26ddd90600090a28315610b8f57845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50505050505050565b610ba061195c565b610ba982611a01565b610bb38282611a09565b5050565b6000610bc1611acb565b50600080516020612b868339815191525b90565b63389a75e1600c523360005260006020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b610c19611871565b6040516317b0dca160e31b8152600481018290526001600160a01b038316602482015273469788fe6e9e9681c6ebf3bf78e7fd26fc0154469063bd86e50890604401600060405180830381600087803b158015610c7557600080fd5b505af1158015610c89573d6000803e3d6000fd5b505050505050565b610c99611871565b610cb0610cab3683900383018361274d565b611b14565b50565b610cbb611871565b610cc56000611b6b565b565b610ccf611871565b8060005b81811015610d1d57610d0b848483818110610cf057610cf06127a7565b905060400201803603810190610d06919061274d565b6118d0565b80610d15816127bd565b915050610cd3565b50505050565b600080610d2e611ba9565b9050610d4281610d3c6105c0565b90611c9a565b91509091565b6000336001600160a01b037f0000000000000000000000000000000016e6cb3038203c1129c8b4aee7af7a111614610d92576040516282b42960e81b815260040160405180910390fd5b610d9b34611cc8565b905081811015610dbe57604051630175a68960e01b815260040160405180910390fd5b6000610dc861148a565b92505050808210610df657610ddd6001611d58565b808203828214610df057610df0816115fc565b50610e17565b6000610e006115b9565b905081811115610e1557610e158282036115fc565b505b50919050565b6000610e2761148a565b925050506000610e356115b9565b905081811115610bb357610bb38282036115fc565b60008080336001600160a01b037f0000000000000000000000000000000016e6cb3038203c1129c8b4aee7af7a111614610e96576040516282b42960e81b815260040160405180910390fd5b84600003610eac57506000915081905080610fdb565b600080610eb761148a565b92509250506000610ec66115b9565b90506000610ed2611517565b9050600083610ee18484612707565b610eeb919061271a565b90506000610ef9828c611c9a565b9050610f058186612707565b9450848410610f3257610f178161172c565b9750848403848614610f2c57610f2c816115fc565b50610fc4565b60019850610f3f816115e3565b610f49908761272d565b6001600160801b0316965080600360008c6001600160a01b03166001600160a01b0316815260200190815260200160002060008981526020019081526020016000206000828254610f9a9190612707565b9091555050600180546fffffffffffffffffffffffffffffffff19166001600160801b0389161790555b8715610fd457610fd433896117c0565b5050505050505b9250925092565b6000610fee6000610d48565b905090565b6000546001600160a01b0316331461101d576040516282b42960e81b815260040160405180910390fd5b600061103d734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b3061158d565b604051631067326f60e11b815290915073378ba9b73309be80bf4c2c027aad799766a7ed5a906320ce64de9061107b90309087908790600401612808565b600060405180830381600087803b15801561109557600080fd5b505af19250505080156110a6575060015b50604051632d3dc3f960e11b8152606090733f29cb4111cbda8081642da1f75b3c12decf251690635a7b87f2906110f3908490819081908190600090819081908190600890600401612942565b600060405180830381600087803b15801561110d57600080fd5b505af192505050801561111e575060015b50600082611140734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b3061158d565b61114a919061271a565b905080156111b35780600260008282546111649190612707565b909155506111739050816115e3565b6001805460009061118e9084906001600160801b031661272d565b92506101000a8154816001600160801b0302191690836001600160801b031602179055505b5050505050565b6000546001600160a01b031633146111e4576040516282b42960e81b815260040160405180910390fd5b8042111561120557604051635d91de8560e01b815260040160405180910390fd5b7f0000000000000000000000000000000016e6cb3038203c1129c8b4aee7af7a116000611246734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b3061158d565b90508660005b8181101561135257368a8a83818110611267576112676127a7565b905060200281019061127991906129c0565b9050600061128a6020830183612388565b90506112968682611e20565b60006001600160a01b0382166112af60208501856129e0565b6040516112bd929190612a26565b6000604051808303816000865af19150503d80600081146112fa576040519150601f19603f3d011682016040523d82523d6000602084013e6112ff565b606091505b505090508061133c576040518481527fa362a1fca10d1593e1b865fbe33ff052006aaceff9cd835e7c5904fef347be929060200160405180910390a15b505050808061134a906127bd565b91505061124c565b506000611373734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b3061158d565b9050808311156113ed57600081840390508060026000828254611396919061271a565b909155506113a59050816115e3565b600180546010906113c7908490600160801b90046001600160801b031661272d565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550505b604080516080810182528981526020810189815281830189815242606084019081529351632990265b60e01b81529251600484015290516024830152516044820152905160648201526001600160a01b03851690632990265b9047906084016000604051808303818588803b15801561146557600080fd5b505af1158015611479573d6000803e3d6000fd5b505050505050505050505050505050565b6001546001600160801b03600160801b82048116911660006114ac838361271a565b9050909192565b6114bb611871565b63389a75e1600c52806000526020600c2080544211156114e357636f5e88186000526004601cfd5b60009055610cb081611b6b565b6114f8611871565b8060601b61150e57637448fbae6000526004601cfd5b610cb081611b6b565b604051632c9aab9b60e11b81523060048201526000907372a19342e8f1838460ebfccef09f6585e32db86e90635935573690602401602060405180830381865afa158015611569573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fee9190612a36565b6000816014526370a0823160601b60005260208060246010865afa601f3d111660205102905092915050565b60006115c56000611d58565b610fee734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b3061158d565b6000600160801b82106115f8576115f8611eb4565b5090565b60405163e2ab691d60e01b815230600482015260248101829052600060448201527372a19342e8f1838460ebfccef09f6585e32db86e9063e2ab691d90606401600060405180830381600087803b15801561165657600080fd5b505af1925050508015611667575060015b610cb057611673612a4f565b806308c379a0036116da5750611687612a6a565b8061169257506116dc565b805160208201207fc65f40fc7078beb3b353668ff8733b25201df0cd149aba86eee41d90cd579918905b14610bb35760405163b36c03f560e01b815260040160405180910390fd5b505b3d6000803e3d6000fd5b816014528060345263a9059cbb60601b60005260206000604460106000875af13d156001600051141716611722576390b8ec186000526004601cfd5b6000603452505050565b6040516365b2489b60e01b81526001600482015260006024820181905260448201839052606482018190529073b576491f1e6e5e62f1d8f26062ee822b40b0e0d4906365b2489b906084016020604051808303816000875af1158015611796573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117ba9190612a36565b92915050565b60003860003884865af1610bb35763b12d13eb6000526004601cfd5b7f6628618d7bc4d0dd1eb0a5bb53ba475441105535e20645110834c8c5d548ddb4600061180882611ec2565b905060005b8181101561186c5760006118218483611ecc565b60008181526002860160205260408120805460018201549394509092611857926001600160a01b03918216929190911690611ed8565b50508080611864906127bd565b91505061180d565b505050565b638b78c6d819543314610cc5576382b429006000526004601cfd5b6001600160a01b0316638b78c6d8198190558060007f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a350565b610cc5611f50565b7f6628618d7bc4d0dd1eb0a5bb53ba475441105535e20645110834c8c5d548ddb460006118fc83611f99565b90506119088282611fe7565b5060008181526002830160209081526040909120845181546001600160a01b038083166001600160a01b03199283161784559387015160019093018054939094169216821790925561186c91600019611ed8565b306001600160a01b037f000000000000000000000000b628b1fdbe8c01777aea2bf3bd386df4af84e8d31614806119e357507f000000000000000000000000b628b1fdbe8c01777aea2bf3bd386df4af84e8d36001600160a01b03166119d7600080516020612b86833981519152546001600160a01b031690565b6001600160a01b031614155b15610cc55760405163703e46dd60e11b815260040160405180910390fd5b610cb0611871565b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015611a63575060408051601f3d908101601f19168201909252611a6091810190612a36565b60015b611a9057604051634c9c8ce360e01b81526001600160a01b03831660048201526024015b60405180910390fd5b600080516020612b868339815191528114611ac157604051632a87526960e21b815260048101829052602401611a87565b61186c8383611ff3565b306001600160a01b037f000000000000000000000000b628b1fdbe8c01777aea2bf3bd386df4af84e8d31614610cc55760405163703e46dd60e11b815260040160405180910390fd5b7f6628618d7bc4d0dd1eb0a5bb53ba475441105535e20645110834c8c5d548ddb46000611b4083611f99565b9050611b4c8282612049565b508251602084015161186c916001600160a01b03909116906000611ed8565b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b60008060008073c9cbf687f43176b302f03f5e58470b77d07c61c66001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015611c01573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c259190612b0d565b50935050925092508269ffffffffffffffffffff1660001480611c485750600082125b15611c66576040516378de663960e11b815260040160405180910390fd5b62015f90611c74824261271a565b1115611c9357604051630e4e2b8f60e21b815260040160405180910390fd5b5092915050565b600081600019048311820215611cb85763bac65e5b6000526004601cfd5b50670de0b6b3a764000091020490565b6040516365b2489b60e01b81526000600482018190526001602483015260448201839052606482018190529073b576491f1e6e5e62f1d8f26062ee822b40b0e0d4906365b2489b90849060840160206040518083038185885af1158015611d33573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906117ba9190612a36565b6000611d62611517565b1115610cb05760405163312ff83960e01b815281151560048201527372a19342e8f1838460ebfccef09f6585e32db86e9063312ff83990602401600060405180830381600087803b158015611db657600080fd5b505af1925050508015611dc7575060015b610cb057611dd3612a4f565b806308c379a0036116da5750611de7612a6a565b80611df257506116dc565b805160208201207f5f1d62cf240065b40cd9a62cce3108c9ed3b4fa2b2b0dd7805f31c7eae234137906116bc565b816001600160a01b0316816001600160a01b03161480611e5c57506001600160a01b0381167372a19342e8f1838460ebfccef09f6585e32db86e145b80611e8357506001600160a01b038116734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b145b80611e9657506001600160a01b03811630145b15610bb3576040516385f92ca960e01b815260040160405180910390fd5b6335278d126000526004601cfd5b60006117ba825490565b60006107f28383612055565b816014528060345263095ea7b360601b60005260206000604460106000875af13d15600160005114171661172257600060345263095ea7b360601b600052600038604460106000875af1508060345260206000604460106000875af13d15600160005114171661172257633e3f8f736000526004601cfd5b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff16610cc557604051631afcd79f60e31b815260040160405180910390fd5b600081604051602001611fca919081516001600160a01b039081168252602092830151169181019190915260400190565b604051602081830303815290604052805190602001209050919050565b60006107f2838361207f565b611ffc826120ce565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a28051156120415761186c8282612133565b610bb36121a9565b60006107f283836121c8565b600082600001828154811061206c5761206c6127a7565b9060005260206000200154905092915050565b60008181526001830160205260408120546120c6575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556117ba565b5060006117ba565b806001600160a01b03163b60000361210457604051634c9c8ce360e01b81526001600160a01b0382166004820152602401611a87565b600080516020612b8683398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b6060600080846001600160a01b0316846040516121509190612b5d565b600060405180830381855af49150503d806000811461218b576040519150601f19603f3d011682016040523d82523d6000602084013e612190565b606091505b50915091506121a08583836122bb565b95945050505050565b3415610cc55760405163b398979f60e01b815260040160405180910390fd5b600081815260018301602052604081205480156122b15760006121ec60018361271a565b85549091506000906122009060019061271a565b9050808214612265576000866000018281548110612220576122206127a7565b9060005260206000200154905080876000018481548110612243576122436127a7565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061227657612276612b6f565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506117ba565b60009150506117ba565b6060826122d0576122cb82612317565b6107f2565b81511580156122e757506001600160a01b0384163b155b1561231057604051639996b31560e01b81526001600160a01b0385166004820152602401611a87565b50806107f2565b8051156123275780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b60008060006060848603121561235557600080fd5b505081359360208301359350604090920135919050565b80356001600160a01b038116811461238357600080fd5b919050565b60006020828403121561239a57600080fd5b6107f28261236c565b600080604083850312156123b657600080fd5b6123bf8361236c565b946020939093013593505050565b600080604083850312156123e057600080fd5b6123e98361236c565b91506123f76020840161236c565b90509250929050565b634e487b7160e01b600052604160045260246000fd5b601f8201601f191681016001600160401b038111828210171561243b5761243b612400565b6040525050565b6000806040838503121561245557600080fd5b61245e8361236c565b91506020808401356001600160401b038082111561247b57600080fd5b818601915086601f83011261248f57600080fd5b8135818111156124a1576124a1612400565b60405191506124b9601f8201601f1916850183612416565b80825287848285010111156124cd57600080fd5b80848401858401376000848284010152508093505050509250929050565b600060408284031215610e1757600080fd5b6000806020838503121561251057600080fd5b82356001600160401b038082111561252757600080fd5b818501915085601f83011261253b57600080fd5b81358181111561254a57600080fd5b8660208260061b850101111561255f57600080fd5b60209290920196919550909350505050565b60005b8381101561258c578181015183820152602001612574565b50506000910152565b60208152600082518060208401526125b4816040850160208701612571565b601f01601f19169190910160400192915050565b6000602082840312156125da57600080fd5b5035919050565b600080604083850312156125f457600080fd5b823591506123f76020840161236c565b60008083601f84011261261657600080fd5b5081356001600160401b0381111561262d57600080fd5b6020830191508360208260051b850101111561264857600080fd5b9250929050565b6000806020838503121561266257600080fd5b82356001600160401b0381111561267857600080fd5b61268485828601612604565b90969095509350505050565b60008060008060008060a087890312156126a957600080fd5b86356001600160401b038111156126bf57600080fd5b6126cb89828a01612604565b909a90995060208901359860408101359850606081013597506080013595509350505050565b634e487b7160e01b600052601160045260246000fd5b808201808211156117ba576117ba6126f1565b818103818111156117ba576117ba6126f1565b6001600160801b03818116838216019080821115611c9357611c936126f1565b60006040828403121561275f57600080fd5b604051604081018181106001600160401b038211171561278157612781612400565b60405261278d8361236c565b815261279b6020840161236c565b60208201529392505050565b634e487b7160e01b600052603260045260246000fd5b6000600182016127cf576127cf6126f1565b5060010190565b81835260006001600160fb1b038311156127ef57600080fd5b8260051b80836020870137939093016020019392505050565b6001600160a01b03848116825260406020808401829052838201859052600092606091828601600588811b880185018a885b8b8110156128ec578a8303605f190185528135368e9003607e1901811261286057600080fd5b8d0160808861286e8361236c565b16855287820135888601528a8201358b86015289820135601e1983360301811261289757600080fd5b9091018781019190356001600160401b038111156128b457600080fd5b80871b36038313156128c557600080fd5b818b8701526128d782870182856127d6565b9789019795505050918601915060010161283a565b50909c9b505050505050505050505050565b600081518084526020808501945080840160005b838110156129375781516001600160a01b031687529582019590820190600101612912565b509495945050505050565b60006101208083526129568184018d6128fe565b9050828103602084015261296a818c6128fe565b9050828103604084015261297e818b6128fe565b90508281036060840152612992818a6128fe565b6080840198909852505060a081019490945260c084019290925260e083015261010090910152949350505050565b60008235603e198336030181126129d657600080fd5b9190910192915050565b6000808335601e198436030181126129f757600080fd5b8301803591506001600160401b03821115612a1157600080fd5b60200191503681900382131561264857600080fd5b8183823760009101908152919050565b600060208284031215612a4857600080fd5b5051919050565b600060033d1115610bd25760046000803e5060005160e01c90565b600060443d1015612a785790565b6040516003193d81016004833e81513d6001600160401b038160248401118184111715612aa757505050505090565b8285019150815181811115612abf5750505050505090565b843d8701016020828501011115612ad95750505050505090565b612ae860208286010187612416565b509095945050505050565b805169ffffffffffffffffffff8116811461238357600080fd5b600080600080600060a08688031215612b2557600080fd5b612b2e86612af3565b9450602086015193506040860151925060608601519150612b5160808701612af3565b90509295509295909350565b600082516129d6818460208701612571565b634e487b7160e01b600052603160045260246000fdfe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca26469706673582212204c9ed3a6495e59b7bdc8ea52235c49efbe1fedd7ee61df8ac7f4852fcaf6fdfd64736f6c63430008140033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000000000000016e6cb3038203c1129c8b4aee7af7a11
-----Decoded View---------------
Arg [0] : afEth (address): 0x0000000016E6Cb3038203c1129c8B4aEE7af7a11
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000016e6cb3038203c1129c8b4aee7af7a11
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
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.