Source Code
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 16 internal transactions
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 7821434 | 542 days ago | Contract Creation | 0 FRAX | |||
| 4233959 | 625 days ago | Contract Creation | 0 FRAX | |||
| 4233959 | 625 days ago | Contract Creation | 0 FRAX | |||
| 4233959 | 625 days ago | Contract Creation | 0 FRAX | |||
| 4233959 | 625 days ago | Contract Creation | 0 FRAX | |||
| 4233959 | 625 days ago | Contract Creation | 0 FRAX | |||
| 4233959 | 625 days ago | Contract Creation | 0 FRAX | |||
| 4190097 | 626 days ago | Contract Creation | 0 FRAX | |||
| 4190097 | 626 days ago | Contract Creation | 0 FRAX | |||
| 4190097 | 626 days ago | Contract Creation | 0 FRAX | |||
| 4190097 | 626 days ago | Contract Creation | 0 FRAX | |||
| 4190097 | 626 days ago | Contract Creation | 0 FRAX | |||
| 4190097 | 626 days ago | Contract Creation | 0 FRAX | |||
| 1473619 | 689 days ago | Contract Creation | 0 FRAX | |||
| 1473619 | 689 days ago | Contract Creation | 0 FRAX | |||
| 1473619 | 689 days ago | Contract Creation | 0 FRAX |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
SlippageAuctionFactory
Compiler Version
v0.8.24+commit.e11b9ed9
Optimization Enabled:
Yes with 100000 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: ISC
pragma solidity ^0.8.23;
// ====================================================================
// | ______ _______ |
// | / _____________ __ __ / ____(_____ ____ _____ ________ |
// | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ |
// | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ |
// | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ |
// | |
// ====================================================================
// ====================== SlippageAuctionFactory ======================
// ====================================================================
// Factory contract for SlippageAuctions
// Frax Finance: https://github.com/FraxFinance
import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import { SlippageAuction } from "./SlippageAuction.sol";
/// @title SlippageAuctionFactory
/// @notice Permission-less factory to create SlippageAuction.sol contracts.
/// @dev https://github.com/FraxFinance/frax-bonds
contract SlippageAuctionFactory {
/// @notice The auctions addresses created by this factory
address[] public auctions;
/// @notice Mapping of auction addresses to whether or not the auction has been created
mapping(address auction => bool exists) public isAuction;
/// @notice Creates a new auction contract
/// @dev Tokens must be 18 decimals
/// @param _timelock Timelock role for auction
/// @param _tokenBuy Token used to purchase `_tokenSell`
/// @param _tokenSell Token sold in the auction
/// @return auction The address of the new SlippageAuction that was created
function createAuctionContract(
address _timelock,
address _tokenBuy,
address _tokenSell
) external returns (address auction) {
// Reject if both tokens are not 18 decimals
if (IERC20Metadata(_tokenBuy).decimals() != 18) {
revert TokenBuyMustBe18Decimals();
}
if (IERC20Metadata(_tokenSell).decimals() != 18) {
revert TokenSellMustBe18Decimals();
}
// Deploy the auction
auction = address(new SlippageAuction({ _timelock: _timelock, _tokenBuy: _tokenBuy, _tokenSell: _tokenSell }));
// Add auction address to mapping
isAuction[auction] = true;
// Add to auctions array
auctions.push(auction);
emit AuctionCreated({ auction: auction, tokenBuy: _tokenBuy, tokenSell: _tokenSell });
}
/// @notice Returns a list of all auction addresses deployed
/// @return memory address[] The list of auction addresses
function getAuctions() external view returns (address[] memory) {
return auctions;
}
/// @notice Get an auction address by index to save on-chain gas usage from returning the whole auctions array
/// @dev Reverts if attempting to return an index greater than the auctions array length
/// @param _index Index of auction address to request from the auctions array
/// @return auction Address of the specified auction
function getAuction(uint256 _index) external view returns (address auction) {
// Revert if non-existent
if (_index > auctions.length) revert AuctionDoesNotExist();
// Fetch the auction address by its index
auction = auctions[_index];
}
/// @notice Returns the number of auctions deployed
/// @return uint256 length of the auctions array
function auctionsLength() external view returns (uint256) {
return auctions.length;
}
/// @notice Emitted when a new auction is created
/// @param auction The address of the new auction contract
/// @param tokenBuy Token to purchase `tokenSell`
/// @param tokenSell Token sold in the auction
event AuctionCreated(address indexed auction, address indexed tokenBuy, address indexed tokenSell);
/// @notice Thrown when an auction with the same sender and tokens has already been created
error AuctionAlreadyExists();
/// @notice Thrown when attempting to call `getAuction()` with an index greater than auctions.length
error AuctionDoesNotExist();
/// @notice Thrown when the sell token is not 18 decimals
error TokenSellMustBe18Decimals();
/// @notice Thrown when the buy token is not 18 decimals
error TokenBuyMustBe18Decimals();
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
import {IERC20Metadata} from "./extensions/IERC20Metadata.sol";
import {Context} from "../../utils/Context.sol";
import {IERC20Errors} from "../../interfaces/draft-IERC6093.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
*
* TIP: For a detailed writeup see our guide
* https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* The default value of {decimals} is 18. To change this, you should override
* this function so it returns a different value.
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC20
* applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*/
abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
mapping(address account => uint256) private _balances;
mapping(address account => mapping(address spender => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* All two of these values are immutable: they can only be set once during
* construction.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the default value returned by this function, unless
* it's overridden.
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual returns (uint8) {
return 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `value`.
*/
function transfer(address to, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_transfer(owner, to, value);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `value` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, value);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `value`.
* - the caller must have allowance for ``from``'s tokens of at least
* `value`.
*/
function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, value);
_transfer(from, to, value);
return true;
}
/**
* @dev Moves a `value` amount of tokens from `from` to `to`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _transfer(address from, address to, uint256 value) internal {
if (from == address(0)) {
revert ERC20InvalidSender(address(0));
}
if (to == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(from, to, value);
}
/**
* @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
* (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
* this function.
*
* Emits a {Transfer} event.
*/
function _update(address from, address to, uint256 value) internal virtual {
if (from == address(0)) {
// Overflow check required: The rest of the code assumes that totalSupply never overflows
_totalSupply += value;
} else {
uint256 fromBalance = _balances[from];
if (fromBalance < value) {
revert ERC20InsufficientBalance(from, fromBalance, value);
}
unchecked {
// Overflow not possible: value <= fromBalance <= totalSupply.
_balances[from] = fromBalance - value;
}
}
if (to == address(0)) {
unchecked {
// Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
_totalSupply -= value;
}
} else {
unchecked {
// Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
_balances[to] += value;
}
}
emit Transfer(from, to, value);
}
/**
* @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).
* Relies on the `_update` mechanism
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _mint(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(address(0), account, value);
}
/**
* @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.
* Relies on the `_update` mechanism.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead
*/
function _burn(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidSender(address(0));
}
_update(account, address(0), value);
}
/**
* @dev Sets `value` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*
* Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
*/
function _approve(address owner, address spender, uint256 value) internal {
_approve(owner, spender, value, true);
}
/**
* @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.
*
* By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by
* `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any
* `Approval` event during `transferFrom` operations.
*
* Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to
* true using the following override:
* ```
* function _approve(address owner, address spender, uint256 value, bool) internal virtual override {
* super._approve(owner, spender, value, true);
* }
* ```
*
* Requirements are the same as {_approve}.
*/
function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
if (owner == address(0)) {
revert ERC20InvalidApprover(address(0));
}
if (spender == address(0)) {
revert ERC20InvalidSpender(address(0));
}
_allowances[owner][spender] = value;
if (emitEvent) {
emit Approval(owner, spender, value);
}
}
/**
* @dev Updates `owner` s allowance for `spender` based on spent `value`.
*
* Does not update the allowance value in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Does not emit an {Approval} event.
*/
function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
if (currentAllowance < value) {
revert ERC20InsufficientAllowance(spender, currentAllowance, value);
}
unchecked {
_approve(owner, spender, currentAllowance - value, false);
}
}
}
}// SPDX-License-Identifier: ISC
pragma solidity ^0.8.23;
// ====================================================================
// | ______ _______ |
// | / _____________ __ __ / ____(_____ ____ _____ ________ |
// | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ |
// | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ |
// | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ |
// | |
// ====================================================================
// ========================= SlippageAuction ==========================
// ====================================================================
// Dutch-style Auction. Starts at a high price and gradually decreases until the entire lot
// of tokens is sold, or the time expires.
// Frax Finance: https://github.com/FraxFinance
import { ReentrancyGuard } from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import { IERC20, IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { Timelock2Step } from "frax-std/access-control/v2/Timelock2Step.sol";
import { IUniswapV2Callee } from "./interfaces/IUniswapV2Callee.sol";
/// @title SlippageAuction
/// @notice Slippage auction to sell tokens over time. Created via factory.
/// @dev Both tokens must be 18 decimals.
/// @dev https://github.com/FraxFinance/frax-bonds
contract SlippageAuction is ReentrancyGuard, Timelock2Step {
using SafeERC20 for IERC20;
// ==============================================================================
// Storage
// ==============================================================================
/// @notice The name of this auction
string public name;
/// @notice Slippage precision
uint256 public constant PRECISION = 1e18;
/// @notice Stored information about details
Detail[] public details;
/// @notice The token used for buying the tokenSell
address public immutable TOKEN_BUY;
/// @notice The token being auctioned off
address public immutable TOKEN_SELL;
/// @notice Alias for TOKEN_BUY
/// @dev Maintains UniswapV2 interface
address public immutable token0;
/// @notice Alias for TOKEN_SELL
/// @notice Maintains UniswapV2 interface
address public immutable token1;
// ==============================================================================
// Structs
// ==============================================================================
/// @notice Detail information behind an auction
/// @notice Auction information
/// @param amountListed Amount of sellToken placed for auction
/// @param amountLeft Amount of sellToken remaining to buy
/// @param amountExcessBuy Amount of any additional TOKEN_BUY sent to contract during auction
/// @param amountExcessSell Amount of any additional TOKEN_SELL sent to contract during auction
/// @param tokenBuyReceived Amount of tokenBuy that came in from sales
/// @param priceLast Price of the last sale, in tokenBuy amount per tokenSell (amount of tokenBuy to purchase 1e18 tokenSell)
/// @param priceMin Minimum price of 1e18 tokenSell, in tokenBuy
/// @param priceDecay Price decay, (wei per second), using PRECISION
/// @param priceSlippage Slippage fraction. E.g (0.01 * PRECISION) = 1%
/// @param lastBuyTime Time of the last sale
/// @param expiry UNIX timestamp when the auction ends
/// @param active If the auction is active
struct Detail {
uint128 amountListed;
uint128 amountLeft;
uint128 amountExcessBuy;
uint128 amountExcessSell;
uint128 tokenBuyReceived;
uint128 priceLast;
uint128 priceMin;
uint64 priceDecay;
uint64 priceSlippage;
uint32 lastBuyTime;
uint32 expiry;
bool active;
}
// ==============================================================================
// Constructor
// ==============================================================================
/// @param _timelock Address of the timelock/owner
/// @param _tokenBuy Token used to purchase _tokenSell
/// @param _tokenSell Token sold in the auction
constructor(address _timelock, address _tokenBuy, address _tokenSell) Timelock2Step(_timelock) {
name = string(abi.encodePacked("SlippageAuction: ", IERC20Metadata(_tokenSell).symbol()));
TOKEN_BUY = _tokenBuy;
TOKEN_SELL = _tokenSell;
token0 = _tokenBuy;
token1 = _tokenSell;
}
// ==============================================================================
// Views
// ==============================================================================
/// @notice Returns the semantic version of this contract
/// @return _major The major version
/// @return _minor The minor version
/// @return _patch The patch version
function version() external pure returns (uint256 _major, uint256 _minor, uint256 _patch) {
return (1, 0, 1);
}
/// @notice Calculates the pre-slippage price (with the user supplied auction _detail) from the time decay alone
/// @param _detail The auction struct
/// @return _price The price
function getPreSlippagePrice(Detail memory _detail) public view returns (uint256 _price) {
// Calculate Decay
uint256 _decay = (_detail.priceDecay * (block.timestamp - _detail.lastBuyTime));
// Calculate the sale price (in tokenBuy per tokenSell), factoring in the time decay
if (_detail.priceLast < _decay) {
return _price = _detail.priceMin;
} else {
_price = _detail.priceLast - _decay;
}
// Never go below the minimum price
if (_price < _detail.priceMin) _price = _detail.priceMin;
}
/// @notice Calculates the pre-slippage price (with the current auction) from the time decay alone
function getPreSlippagePrice() external view returns (uint256) {
return getPreSlippagePrice(details[details.length - 1]);
}
/// @notice Calculates the amount of tokenSells out for a given tokenBuy amount
/// @param amountIn Amount of tokenBuy in
/// @param _revertOnOverAmountLeft Whether to revert if amountOut > amountLeft
/// @return amountOut Amount of tokenSell out
/// @return _slippagePerTokenSell The slippage component of the price change (in tokenBuy per tokenSell)
/// @return _postPriceSlippage The post-slippage price from the time decay + slippage
function getAmountOut(
uint256 amountIn,
bool _revertOnOverAmountLeft
) public view returns (uint256 amountOut, uint256 _slippagePerTokenSell, uint256 _postPriceSlippage) {
// Get the auction number
uint256 _auctionNumber = details.length - 1;
// Get the auction info
Detail memory _detail = details[_auctionNumber];
// Revert if the auction is inactive or expired
if (!_detail.active) revert AuctionNotActive();
if (block.timestamp >= _detail.expiry) revert AuctionExpired();
// Calculate the sale price (in tokenBuy per tokenSell), factoring in the time decay
uint256 _preSlippagePrice = getPreSlippagePrice({ _detail: _detail });
// Calculate the slippage component of the price (in tokenBuy per tokenSell)
_slippagePerTokenSell = (_detail.priceSlippage * amountIn) / PRECISION;
// Calculate the output amount of tokenSell
amountOut = (amountIn * PRECISION) / (_preSlippagePrice + _slippagePerTokenSell);
// Make sure you are not going over the amountLeft
if (amountOut > _detail.amountLeft) {
if (_revertOnOverAmountLeft) revert InsufficientTokenSellsAvailable();
else amountOut = _detail.amountLeft;
}
// Set return value
_postPriceSlippage = _preSlippagePrice + (2 * _slippagePerTokenSell); // Price impact is twice the slippage
}
/// @notice Calculates how much tokenBuy you would need to buy out the remaining tokenSell in the auction
/// @return amountIn Amount of tokenBuy needed
/// @return _slippagePerTokenSell The slippage component of the price change (in tokenBuy per tokenSell)
/// @return _postPriceSlippage The post-slippage price from the time decay + slippage
function getAmountInMax()
external
view
returns (uint256 amountIn, uint256 _slippagePerTokenSell, uint256 _postPriceSlippage)
{
// Get the auction number
uint256 _auctionNumber = details.length - 1;
// Get the auction info
Detail memory detail = details[_auctionNumber];
// Call the internal function with amountLeft
return _getAmountIn({ _detail: detail, amountOut: detail.amountLeft });
}
/// @notice Calculates how much tokenBuy you would need in order to obtain a given number of tokenSell
/// @param amountOut The desired amount of tokenSell
/// @return amountIn Amount of tokenBuy needed
/// @return _slippagePerTokenSell The slippage component of the price change (in tokenBuy per tokenSell)
/// @return _postPriceSlippage The post-slippage price from the time decay + slippage
function getAmountIn(
uint256 amountOut
) public view returns (uint256 amountIn, uint256 _slippagePerTokenSell, uint256 _postPriceSlippage) {
// Get the auction number
uint256 _auctionNumber = details.length - 1;
// Get the auction info
Detail memory detail = details[_auctionNumber];
// Call the internal function with amountOut, set return values
(amountIn, _slippagePerTokenSell, _postPriceSlippage) = _getAmountIn({ _detail: detail, amountOut: amountOut });
}
/// @notice Calculate how much tokenBuy you would need to obtain a given number of tokenSell
/// @param _detail The auction struct
/// @return amountIn Amount of tokenBuy needed
/// @return _slippagePerTokenSell The slippage component of the price change (in tokenBuy per tokenSell)
/// @return _postPriceSlippage The post-slippage price from the time decay + slippage
function _getAmountIn(
Detail memory _detail,
uint256 amountOut
) internal view returns (uint256 amountIn, uint256 _slippagePerTokenSell, uint256 _postPriceSlippage) {
// Do checks
if (!_detail.active) revert AuctionNotActive();
if (block.timestamp >= _detail.expiry) revert AuctionExpired();
if (amountOut > _detail.amountLeft) revert InsufficientTokenSellsAvailable();
// Calculate the sale price (in tokenBuy per tokenSell), factoring in the time decay
uint256 _preSlippagePrice = getPreSlippagePrice({ _detail: _detail });
// Math in a more readable format:
// uint256 _numerator = (amountOut * _preSlippagePrice) / PRECISION;
// uint256 _denominator = (PRECISION -
// ((amountOut * uint256(_detail.priceSlippage)) / PRECISION));
// amountIn = (_numerator * PRECISION) / _denominator;
// Set return params amountIn
amountIn =
(amountOut * _preSlippagePrice) /
(PRECISION - (amountOut * uint256(_detail.priceSlippage)) / PRECISION);
// Set return params, calculate the slippage component of the price (in tokenBuy per tokenSell)
_slippagePerTokenSell = (_detail.priceSlippage * amountIn) / PRECISION;
_postPriceSlippage = _preSlippagePrice + (2 * _slippagePerTokenSell); // Price impact is twice the slippage
}
/// @notice Calculates how much tokenBuy you would need in order to obtain a given number of tokenSell
/// @dev Maintains compatibility with some router implementations
/// @param amountOut The amount out of sell tokens
/// @param tokenOut The sell token address
/// @return amountIn The amount of tokenBuy needed
function getAmountIn(uint256 amountOut, address tokenOut) public view returns (uint256 amountIn) {
if (tokenOut != TOKEN_SELL) revert InvalidTokenOut();
(amountIn, , ) = getAmountIn({ amountOut: amountOut });
}
/// @notice Calculates the amount of tokenSell out for a given tokenBuy amount
/// @dev Used to maintain compatibility
/// @param amountIn Amount of tokenBuy in
/// @param tokenIn The token being swapped in
/// @return amountOut Amount of tokenSells out
function getAmountOut(uint256 amountIn, address tokenIn) public view returns (uint256 amountOut) {
if (tokenIn != TOKEN_BUY) revert InvalidTokenIn();
(amountOut, , ) = getAmountOut({ amountIn: amountIn, _revertOnOverAmountLeft: false });
}
/// @dev Uni v2 support without revert
function skim(address) external pure {
return;
}
/// @dev Uni v2 support without revert
function sync() external pure {
return;
}
function getAmountOut(uint256, uint256, uint256) external pure returns (uint256) {
revert NotImplemented();
}
function getAmountIn(uint256, uint256, uint256) external pure returns (uint256) {
revert NotImplemented();
}
function getReserves() external pure returns (uint112, uint112, uint32) {
revert NotImplemented();
}
function price0CumulativeLast() external pure returns (uint256) {
revert NotImplemented();
}
function price1CumulativeLast() external pure returns (uint256) {
revert NotImplemented();
}
function kLast() external pure returns (uint256) {
revert NotImplemented();
}
function factory() external pure returns (address) {
revert NotImplemented();
}
function MINIMUM_LIQUIDITY() external pure returns (uint256) {
revert NotImplemented();
}
function initialize(address, address) external pure {
revert NotImplemented();
}
/// @notice Gets a struct instead of a tuple for details()
/// @param _auctionNumber Detail ID
/// @return The struct of the auction
function getDetailStruct(uint256 _auctionNumber) external view returns (Detail memory) {
return details[_auctionNumber];
}
/// @notice Returns the length of the details array
/// @return _length The length of the details array
function detailsLength() external view returns (uint256 _length) {
_length = details.length;
}
/// @notice Returns the latest auction
/// @dev Returns an empty struct if there are no auctions
/// @return _latestAuction The latest auction struct
function getLatestAuction() external view returns (Detail memory _latestAuction) {
uint256 _length = details.length;
if (_length == 0) return _latestAuction;
_latestAuction = details[details.length - 1];
}
// ==============================================================================
// Owner-only Functions
// ==============================================================================
/// @notice Parameters for starting an auction
/// @dev Sender must have an allowance on tokenSell
/// @param amountListed Amount of tokenSell being sold
/// @param priceStart Starting price of 1e18 tokenSell, in tokenBuy
/// @param priceMin Minimum price of 1e18 tokenSell, in tokenBuy
/// @param priceDecay Price decay, (wei per second), using PRECISION
/// @param priceSlippage Slippage fraction. E.g (0.01 * PRECISION) = 1%
/// @param expiry UNIX timestamp when the auction ends
struct StartAuctionParams {
uint128 amountListed;
uint128 priceStart;
uint128 priceMin;
uint64 priceDecay;
uint64 priceSlippage;
uint32 expiry;
}
/// @notice Starts a new auction
/// @dev Requires an ERC20 allowance on the tokenSell prior to calling
/// @param _params StartAuctionParams
function startAuction(StartAuctionParams calldata _params) external nonReentrant returns (uint256 _auctionNumber) {
_requireSenderIsTimelock();
// Check expiry is not in the past
if (_params.expiry < block.timestamp) revert Expired();
// Ensure that enough amountListed are for sale to prevent round-down errors
// see E2E test for 1e6 requirement. At 1e8 requirement, there should be enough trades
// to constitute an auction.
if (_params.amountListed < 1e8) revert AmountListedTooLow();
// Ensure that priceStart > priceMin
if (_params.priceStart < _params.priceMin) revert PriceStartLessThanPriceMin();
// Prevent edge-case revert of amountOut within getAmountOut
if (_params.priceMin == 0 && _params.priceSlippage == 0) revert PriceMinAndSlippageBothZero();
// Pre-compute the auction number
_auctionNumber = details.length;
// Ensure that the previous auction, if any, has been stopped
if (_auctionNumber > 0) {
Detail memory _lastAuction = details[_auctionNumber - 1];
if (_lastAuction.active) revert LastAuctionStillActive();
}
// Create the auction
details.push(
Detail({
amountListed: _params.amountListed,
amountLeft: _params.amountListed,
amountExcessBuy: 0,
amountExcessSell: 0,
tokenBuyReceived: 0,
priceLast: _params.priceStart,
priceMin: _params.priceMin,
priceDecay: _params.priceDecay,
priceSlippage: _params.priceSlippage,
lastBuyTime: uint32(block.timestamp),
expiry: _params.expiry,
active: true
})
);
emit AuctionStarted({
auctionNumber: _auctionNumber,
amountListed: _params.amountListed,
priceStart: _params.priceStart,
priceMin: _params.priceMin,
priceDecay: _params.priceDecay,
priceSlippage: _params.priceSlippage,
expiry: _params.expiry
});
// Clear out any tokens held by the auction so that bookkeeping is accurate
_withdrawAnyAvailableTokens({ _excess: true });
// Take the tokenSells from the sender
IERC20(TOKEN_SELL).safeTransferFrom(msg.sender, address(this), _params.amountListed);
}
/// @notice Ends the auction
/// @dev Only callable by the auction owner
/// @return tokenBuyReceived Amount of tokenBuy obtained from the auction
/// @return tokenSellRemaining Amount of unsold tokenSell left over
function stopAuction() public nonReentrant returns (uint256 tokenBuyReceived, uint256 tokenSellRemaining) {
_requireSenderIsTimelock();
// Get the auction info and perform checks
uint256 _auctionNumber = details.length - 1;
Detail storage detail = details[_auctionNumber];
if (!detail.active) revert AuctionNotActive();
// Skim excess token to sender if additional has been received to keep bookkeeping accurate
_withdrawIfTokenBalance({ _token: TOKEN_BUY, _priorBalance: detail.tokenBuyReceived, _excess: true });
_withdrawIfTokenBalance({ _token: TOKEN_SELL, _priorBalance: detail.amountLeft, _excess: true });
// Set Return params
tokenBuyReceived = IERC20(TOKEN_BUY).balanceOf(address(this));
tokenSellRemaining = IERC20(TOKEN_SELL).balanceOf(address(this));
// Effects: Update state with final balances;
detail.active = false;
detail.tokenBuyReceived = uint128(tokenBuyReceived);
detail.amountLeft = uint128(tokenSellRemaining);
// Return any TOKEN_BUY and TOKEN_SELL from the auction to the timelock
_withdrawAnyAvailableTokens({ _excess: false });
emit AuctionStopped({
auctionNumber: _auctionNumber,
tokenBuyReceived: tokenBuyReceived,
tokenSellRemaining: tokenSellRemaining
});
}
// ==============================================================================
// Public Functions
// ==============================================================================
/// @notice Swaps tokenBuys for tokenSells
/// @dev This low-level function should be called from a contract which performs important safety checks
/// @dev Token0 is always the TOKEN_BUY, token1 is always the TOKEN_SELL
/// @dev Maintains uniV2 interface
/// @param amount0Out The amount of tokenBuys to receive
/// @param amount1Out The amount of tokenSells to receive
/// @param to The recipient of the output tokens
/// @param data Callback data
function swap(uint256 amount0Out, uint256 amount1Out, address to, bytes memory data) public nonReentrant {
if (amount0Out != 0) revert ExcessiveTokenBuyOut({ minOut: 0, actualOut: amount0Out });
if (amount1Out == 0) revert InsufficientOutputAmount({ minOut: 1, actualOut: 0 });
// Get the auction info (similar to get reserves in univ2)
uint256 _auctionNumber = details.length - 1;
Detail memory detail = details[_auctionNumber];
// Transfer tokens
IERC20(TOKEN_SELL).safeTransfer(to, amount1Out);
// Callback if necessary for flash swap
if (data.length > 0) {
IUniswapV2Callee(to).uniswapV2Call({
sender: msg.sender,
amount0: amount0Out,
amount1: amount1Out,
data: data
});
}
// Calculate the amount of tokenBuys in
uint256 _tokenBuyBalance = IERC20(TOKEN_BUY).balanceOf(address(this));
uint256 _tokenBuyIn = _tokenBuyBalance - detail.tokenBuyReceived;
// Adheres to uniswap v2 interface, called here to prevent stack-too-deep error
emit Swap({
sender: msg.sender,
amount0In: _tokenBuyIn,
amount1In: 0,
amount0Out: 0,
amount1Out: amount1Out,
to: to
});
// Call the internal function with amountOut
(uint256 _minAmountIn, uint256 _slippagePerTokenSell, uint256 _postPriceSlippage) = _getAmountIn({
_detail: detail,
amountOut: amount1Out
});
// Check invariants
if (_tokenBuyIn < _minAmountIn) revert InsufficientInputAmount({ minIn: _minAmountIn, actualIn: _tokenBuyIn });
if (_minAmountIn == 0) revert InputAmountZero();
// Mutate _auction, which has the previous state
detail.amountLeft -= safeUint128(amount1Out);
detail.tokenBuyReceived = safeUint128(_tokenBuyBalance);
detail.priceLast = safeUint128(_postPriceSlippage);
detail.lastBuyTime = uint32(block.timestamp);
// Write back to state, similar to _update in univ2
details[_auctionNumber] = detail;
// Emit Buy event
emit Buy({
auctionNumber: _auctionNumber,
tokenBuy: TOKEN_BUY,
tokenSell: TOKEN_SELL,
amountIn: safeUint128(_tokenBuyIn),
amountOut: safeUint128(amount1Out),
priceLast: detail.priceLast,
slippagePerTokenSell: safeUint128(_slippagePerTokenSell)
});
}
/// @notice Swaps an exact amount of input tokens for as many output tokens as possible
/// @dev Must have an allowance on the TOKEN_BUY prior to invocation
/// @dev Maintains uniV2 interface
/// @param amountIn The amount of buy tokens to send.
/// @param amountOutMin The minimum amount of sell tokens that must be received for the transaction not to revert
/// @param to Recipient of the output tokens
/// @param deadline Unix timestamp after which the transaction will revert
/// @return _amounts The input token amount and output token amount
function swapExactTokensForTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] memory path,
address to,
uint256 deadline
) external returns (uint256[] memory _amounts) {
path; // compile warnings
// Ensure deadline has not passed
if (block.timestamp > deadline) revert Expired();
// Calculate the amount of tokenSells out & check invariant
(uint256 amountOut, , ) = getAmountOut({ amountIn: amountIn, _revertOnOverAmountLeft: true });
if (amountOut < amountOutMin) {
revert InsufficientOutputAmount({ minOut: amountOutMin, actualOut: amountOut });
}
// Interactions: Transfer tokenBuys to the contract
IERC20(TOKEN_BUY).safeTransferFrom(msg.sender, address(this), amountIn);
// Call the swap function
swap({ amount0Out: 0, amount1Out: amountOut, to: to, data: new bytes(0) });
// Set return values
_amounts = new uint256[](2);
_amounts[0] = amountIn;
_amounts[1] = amountOut;
}
/// @notice Receives an exact amount of output tokens for as few input tokens as possible
/// @dev Must have an allowance on the TOKEN_BUY prior to invocation
/// @dev Maintains uniV2 interface
/// @param amountOut The amount of sell tokens to receive
/// @param amountInMax The maximum amount of buy tokens that can be required before the transaction reverts
/// @param to Recipient of the output tokens
/// @param deadline Unix timestamp after which the transaction will revert
/// @return _amounts The input token amount and output token amount
function swapTokensForExactTokens(
uint256 amountOut,
uint256 amountInMax,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory _amounts) {
path; // compile warning
// Ensure deadline has not passed
if (block.timestamp > deadline) revert Expired();
// Calculate the amount of tokenBuys in & check invariant
(uint256 amountIn, , ) = getAmountIn({ amountOut: amountOut });
if (amountIn > amountInMax) revert ExcessiveInputAmount({ minIn: amountInMax, actualIn: amountIn });
// Interactions: Transfer tokenBuys to the contract
IERC20(TOKEN_BUY).safeTransferFrom(msg.sender, address(this), amountIn);
// Call the swap function
swap({ amount0Out: 0, amount1Out: amountOut, to: to, data: new bytes(0) });
// Set return variable
_amounts = new uint256[](2);
_amounts[0] = amountIn;
_amounts[1] = amountOut;
}
// ==============================================================================
// Helpers
// ==============================================================================
/// @notice Withdraw available TOKEN_BUY and TOKEN_SELL on startAuction() and stopAuction()
/// @param _excess Whether to bookkeep any excess tokens received outside of auction
function _withdrawAnyAvailableTokens(bool _excess) private {
_withdrawIfTokenBalance({ _token: TOKEN_BUY, _priorBalance: 0, _excess: _excess });
_withdrawIfTokenBalance({ _token: TOKEN_SELL, _priorBalance: 0, _excess: _excess });
}
/// @notice Withdraw available TOKEN_BUY and TOKEN_SELL on startAuction() and stopAuction()
/// @param _token Address of the token you want to withdraw
/// @param _priorBalance Prior balance of the _token
/// @param _excess Whether to bookkeep any excess tokens received outside of auction
function _withdrawIfTokenBalance(address _token, uint256 _priorBalance, bool _excess) private {
// Fetch the current balance of _token
uint256 balance = IERC20(_token).balanceOf(address(this));
// If the current balance is higher than the prior balance
if (balance > _priorBalance) {
uint256 amount = balance - _priorBalance;
// Bookkeep any excess token received
if (_excess) {
Detail storage detail = details[details.length - 1];
if (_token == TOKEN_BUY) {
detail.amountExcessBuy += safeUint128(amount);
} else {
// token == TOKEN_SELL
detail.amountExcessSell += safeUint128(amount);
}
}
IERC20(_token).safeTransfer(msg.sender, amount);
}
}
/// @dev Overflow protection
function safeUint128(uint256 number) internal pure returns (uint128 casted) {
if (number > type(uint128).max) revert Overflow();
casted = uint128(number);
}
// ==============================================================================
// Errors
// ==============================================================================
/// @notice Emitted when a user attempts to start an auction selling too few tokens
error AmountListedTooLow();
/// @notice Emitted when a user attempts to end an auction that has been stopped
error AuctionNotActive();
/// @notice Emitted when a user attempts to interact with an auction that has expired
error AuctionExpired();
/// @notice Emitted when a user attempts to start a new auction before the previous one has been stopped (via ```stopAuction()```)
error LastAuctionStillActive();
/// @notice Emitted when a user attempts to swap a given amount of buy tokens that would result in an insufficient amount of sell tokens
/// @param minOut Minimum out that the user expects
/// @param actualOut Actual amount out that would occur
error InsufficientOutputAmount(uint256 minOut, uint256 actualOut);
/// @notice Emitted when a user attempts to swap an insufficient amount of buy tokens
/// @param minIn Minimum in that the contract requires
/// @param actualIn Actual amount in that has been deposited
error InsufficientInputAmount(uint256 minIn, uint256 actualIn);
/// @notice Emitted when a user attempts to swap an excessive amount of buy tokens for aa given amount of sell tokens
/// @param minIn Minimum in that the user expects
/// @param actualIn Actual amount in that would occur
error ExcessiveInputAmount(uint256 minIn, uint256 actualIn);
/// @notice Emitted when a user attempts to buy more sell tokens than are left in the auction
error InsufficientTokenSellsAvailable();
/// @notice Emitted when attempting to swap where the calculated amountIn is 0
error InputAmountZero();
/// @notice Emitted when a user attempts to buy the tokenBuy using the swap() function
error ExcessiveTokenBuyOut(uint256 minOut, uint256 actualOut);
/// @notice Emitted when a user attempts to make a swap after the transaction deadline has passed
error Expired();
/// @notice Emitted when a user attempts to use an invalid buy token
error InvalidTokenIn();
/// @notice Emitted when a user attempts to use an invalid sell token
error InvalidTokenOut();
/// @notice Emitted when calling `startAuction()` when `StartAuctionParams.priceMin == 0 && StartAuctionParams.priceSlippage == 0`
error PriceMinAndSlippageBothZero();
/// @notice Emitted when attempting to call a uni-v2 pair function that is not supported by this contract
error NotImplemented();
/// @notice Emitted when downcasting a uint on type overflow
error Overflow();
/// @notice Emitted when a user attempts to start an auction with `_params.priceStart < _params.priceMin`
error PriceStartLessThanPriceMin();
// ==============================================================================
// Events
// ==============================================================================
/// @dev Emitted when an auction is stopped
/// @param auctionNumber The ID of the auction
/// @param tokenBuyReceived Amount of tokenBuy obtained from the auction
/// @param tokenSellRemaining Amount of unsold tokenSells left over
event AuctionStopped(uint256 auctionNumber, uint256 tokenBuyReceived, uint256 tokenSellRemaining);
/// @dev Emitted when a swap occurs and has more information than the ```Swap``` event
/// @param auctionNumber The ID of the auction, and index in the details array
/// @param tokenBuy The token used to buy the tokenSell being auctioned off
/// @param tokenSell The token being auctioned off
/// @param amountIn Amount of tokenBuy in
/// @param amountOut Amount of tokenSell out
/// @param priceLast The execution price of the buy
/// @param slippagePerTokenSell How many tokenBuys (per tokenSell) were added as slippage
event Buy(
uint256 auctionNumber,
address tokenBuy,
address tokenSell,
uint128 amountIn,
uint128 amountOut,
uint128 priceLast,
uint128 slippagePerTokenSell
);
/// @notice Emitted when a swap occurs
/// @param sender The address of the sender
/// @param amount0In The amount of TOKEN_BUY in
/// @param amount1In The amount of TOKEN_SELL in
/// @param amount0Out The amount of TOKEN_BUY out
/// @param amount1Out The amount of TOKEN_SELL out
/// @param to The address of the recipient
event Swap(
address indexed sender,
uint256 amount0In,
uint256 amount1In,
uint256 amount0Out,
uint256 amount1Out,
address indexed to
);
/// @dev Emitted when an auction is started
/// @param auctionNumber The ID of the auction
/// @param amountListed Amount of tokenSell being sold
/// @param priceStart Starting price of the tokenSell, in tokenBuy
/// @param priceMin Minimum price of the tokenSell, in tokenBuy
/// @param priceDecay Price decay, per day, using PRECISION
/// @param priceSlippage Slippage fraction. E.g (0.01 * PRECISION) = 1%
/// @param expiry Expiration time of the auction
event AuctionStarted(
uint256 auctionNumber,
uint128 amountListed,
uint128 priceStart,
uint128 priceMin,
uint128 priceDecay,
uint128 priceSlippage,
uint32 expiry
);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard ERC20 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens.
*/
interface IERC20Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC20InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC20InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
* @param spender Address that may be allowed to operate on tokens without being their owner.
* @param allowance Amount of tokens a `spender` is allowed to operate with.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC20InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `spender` to be approved. Used in approvals.
* @param spender Address that may be allowed to operate on tokens without being their owner.
*/
error ERC20InvalidSpender(address spender);
}
/**
* @dev Standard ERC721 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens.
*/
interface IERC721Errors {
/**
* @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20.
* Used in balance queries.
* @param owner Address of the current owner of a token.
*/
error ERC721InvalidOwner(address owner);
/**
* @dev Indicates a `tokenId` whose `owner` is the zero address.
* @param tokenId Identifier number of a token.
*/
error ERC721NonexistentToken(uint256 tokenId);
/**
* @dev Indicates an error related to the ownership over a particular token. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param tokenId Identifier number of a token.
* @param owner Address of the current owner of a token.
*/
error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC721InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC721InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param tokenId Identifier number of a token.
*/
error ERC721InsufficientApproval(address operator, uint256 tokenId);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC721InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC721InvalidOperator(address operator);
}
/**
* @dev Standard ERC1155 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens.
*/
interface IERC1155Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
* @param tokenId Identifier number of a token.
*/
error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC1155InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC1155InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param owner Address of the current owner of a token.
*/
error ERC1155MissingApprovalForAll(address operator, address owner);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC1155InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC1155InvalidOperator(address operator);
/**
* @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
* Used in batch transfers.
* @param idsLength Length of the array of token identifiers
* @param valuesLength Length of the array of token amounts
*/
error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)
pragma solidity ^0.8.20;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
uint256 private _status;
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
constructor() {
_status = NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be NOT_ENTERED
if (_status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
_status = ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == ENTERED;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @dev An operation with an ERC20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data);
if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
}
}// SPDX-License-Identifier: ISC
pragma solidity >=0.8.0;
// ====================================================================
// | ______ _______ |
// | / _____________ __ __ / ____(_____ ____ _____ ________ |
// | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ |
// | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ |
// | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ |
// | |
// ====================================================================
// ========================== Timelock2Step ===========================
// ====================================================================
// Frax Finance: https://github.com/FraxFinance
// Primary Author
// Drake Evans: https://github.com/DrakeEvans
// Reviewers
// Dennis: https://github.com/denett
// ====================================================================
/// @title Timelock2Step
/// @author Drake Evans (Frax Finance) https://github.com/drakeevans
/// @dev Inspired by OpenZeppelin's Ownable2Step contract
/// @notice An abstract contract which contains 2-step transfer and renounce logic for a timelock address
abstract contract Timelock2Step {
/// @notice The pending timelock address
address public pendingTimelockAddress;
/// @notice The current timelock address
address public timelockAddress;
constructor(address _timelockAddress) {
timelockAddress = _timelockAddress;
}
// ============================================================================================
// Functions: External Functions
// ============================================================================================
/// @notice The ```transferTimelock``` function initiates the timelock transfer
/// @dev Must be called by the current timelock
/// @param _newTimelock The address of the nominated (pending) timelock
function transferTimelock(address _newTimelock) external virtual {
_requireSenderIsTimelock();
_transferTimelock(_newTimelock);
}
/// @notice The ```acceptTransferTimelock``` function completes the timelock transfer
/// @dev Must be called by the pending timelock
function acceptTransferTimelock() external virtual {
_requireSenderIsPendingTimelock();
_acceptTransferTimelock();
}
/// @notice The ```renounceTimelock``` function renounces the timelock after setting pending timelock to current timelock
/// @dev Pending timelock must be set to current timelock before renouncing, creating a 2-step renounce process
function renounceTimelock() external virtual {
_requireSenderIsTimelock();
_requireSenderIsPendingTimelock();
_transferTimelock(address(0));
_setTimelock(address(0));
}
// ============================================================================================
// Functions: Internal Actions
// ============================================================================================
/// @notice The ```_transferTimelock``` function initiates the timelock transfer
/// @dev This function is to be implemented by a public function
/// @param _newTimelock The address of the nominated (pending) timelock
function _transferTimelock(address _newTimelock) internal {
pendingTimelockAddress = _newTimelock;
emit TimelockTransferStarted(timelockAddress, _newTimelock);
}
/// @notice The ```_acceptTransferTimelock``` function completes the timelock transfer
/// @dev This function is to be implemented by a public function
function _acceptTransferTimelock() internal {
pendingTimelockAddress = address(0);
_setTimelock(msg.sender);
}
/// @notice The ```_setTimelock``` function sets the timelock address
/// @dev This function is to be implemented by a public function
/// @param _newTimelock The address of the new timelock
function _setTimelock(address _newTimelock) internal {
emit TimelockTransferred(timelockAddress, _newTimelock);
timelockAddress = _newTimelock;
}
// ============================================================================================
// Functions: Internal Checks
// ============================================================================================
/// @notice The ```_isTimelock``` function checks if _address is current timelock address
/// @param _address The address to check against the timelock
/// @return Whether or not msg.sender is current timelock address
function _isTimelock(address _address) internal view returns (bool) {
return _address == timelockAddress;
}
/// @notice The ```_requireIsTimelock``` function reverts if _address is not current timelock address
/// @param _address The address to check against the timelock
function _requireIsTimelock(address _address) internal view {
if (!_isTimelock(_address)) revert AddressIsNotTimelock(timelockAddress, _address);
}
/// @notice The ```_requireSenderIsTimelock``` function reverts if msg.sender is not current timelock address
/// @dev This function is to be implemented by a public function
function _requireSenderIsTimelock() internal view {
_requireIsTimelock(msg.sender);
}
/// @notice The ```_isPendingTimelock``` function checks if the _address is pending timelock address
/// @dev This function is to be implemented by a public function
/// @param _address The address to check against the pending timelock
/// @return Whether or not _address is pending timelock address
function _isPendingTimelock(address _address) internal view returns (bool) {
return _address == pendingTimelockAddress;
}
/// @notice The ```_requireIsPendingTimelock``` function reverts if the _address is not pending timelock address
/// @dev This function is to be implemented by a public function
/// @param _address The address to check against the pending timelock
function _requireIsPendingTimelock(address _address) internal view {
if (!_isPendingTimelock(_address)) revert AddressIsNotPendingTimelock(pendingTimelockAddress, _address);
}
/// @notice The ```_requirePendingTimelock``` function reverts if msg.sender is not pending timelock address
/// @dev This function is to be implemented by a public function
function _requireSenderIsPendingTimelock() internal view {
_requireIsPendingTimelock(msg.sender);
}
// ============================================================================================
// Functions: Events
// ============================================================================================
/// @notice The ```TimelockTransferStarted``` event is emitted when the timelock transfer is initiated
/// @param previousTimelock The address of the previous timelock
/// @param newTimelock The address of the new timelock
event TimelockTransferStarted(address indexed previousTimelock, address indexed newTimelock);
/// @notice The ```TimelockTransferred``` event is emitted when the timelock transfer is completed
/// @param previousTimelock The address of the previous timelock
/// @param newTimelock The address of the new timelock
event TimelockTransferred(address indexed previousTimelock, address indexed newTimelock);
// ============================================================================================
// Functions: Errors
// ============================================================================================
/// @notice Emitted when timelock is transferred
error AddressIsNotTimelock(address timelockAddress, address actualAddress);
/// @notice Emitted when pending timelock is transferred
error AddressIsNotPendingTimelock(address pendingTimelockAddress, address actualAddress);
}// SPDX-License-Identifier: ISC
pragma solidity ^0.8.23;
interface IUniswapV2Callee {
function uniswapV2Call(address sender, uint256 amount0, uint256 amount1, bytes calldata data) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (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();
}
}
}{
"remappings": [
"forge-std/=node_modules/forge-std/src/",
"solidity-bytes-utils/=node_modules/solidity-bytes-utils/",
"@openzeppelin/=node_modules/@openzeppelin/",
"@chainlink/=node_modules/@chainlink/",
"ds-test/=node_modules/ds-test/src/",
"frax-std/=node_modules/frax-std/src/",
"frax-standard-solidity/=node_modules/frax-standard-solidity/"
],
"optimizer": {
"enabled": true,
"runs": 100000
},
"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":[],"name":"AuctionAlreadyExists","type":"error"},{"inputs":[],"name":"AuctionDoesNotExist","type":"error"},{"inputs":[],"name":"TokenBuyMustBe18Decimals","type":"error"},{"inputs":[],"name":"TokenSellMustBe18Decimals","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"auction","type":"address"},{"indexed":true,"internalType":"address","name":"tokenBuy","type":"address"},{"indexed":true,"internalType":"address","name":"tokenSell","type":"address"}],"name":"AuctionCreated","type":"event"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"auctions","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"auctionsLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_timelock","type":"address"},{"internalType":"address","name":"_tokenBuy","type":"address"},{"internalType":"address","name":"_tokenSell","type":"address"}],"name":"createAuctionContract","outputs":[{"internalType":"address","name":"auction","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"getAuction","outputs":[{"internalType":"address","name":"auction","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAuctions","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"auction","type":"address"}],"name":"isAuction","outputs":[{"internalType":"bool","name":"exists","type":"bool"}],"stateMutability":"view","type":"function"}]Contract Creation Code
608060405234801561001057600080fd5b5061481a806100206000396000f3fe60806040523480156200001157600080fd5b50600436106200007b5760003560e01c8063d3cc6eb21162000056578063d3cc6eb2146200010f578063d7c069191462000121578063fc5ba3b2146200013a57600080fd5b8063571a26a0146200008057806378bd793514620000c15780638ebde50014620000d8575b600080fd5b62000097620000913660046200051e565b62000151565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b62000097620000d23660046200051e565b62000189565b620000fe620000e936600462000562565b60016020526000908152604090205460ff1681565b6040519015158152602001620000b8565b600054604051908152602001620000b8565b6200012b62000205565b604051620000b8919062000587565b620000976200014b366004620005e3565b62000276565b600081815481106200016257600080fd5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b60008054821115620001c7576040517fe6759c6700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281548110620001dd57620001dd6200062d565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1692915050565b606060008054806020026020016040519081016040528092919081815260200182805480156200026c57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff16815260019091019060200180831162000240575b5050505050905090565b60008273ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015620002c4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002ea91906200065c565b60ff1660121462000327576040517f59d8fde400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000373573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200039991906200065c565b60ff16601214620003d6576040517f1d1b7a4000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b838383604051620003e79062000510565b73ffffffffffffffffffffffffffffffffffffffff938416815291831660208301529091166040820152606001604051809103906000f08015801562000431573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff808216600081815260016020819052604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001683179055825491820183558280527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56390910180547fffffffffffffffffffffffff000000000000000000000000000000000000000016841790555193945085831693928716927f0e87f8cafb4bf66469b7827472c74c529bcb902261be5cd36e4b3dfcbc4ed07f9190a49392505050565b614163806200068283390190565b6000602082840312156200053157600080fd5b5035919050565b803573ffffffffffffffffffffffffffffffffffffffff811681146200055d57600080fd5b919050565b6000602082840312156200057557600080fd5b620005808262000538565b9392505050565b6020808252825182820181905260009190848201906040850190845b81811015620005d757835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101620005a3565b50909695505050505050565b600080600060608486031215620005f957600080fd5b620006048462000538565b9250620006146020850162000538565b9150620006246040850162000538565b90509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6000602082840312156200066f57600080fd5b815160ff811681146200058057600080fdfe6101006040523480156200001257600080fd5b506040516200416338038062004163833981016040819052620000359162000136565b60016000908155600280546001600160a01b0319166001600160a01b0386811691909117909155604080516395d89b4160e01b81529051918416926395d89b41926004808401938290030181865afa15801562000096573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052620000c09190810190620001bc565b604051602001620000d2919062000274565b60405160208183030381529060405260039081620000f1919062000340565b506001600160a01b039182166080819052911660a081905260c09190915260e052506200040c565b80516001600160a01b03811681146200013157600080fd5b919050565b6000806000606084860312156200014c57600080fd5b620001578462000119565b9250620001676020850162000119565b9150620001776040850162000119565b90509250925092565b634e487b7160e01b600052604160045260246000fd5b60005b83811015620001b357818101518382015260200162000199565b50506000910152565b600060208284031215620001cf57600080fd5b81516001600160401b0380821115620001e757600080fd5b818401915084601f830112620001fc57600080fd5b81518181111562000211576200021162000180565b604051601f8201601f19908116603f011681019083821181831017156200023c576200023c62000180565b816040528281528760208487010111156200025657600080fd5b6200026983602083016020880162000196565b979650505050505050565b70029b634b83830b3b2a0bab1ba34b7b71d1607d1b815260008251620002a281601185016020870162000196565b9190910160110192915050565b600181811c90821680620002c457607f821691505b602082108103620002e557634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200033b576000816000526020600020601f850160051c81016020861015620003165750805b601f850160051c820191505b81811015620003375782815560010162000322565b5050505b505050565b81516001600160401b038111156200035c576200035c62000180565b62000374816200036d8454620002af565b84620002eb565b602080601f831160018114620003ac5760008415620003935750858301515b600019600386901b1c1916600185901b17855562000337565b600085815260208120601f198616915b82811015620003dd57888601518255948401946001909101908401620003bc565b5085821015620003fc5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60805160a05160c05160e051613cad620004b6600039600061061e015260006103870152600081816104e30152818161085101528181610d52015281816111b4015281816114a9015281816115d5015281816126d10152612daa0152600081816104720152818161093f01528181610d310152818161146801528181611524015281816117e901528181611cda015281816127ee01528181612c1a0152612d7e0152613cad6000f3fe608060405234801561001057600080fd5b50600436106102ad5760003560e01c80635909c0d51161017b578063aaf5eb68116100d8578063d21220a71161008c578063f140a35a11610071578063f140a35a14610653578063f6ccaad414610666578063fff6cae9146102c557600080fd5b8063d21220a714610619578063e40dc7031461064057600080fd5b8063ba9a7a56116100bd578063ba9a7a56146104d6578063bc25cf7714610600578063c45a01551461061157600080fd5b8063aaf5eb68146105de578063afa29031146105ed57600080fd5b80637464fc3d1161012f5780638803dbee116101145780638803dbee146105155780639b4faa8014610528578063a005ec7a1461053b57600080fd5b80637464fc3d146104d657806385f8c259146102c757600080fd5b80635c80aeee116101605780635c80aeee146104de5780635f28bc5b146105055780636df00be81461050d57600080fd5b80635909c0d5146104d65780635a3d5493146104d657600080fd5b8063269b9a08116102295780634bc66f32116101dd57806354fd4d50116101c257806354fd4d50146104bc57806355d256e9146104c6578063561ad39f146104ce57600080fd5b80634bc66f32146104945780634f8b4ae7146104b457600080fd5b8063450140951161020e5780634501409514610447578063485cc9551461045a5780634b4349d51461046d57600080fd5b8063269b9a081461040a57806338ed17391461042757600080fd5b8063090f3f501161028057806311106ee21161026557806311106ee2146103a95780631125f13f146103d7578063241a277f146103ea57600080fd5b8063090f3f501461033d5780630dfe16811461038257600080fd5b8063022c0d9f146102b2578063054d50d4146102c757806306fdde03146102ed5780630902f1ac14610302575b600080fd5b6102c56102c0366004613355565b61066e565b005b6102da6102d536600461342c565b610e0e565b6040519081526020015b60405180910390f35b6102f5610e42565b6040516102e491906134c6565b61030a610ed0565b604080516dffffffffffffffffffffffffffff948516815293909216602084015263ffffffff16908201526060016102e4565b60015461035d9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016102e4565b61035d7f000000000000000000000000000000000000000000000000000000000000000081565b6103bc6103b73660046134f2565b610f07565b604080519384526020840192909252908201526060016102e4565b6102da6103e5366004613522565b6111b0565b6103fd6103f836600461354e565b61124a565b6040516102e49190613567565b6104126113c9565b604080519283526020830191909152016102e4565b61043a6104353660046136c3565b61173e565b6040516102e4919061379e565b6102c56104553660046137e2565b6118b4565b6102c56104683660046137fd565b6118c5565b61035d7f000000000000000000000000000000000000000000000000000000000000000081565b60025461035d9073ffffffffffffffffffffffffffffffffffffffff1681565b6102c56118f7565b60016000816103bc565b6102da61191d565b6004546102da565b6102da610e0e565b61035d7f000000000000000000000000000000000000000000000000000000000000000081565b6103fd611a53565b6103bc611ae4565b61043a610523366004613827565b611c31565b6103bc61053636600461354e565b611d7a565b61054e61054936600461354e565b611ec9565b604080516fffffffffffffffffffffffffffffffff9d8e1681529b8d1660208d0152998c16998b0199909952968a1660608a0152948916608089015292881660a0880152961660c086015267ffffffffffffffff95861660e08601529490941661010084015263ffffffff93841661012084015292909216610140820152901515610160820152610180016102e4565b6102da670de0b6b3a764000081565b6102da6105fb3660046138c9565b611f9d565b6102c561060e3660046137e2565b50565b61035d610e0e565b61035d7f000000000000000000000000000000000000000000000000000000000000000081565b6102da61064e366004613927565b61271a565b6102da610661366004613522565b6127ea565b6102c561287c565b61067661288c565b83156106bd576040517f0ed4217800000000000000000000000000000000000000000000000000000000815260006004820152602481018590526044015b60405180910390fd5b82600003610701576040517fd28d3eb500000000000000000000000000000000000000000000000000000000815260016004820152600060248201526044016106b4565b60045460009061071390600190613a42565b905060006004828154811061072a5761072a613a55565b60009182526020918290206040805161018081018252600590930290910180546fffffffffffffffffffffffffffffffff808216855270010000000000000000000000000000000091829004811695850195909552600182015480861693850193909352918290048416606084015260028101548085166080850152829004841660a0840152600381015493841660c084015267ffffffffffffffff918404821660e084015278010000000000000000000000000000000000000000000000009093041661010082015260049091015463ffffffff8082166101208401526401000000008204811661014084015260ff6801000000000000000090920491909116151561016083015290915061087c9073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690869088906128cf16565b82511561090e576040517f10d1e85c00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516906310d1e85c906108db9033908a908a908990600401613a84565b600060405180830381600087803b1580156108f557600080fd5b505af1158015610909573d6000803e3d6000fd5b505050505b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa15801561099b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109bf9190613ac9565b9050600082608001516fffffffffffffffffffffffffffffffff16826109e59190613a42565b6040805182815260006020820181905281830152606081018a9052905191925073ffffffffffffffffffffffffffffffffffffffff88169133917fd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822919081900360800190a36000806000610a59868b612955565b92509250925082841015610aa3576040517fec3e79fb00000000000000000000000000000000000000000000000000000000815260048101849052602481018590526044016106b4565b82600003610add576040517f55eaa09500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610ae68a612adc565b86602001818151610af79190613ae2565b6fffffffffffffffffffffffffffffffff16905250610b1585612adc565b6fffffffffffffffffffffffffffffffff166080870152610b3581612adc565b6fffffffffffffffffffffffffffffffff1660a087015263ffffffff42166101208701526004805487919089908110610b7057610b70613a55565b60009182526020918290208351928401516fffffffffffffffffffffffffffffffff9081167001000000000000000000000000000000009081029482169490941760059093029091019182556040840151606085015182168402908216176001830155608084015160a08501518216840290821617600283015560c084015160038301805460e087015161010088015167ffffffffffffffff90811678010000000000000000000000000000000000000000000000000277ffffffffffffffffffffffffffffffffffffffffffffffff919092169097027fffffffffffffffff00000000000000000000000000000000000000000000000090921693909416929092179190911793909316179091556101208201516004909101805461014084015161016090940151151568010000000000000000027fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff63ffffffff958616640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000909316959094169490941717919091169190911790557f4c8e97934cb2d5c0876fe70b82782d28160e62ef5844aa6ba80e10174feed687877f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000610d7a88612adc565b610d838f612adc565b8b60a00151610d9189612adc565b6040805197885273ffffffffffffffffffffffffffffffffffffffff968716602089015294909516868501526fffffffffffffffffffffffffffffffff92831660608701529082166080860152811660a085015290911660c0830152519081900360e00190a150505050505050610e086001600055565b50505050565b60006040517fd623472500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60038054610e4f90613b12565b80601f0160208091040260200160405190810160405280929190818152602001828054610e7b90613b12565b8015610ec85780601f10610e9d57610100808354040283529160200191610ec8565b820191906000526020600020905b815481529060010190602001808311610eab57829003601f168201915b505050505081565b60008060006040517fd623472500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000806000806001600480549050610f1f9190613a42565b9050600060048281548110610f3657610f36613a55565b60009182526020918290206040805161018081018252600590930290910180546fffffffffffffffffffffffffffffffff808216855270010000000000000000000000000000000091829004811695850195909552600182015480861693850193909352918290048416606084015260028101548085166080850152829004841660a0840152600381015493841660c084015267ffffffffffffffff918404821660e084015278010000000000000000000000000000000000000000000000009093041661010082015260049091015463ffffffff80821661012084015264010000000082041661014083015260ff680100000000000000009091041615156101608201819052909150611076576040517f69b8d0fe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80610140015163ffffffff1642106110ba576040517f04a5e67c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006110c58261271a565b9050670de0b6b3a76400008883610100015167ffffffffffffffff166110eb9190613b5f565b6110f59190613b76565b94506111018582613bb1565b611113670de0b6b3a76400008a613b5f565b61111d9190613b76565b955081602001516fffffffffffffffffffffffffffffffff1686111561118f578615611175576040517ffc43992200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81602001516fffffffffffffffffffffffffffffffff1695505b61119a856002613b5f565b6111a49082613bb1565b93505050509250925092565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614611237576040517f1b6d1fa000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61124083611d7a565b5090949350505050565b6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810191909152600482815481106112be576112be613a55565b60009182526020918290206040805161018081018252600590930290910180546fffffffffffffffffffffffffffffffff808216855270010000000000000000000000000000000091829004811695850195909552600182015480861693850193909352918290048416606084015260028101548085166080850152829004841660a0840152600381015493841660c084015267ffffffffffffffff918404821660e084015278010000000000000000000000000000000000000000000000009093041661010082015260049091015463ffffffff80821661012084015264010000000082041661014083015260ff6801000000000000000090910416151561016082015292915050565b6000806113d461288c565b6113dc612b2c565b6004546000906113ee90600190613a42565b905060006004828154811061140557611405613a55565b906000526020600020906005020190508060040160089054906101000a900460ff1661145d576040517f69b8d0fe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60028101546114a1907f0000000000000000000000000000000000000000000000000000000000000000906fffffffffffffffffffffffffffffffff166001612b35565b80546114f6907f00000000000000000000000000000000000000000000000000000000000000009070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff166001612b35565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015611580573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115a49190613ac9565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529094507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015611631573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116559190613ac9565b6004820180547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff1690556002820180546fffffffffffffffffffffffffffffffff8088167fffffffffffffffffffffffffffffffff0000000000000000000000000000000090921691909117909155825481831670010000000000000000000000000000000002911617825592506116ed6000612d79565b60408051838152602081018690529081018490527fdeb58d7180330f713ed3023619d340a8f4f264aee7cd0707f8997ce863182e999060600160405180910390a1505061173a6001600055565b9091565b60608142111561177a576040517f203d82d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611787876001610f07565b50509050858110156117cf576040517fd28d3eb500000000000000000000000000000000000000000000000000000000815260048101879052602481018290526044016106b4565b61181173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001633308a612dd1565b61184a60008286825b6040519080825280601f01601f191660200182016040528015611844576020820181803683370190505b5061066e565b6040805160028082526060820183529091602083019080368337019050509150868260008151811061187e5761187e613a55565b602002602001018181525050808260018151811061189e5761189e613a55565b6020026020010181815250505095945050505050565b6118bc612b2c565b61060e81612e17565b6040517fd623472500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6118ff612b2c565b611907612e8e565b6119116000612e17565b61191b6000612e97565b565b60048054600091611a4e9161193490600190613a42565b8154811061194457611944613a55565b60009182526020918290206040805161018081018252600590930290910180546fffffffffffffffffffffffffffffffff808216855270010000000000000000000000000000000091829004811695850195909552600182015480861693850193909352918290048416606084015260028101548085166080850152829004841660a0840152600381015493841660c084015267ffffffffffffffff918404821660e084015278010000000000000000000000000000000000000000000000009093041661010082015260049091015463ffffffff80821661012084015264010000000082041661014083015260ff6801000000000000000090910416151561016082015261271a565b905090565b6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081018290526101608101919091526004546000819003611ac4575090565b60048054611ad490600190613a42565b815481106112be576112be613a55565b6000806000806001600480549050611afc9190613a42565b9050600060048281548110611b1357611b13613a55565b60009182526020918290206040805161018081018252600590930290910180546fffffffffffffffffffffffffffffffff8082168552700100000000000000000000000000000000918290048116958501869052600183015480821694860194909452928190048316606085015260028201548084166080860152819004831660a0850152600382015492831660c085015267ffffffffffffffff908304811660e085015278010000000000000000000000000000000000000000000000009092049091166101008301526004015463ffffffff80821661012084015264010000000082041661014083015260ff680100000000000000009091041615156101608201529150611c24908290612955565b9450945094505050909192565b606081421115611c6d576040517f203d82d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611c7888611d7a565b5050905086811115611cc0576040517f4c67496b00000000000000000000000000000000000000000000000000000000815260048101889052602481018290526044016106b4565b611d0273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016333084612dd1565b611d0f600089868261181a565b60408051600280825260608201835290916020830190803683370190505091508082600081518110611d4357611d43613a55565b6020026020010181815250508782600181518110611d6357611d63613a55565b602002602001018181525050509695505050505050565b6000806000806001600480549050611d929190613a42565b9050600060048281548110611da957611da9613a55565b60009182526020918290206040805161018081018252600590930290910180546fffffffffffffffffffffffffffffffff808216855270010000000000000000000000000000000091829004811695850195909552600182015480861693850193909352918290048416606084015260028101548085166080850152829004841660a0840152600381015493841660c084015267ffffffffffffffff918404821660e084015278010000000000000000000000000000000000000000000000009093041661010082015260049091015463ffffffff80821661012084015264010000000082041661014083015260ff680100000000000000009091041615156101608201529050611eba8187612955565b91989097509095509350505050565b60048181548110611ed957600080fd5b6000918252602090912060059091020180546001820154600283015460038401546004909401546fffffffffffffffffffffffffffffffff8085169650700100000000000000000000000000000000948590048116958185169594859004821694828516948190048316939282169290820467ffffffffffffffff9081169278010000000000000000000000000000000000000000000000009004169063ffffffff8082169164010000000081049091169068010000000000000000900460ff168c565b6000611fa761288c565b611faf612b2c565b42611fc060c0840160a08501613bc4565b63ffffffff161015611ffe576040517f203d82d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6305f5e1006120106020840184613bdf565b6fffffffffffffffffffffffffffffffff16101561205a576040517fc60f14dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61206a6060830160408401613bdf565b6fffffffffffffffffffffffffffffffff1661208c6040840160208501613bdf565b6fffffffffffffffffffffffffffffffff1610156120d6576040517f501b4f1500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6120e66060830160408401613bdf565b6fffffffffffffffffffffffffffffffff1615801561211c575061211060a0830160808401613bfa565b67ffffffffffffffff16155b15612153576040517fcdcc1fea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5060045480156122bd576000600461216c600184613a42565b8154811061217c5761217c613a55565b60009182526020918290206040805161018081018252600590930290910180546fffffffffffffffffffffffffffffffff808216855270010000000000000000000000000000000091829004811695850195909552600182015480861693850193909352918290048416606084015260028101548085166080850152829004841660a0840152600381015493841660c084015267ffffffffffffffff918404821660e084015278010000000000000000000000000000000000000000000000009093041661010082015260049091015463ffffffff80821661012084015264010000000082041661014083015260ff68010000000000000000909104161580156101608301529091506122bb576040517f800eee7100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b604080516101808101909152600490806122da6020860186613bdf565b6fffffffffffffffffffffffffffffffff16815260209081019061230090860186613bdf565b6fffffffffffffffffffffffffffffffff16815260200160006fffffffffffffffffffffffffffffffff16815260200160006fffffffffffffffffffffffffffffffff16815260200160006fffffffffffffffffffffffffffffffff1681526020018460200160208101906123759190613bdf565b6fffffffffffffffffffffffffffffffff16815260200161239c6060860160408701613bdf565b6fffffffffffffffffffffffffffffffff1681526020016123c36080860160608701613bfa565b67ffffffffffffffff1681526020016123e260a0860160808701613bfa565b67ffffffffffffffff16815263ffffffff4216602082015260400161240d60c0860160a08701613bc4565b63ffffffff908116825260016020928301819052845480820186556000958652948390208451858501516fffffffffffffffffffffffffffffffff91821670010000000000000000000000000000000091831682021760059098029092019687556040860151606087015190821690821683021792870192909255608085015160a0860151908316908316820217600287015560c085015160038701805460e0880151610100890151939095167fffffffffffffffff0000000000000000000000000000000000000000000000009091161767ffffffffffffffff9485169093029290921777ffffffffffffffffffffffffffffffffffffffffffffffff167801000000000000000000000000000000000000000000000000939091169290920291909117905561012083015160049094018054610140850151610160909501519583167fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000909116176401000000009490921693909302177fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff1668010000000000000000931515939093029290921790557f49f979d434de33c8feec553b9de34d0b7b5ee6a11f0df00c3b60c742ae17f1679082906125ee90850185613bdf565b6125fe6040860160208701613bdf565b61260e6060870160408801613bdf565b61261e6080880160608901613bfa565b61262e60a0890160808a01613bfa565b61263e60c08a0160a08b01613bc4565b604080519788526fffffffffffffffffffffffffffffffff96871660208901529486168786015292909416606086015267ffffffffffffffff908116608086015290921660a084015263ffffffff90911660c0830152519081900360e00190a16126a86001612d79565b61270b33306126ba6020860186613bdf565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169291906fffffffffffffffffffffffffffffffff16612dd1565b6127156001600055565b919050565b60008082610120015163ffffffff16426127349190613a42565b8360e0015167ffffffffffffffff1661274d9190613b5f565b9050808360a001516fffffffffffffffffffffffffffffffff16101561278857505060c001516fffffffffffffffffffffffffffffffff1690565b808360a001516fffffffffffffffffffffffffffffffff166127aa9190613a42565b91508260c001516fffffffffffffffffffffffffffffffff168210156127e4578260c001516fffffffffffffffffffffffffffffffff1691505b50919050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614612871576040517fd70f29d200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611240836000610f07565b612884612e8e565b61191b612f25565b6002600054036128c8576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002600055565b60405173ffffffffffffffffffffffffffffffffffffffff83811660248301526044820183905261295091859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050612f56565b505050565b6000806000846101600151612996576040517f69b8d0fe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84610140015163ffffffff1642106129da576040517f04a5e67c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84602001516fffffffffffffffffffffffffffffffff16841115612a2a576040517ffc43992200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612a358661271a565b9050670de0b6b3a764000086610100015167ffffffffffffffff1686612a5b9190613b5f565b612a659190613b76565b612a7790670de0b6b3a7640000613a42565b612a818287613b5f565b612a8b9190613b76565b9350670de0b6b3a76400008487610100015167ffffffffffffffff16612ab19190613b5f565b612abb9190613b76565b9250612ac8836002613b5f565b612ad29082613bb1565b9150509250925092565b60006fffffffffffffffffffffffffffffffff821115612b28576040517f35278d1200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5090565b61191b33612fec565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009073ffffffffffffffffffffffffffffffffffffffff8516906370a0823190602401602060405180830381865afa158015612ba2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bc69190613ac9565b905082811115610e08576000612bdc8483613a42565b90508215612d51576004805460009190612bf890600190613a42565b81548110612c0857612c08613a55565b906000526020600020906005020190507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1603612cd557612c7482612adc565b600182018054600090612c9a9084906fffffffffffffffffffffffffffffffff16613c15565b92506101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff160217905550612d4f565b612cde82612adc565b600182018054601090612d1890849070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16613c15565b92506101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055505b505b612d7273ffffffffffffffffffffffffffffffffffffffff861633836128cf565b5050505050565b612da57f0000000000000000000000000000000000000000000000000000000000000000600083612b35565b61060e7f0000000000000000000000000000000000000000000000000000000000000000600083612b35565b60405173ffffffffffffffffffffffffffffffffffffffff8481166024830152838116604483015260648201839052610e089186918216906323b872dd90608401612909565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff838116918217909255600254604051919216907f162998b90abc2507f3953aa797827b03a14c42dbd9a35f09feaf02e0d592773a90600090a350565b61191b33613064565b60025460405173ffffffffffffffffffffffffffffffffffffffff8084169216907f31b6c5a04b069b6ec1b3cef44c4e7c1eadd721349cda9823d0b1877b3551cdc690600090a3600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b600180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905561191b33612e97565b6000612f7873ffffffffffffffffffffffffffffffffffffffff8416836130dc565b90508051600014158015612f9d575080806020019051810190612f9b9190613c3e565b155b15612950576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff841660048201526024016106b4565b60025473ffffffffffffffffffffffffffffffffffffffff82811691161461060e576002546040517f443dc2b400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff918216600482015290821660248201526044016106b4565b60015473ffffffffffffffffffffffffffffffffffffffff82811691161461060e576001546040517fbe5a953700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff918216600482015290821660248201526044016106b4565b60606130ea838360006130f3565b90505b92915050565b606081471015613131576040517fcd7860590000000000000000000000000000000000000000000000000000000081523060048201526024016106b4565b6000808573ffffffffffffffffffffffffffffffffffffffff16848660405161315a9190613c5b565b60006040518083038185875af1925050503d8060008114613197576040519150601f19603f3d011682016040523d82523d6000602084013e61319c565b606091505b50915091506131ac8683836131b8565b925050505b9392505050565b6060826131cd576131c882613247565b6131b1565b81511580156131f1575073ffffffffffffffffffffffffffffffffffffffff84163b155b15613240576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff851660048201526024016106b4565b50806131b1565b8051156132575780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b803573ffffffffffffffffffffffffffffffffffffffff8116811461271557600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610180810167ffffffffffffffff81118282101715613300576133006132ad565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561334d5761334d6132ad565b604052919050565b6000806000806080858703121561336b57600080fd5b84359350602080860135935061338360408701613289565b9250606086013567ffffffffffffffff808211156133a057600080fd5b818801915088601f8301126133b457600080fd5b8135818111156133c6576133c66132ad565b6133f6847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601613306565b9150808252898482850101111561340c57600080fd5b808484018584013760008482840101525080935050505092959194509250565b60008060006060848603121561344157600080fd5b505081359360208301359350604090920135919050565b60005b8381101561347357818101518382015260200161345b565b50506000910152565b60008151808452613494816020860160208601613458565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006130ea602083018461347c565b801515811461060e57600080fd5b8035612715816134d9565b6000806040838503121561350557600080fd5b823591506020830135613517816134d9565b809150509250929050565b6000806040838503121561353557600080fd5b8235915061354560208401613289565b90509250929050565b60006020828403121561356057600080fd5b5035919050565b81516fffffffffffffffffffffffffffffffff168152610180810160208301516135a560208401826fffffffffffffffffffffffffffffffff169052565b5060408301516135c960408401826fffffffffffffffffffffffffffffffff169052565b5060608301516135ed60608401826fffffffffffffffffffffffffffffffff169052565b50608083015161361160808401826fffffffffffffffffffffffffffffffff169052565b5060a083015161363560a08401826fffffffffffffffffffffffffffffffff169052565b5060c083015161365960c08401826fffffffffffffffffffffffffffffffff169052565b5060e083015161367560e084018267ffffffffffffffff169052565b506101008381015167ffffffffffffffff16908301526101208084015163ffffffff908116918401919091526101408085015190911690830152610160928301511515929091019190915290565b600080600080600060a086880312156136db57600080fd5b853594506020808701359450604087013567ffffffffffffffff8082111561370257600080fd5b818901915089601f83011261371657600080fd5b813581811115613728576137286132ad565b8060051b9150613739848301613306565b818152918301840191848101908c84111561375357600080fd5b938501935b838510156137785761376985613289565b82529385019390850190613758565b80985050505050505061378d60608701613289565b949793965091946080013592915050565b6020808252825182820181905260009190848201906040850190845b818110156137d6578351835292840192918401916001016137ba565b50909695505050505050565b6000602082840312156137f457600080fd5b6130ea82613289565b6000806040838503121561381057600080fd5b61381983613289565b915061354560208401613289565b60008060008060008060a0878903121561384057600080fd5b8635955060208701359450604087013567ffffffffffffffff8082111561386657600080fd5b818901915089601f83011261387a57600080fd5b81358181111561388957600080fd5b8a60208260051b850101111561389e57600080fd5b6020830196508095505050506138b660608801613289565b9150608087013590509295509295509295565b600060c082840312156127e457600080fd5b80356fffffffffffffffffffffffffffffffff8116811461271557600080fd5b803567ffffffffffffffff8116811461271557600080fd5b803563ffffffff8116811461271557600080fd5b6000610180828403121561393a57600080fd5b6139426132dc565b61394b836138db565b8152613959602084016138db565b602082015261396a604084016138db565b604082015261397b606084016138db565b606082015261398c608084016138db565b608082015261399d60a084016138db565b60a08201526139ae60c084016138db565b60c08201526139bf60e084016138fb565b60e08201526101006139d28185016138fb565b908201526101206139e4848201613913565b908201526101406139f6848201613913565b90820152610160613a088482016134e7565b908201529392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b818103818111156130ed576130ed613a13565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b73ffffffffffffffffffffffffffffffffffffffff85168152836020820152826040820152608060608201526000613abf608083018461347c565b9695505050505050565b600060208284031215613adb57600080fd5b5051919050565b6fffffffffffffffffffffffffffffffff828116828216039080821115613b0b57613b0b613a13565b5092915050565b600181811c90821680613b2657607f821691505b6020821081036127e4577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b80820281158282048414176130ed576130ed613a13565b600082613bac577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b808201808211156130ed576130ed613a13565b600060208284031215613bd657600080fd5b6130ea82613913565b600060208284031215613bf157600080fd5b6130ea826138db565b600060208284031215613c0c57600080fd5b6130ea826138fb565b6fffffffffffffffffffffffffffffffff818116838216019080821115613b0b57613b0b613a13565b600060208284031215613c5057600080fd5b81516131b1816134d9565b60008251613c6d818460208701613458565b919091019291505056fea26469706673582212208ec73c478f099ff03b90c422145c33e3f767a8e355a0920077a210d2face11b464736f6c63430008180033a264697066735822122008314d1a0b5ae7db8d9a1f179674d616184fe6eedf0080a52177b51be77ed77364736f6c63430008180033
Deployed Bytecode
0x60806040523480156200001157600080fd5b50600436106200007b5760003560e01c8063d3cc6eb21162000056578063d3cc6eb2146200010f578063d7c069191462000121578063fc5ba3b2146200013a57600080fd5b8063571a26a0146200008057806378bd793514620000c15780638ebde50014620000d8575b600080fd5b62000097620000913660046200051e565b62000151565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b62000097620000d23660046200051e565b62000189565b620000fe620000e936600462000562565b60016020526000908152604090205460ff1681565b6040519015158152602001620000b8565b600054604051908152602001620000b8565b6200012b62000205565b604051620000b8919062000587565b620000976200014b366004620005e3565b62000276565b600081815481106200016257600080fd5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b60008054821115620001c7576040517fe6759c6700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281548110620001dd57620001dd6200062d565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1692915050565b606060008054806020026020016040519081016040528092919081815260200182805480156200026c57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff16815260019091019060200180831162000240575b5050505050905090565b60008273ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015620002c4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002ea91906200065c565b60ff1660121462000327576040517f59d8fde400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000373573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200039991906200065c565b60ff16601214620003d6576040517f1d1b7a4000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b838383604051620003e79062000510565b73ffffffffffffffffffffffffffffffffffffffff938416815291831660208301529091166040820152606001604051809103906000f08015801562000431573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff808216600081815260016020819052604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001683179055825491820183558280527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56390910180547fffffffffffffffffffffffff000000000000000000000000000000000000000016841790555193945085831693928716927f0e87f8cafb4bf66469b7827472c74c529bcb902261be5cd36e4b3dfcbc4ed07f9190a49392505050565b614163806200068283390190565b6000602082840312156200053157600080fd5b5035919050565b803573ffffffffffffffffffffffffffffffffffffffff811681146200055d57600080fd5b919050565b6000602082840312156200057557600080fd5b620005808262000538565b9392505050565b6020808252825182820181905260009190848201906040850190845b81811015620005d757835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101620005a3565b50909695505050505050565b600080600060608486031215620005f957600080fd5b620006048462000538565b9250620006146020850162000538565b9150620006246040850162000538565b90509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6000602082840312156200066f57600080fd5b815160ff811681146200058057600080fdfe6101006040523480156200001257600080fd5b506040516200416338038062004163833981016040819052620000359162000136565b60016000908155600280546001600160a01b0319166001600160a01b0386811691909117909155604080516395d89b4160e01b81529051918416926395d89b41926004808401938290030181865afa15801562000096573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052620000c09190810190620001bc565b604051602001620000d2919062000274565b60405160208183030381529060405260039081620000f1919062000340565b506001600160a01b039182166080819052911660a081905260c09190915260e052506200040c565b80516001600160a01b03811681146200013157600080fd5b919050565b6000806000606084860312156200014c57600080fd5b620001578462000119565b9250620001676020850162000119565b9150620001776040850162000119565b90509250925092565b634e487b7160e01b600052604160045260246000fd5b60005b83811015620001b357818101518382015260200162000199565b50506000910152565b600060208284031215620001cf57600080fd5b81516001600160401b0380821115620001e757600080fd5b818401915084601f830112620001fc57600080fd5b81518181111562000211576200021162000180565b604051601f8201601f19908116603f011681019083821181831017156200023c576200023c62000180565b816040528281528760208487010111156200025657600080fd5b6200026983602083016020880162000196565b979650505050505050565b70029b634b83830b3b2a0bab1ba34b7b71d1607d1b815260008251620002a281601185016020870162000196565b9190910160110192915050565b600181811c90821680620002c457607f821691505b602082108103620002e557634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200033b576000816000526020600020601f850160051c81016020861015620003165750805b601f850160051c820191505b81811015620003375782815560010162000322565b5050505b505050565b81516001600160401b038111156200035c576200035c62000180565b62000374816200036d8454620002af565b84620002eb565b602080601f831160018114620003ac5760008415620003935750858301515b600019600386901b1c1916600185901b17855562000337565b600085815260208120601f198616915b82811015620003dd57888601518255948401946001909101908401620003bc565b5085821015620003fc5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60805160a05160c05160e051613cad620004b6600039600061061e015260006103870152600081816104e30152818161085101528181610d52015281816111b4015281816114a9015281816115d5015281816126d10152612daa0152600081816104720152818161093f01528181610d310152818161146801528181611524015281816117e901528181611cda015281816127ee01528181612c1a0152612d7e0152613cad6000f3fe608060405234801561001057600080fd5b50600436106102ad5760003560e01c80635909c0d51161017b578063aaf5eb68116100d8578063d21220a71161008c578063f140a35a11610071578063f140a35a14610653578063f6ccaad414610666578063fff6cae9146102c557600080fd5b8063d21220a714610619578063e40dc7031461064057600080fd5b8063ba9a7a56116100bd578063ba9a7a56146104d6578063bc25cf7714610600578063c45a01551461061157600080fd5b8063aaf5eb68146105de578063afa29031146105ed57600080fd5b80637464fc3d1161012f5780638803dbee116101145780638803dbee146105155780639b4faa8014610528578063a005ec7a1461053b57600080fd5b80637464fc3d146104d657806385f8c259146102c757600080fd5b80635c80aeee116101605780635c80aeee146104de5780635f28bc5b146105055780636df00be81461050d57600080fd5b80635909c0d5146104d65780635a3d5493146104d657600080fd5b8063269b9a08116102295780634bc66f32116101dd57806354fd4d50116101c257806354fd4d50146104bc57806355d256e9146104c6578063561ad39f146104ce57600080fd5b80634bc66f32146104945780634f8b4ae7146104b457600080fd5b8063450140951161020e5780634501409514610447578063485cc9551461045a5780634b4349d51461046d57600080fd5b8063269b9a081461040a57806338ed17391461042757600080fd5b8063090f3f501161028057806311106ee21161026557806311106ee2146103a95780631125f13f146103d7578063241a277f146103ea57600080fd5b8063090f3f501461033d5780630dfe16811461038257600080fd5b8063022c0d9f146102b2578063054d50d4146102c757806306fdde03146102ed5780630902f1ac14610302575b600080fd5b6102c56102c0366004613355565b61066e565b005b6102da6102d536600461342c565b610e0e565b6040519081526020015b60405180910390f35b6102f5610e42565b6040516102e491906134c6565b61030a610ed0565b604080516dffffffffffffffffffffffffffff948516815293909216602084015263ffffffff16908201526060016102e4565b60015461035d9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016102e4565b61035d7f000000000000000000000000000000000000000000000000000000000000000081565b6103bc6103b73660046134f2565b610f07565b604080519384526020840192909252908201526060016102e4565b6102da6103e5366004613522565b6111b0565b6103fd6103f836600461354e565b61124a565b6040516102e49190613567565b6104126113c9565b604080519283526020830191909152016102e4565b61043a6104353660046136c3565b61173e565b6040516102e4919061379e565b6102c56104553660046137e2565b6118b4565b6102c56104683660046137fd565b6118c5565b61035d7f000000000000000000000000000000000000000000000000000000000000000081565b60025461035d9073ffffffffffffffffffffffffffffffffffffffff1681565b6102c56118f7565b60016000816103bc565b6102da61191d565b6004546102da565b6102da610e0e565b61035d7f000000000000000000000000000000000000000000000000000000000000000081565b6103fd611a53565b6103bc611ae4565b61043a610523366004613827565b611c31565b6103bc61053636600461354e565b611d7a565b61054e61054936600461354e565b611ec9565b604080516fffffffffffffffffffffffffffffffff9d8e1681529b8d1660208d0152998c16998b0199909952968a1660608a0152948916608089015292881660a0880152961660c086015267ffffffffffffffff95861660e08601529490941661010084015263ffffffff93841661012084015292909216610140820152901515610160820152610180016102e4565b6102da670de0b6b3a764000081565b6102da6105fb3660046138c9565b611f9d565b6102c561060e3660046137e2565b50565b61035d610e0e565b61035d7f000000000000000000000000000000000000000000000000000000000000000081565b6102da61064e366004613927565b61271a565b6102da610661366004613522565b6127ea565b6102c561287c565b61067661288c565b83156106bd576040517f0ed4217800000000000000000000000000000000000000000000000000000000815260006004820152602481018590526044015b60405180910390fd5b82600003610701576040517fd28d3eb500000000000000000000000000000000000000000000000000000000815260016004820152600060248201526044016106b4565b60045460009061071390600190613a42565b905060006004828154811061072a5761072a613a55565b60009182526020918290206040805161018081018252600590930290910180546fffffffffffffffffffffffffffffffff808216855270010000000000000000000000000000000091829004811695850195909552600182015480861693850193909352918290048416606084015260028101548085166080850152829004841660a0840152600381015493841660c084015267ffffffffffffffff918404821660e084015278010000000000000000000000000000000000000000000000009093041661010082015260049091015463ffffffff8082166101208401526401000000008204811661014084015260ff6801000000000000000090920491909116151561016083015290915061087c9073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690869088906128cf16565b82511561090e576040517f10d1e85c00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516906310d1e85c906108db9033908a908a908990600401613a84565b600060405180830381600087803b1580156108f557600080fd5b505af1158015610909573d6000803e3d6000fd5b505050505b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa15801561099b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109bf9190613ac9565b9050600082608001516fffffffffffffffffffffffffffffffff16826109e59190613a42565b6040805182815260006020820181905281830152606081018a9052905191925073ffffffffffffffffffffffffffffffffffffffff88169133917fd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822919081900360800190a36000806000610a59868b612955565b92509250925082841015610aa3576040517fec3e79fb00000000000000000000000000000000000000000000000000000000815260048101849052602481018590526044016106b4565b82600003610add576040517f55eaa09500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610ae68a612adc565b86602001818151610af79190613ae2565b6fffffffffffffffffffffffffffffffff16905250610b1585612adc565b6fffffffffffffffffffffffffffffffff166080870152610b3581612adc565b6fffffffffffffffffffffffffffffffff1660a087015263ffffffff42166101208701526004805487919089908110610b7057610b70613a55565b60009182526020918290208351928401516fffffffffffffffffffffffffffffffff9081167001000000000000000000000000000000009081029482169490941760059093029091019182556040840151606085015182168402908216176001830155608084015160a08501518216840290821617600283015560c084015160038301805460e087015161010088015167ffffffffffffffff90811678010000000000000000000000000000000000000000000000000277ffffffffffffffffffffffffffffffffffffffffffffffff919092169097027fffffffffffffffff00000000000000000000000000000000000000000000000090921693909416929092179190911793909316179091556101208201516004909101805461014084015161016090940151151568010000000000000000027fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff63ffffffff958616640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000909316959094169490941717919091169190911790557f4c8e97934cb2d5c0876fe70b82782d28160e62ef5844aa6ba80e10174feed687877f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000610d7a88612adc565b610d838f612adc565b8b60a00151610d9189612adc565b6040805197885273ffffffffffffffffffffffffffffffffffffffff968716602089015294909516868501526fffffffffffffffffffffffffffffffff92831660608701529082166080860152811660a085015290911660c0830152519081900360e00190a150505050505050610e086001600055565b50505050565b60006040517fd623472500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60038054610e4f90613b12565b80601f0160208091040260200160405190810160405280929190818152602001828054610e7b90613b12565b8015610ec85780601f10610e9d57610100808354040283529160200191610ec8565b820191906000526020600020905b815481529060010190602001808311610eab57829003601f168201915b505050505081565b60008060006040517fd623472500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000806000806001600480549050610f1f9190613a42565b9050600060048281548110610f3657610f36613a55565b60009182526020918290206040805161018081018252600590930290910180546fffffffffffffffffffffffffffffffff808216855270010000000000000000000000000000000091829004811695850195909552600182015480861693850193909352918290048416606084015260028101548085166080850152829004841660a0840152600381015493841660c084015267ffffffffffffffff918404821660e084015278010000000000000000000000000000000000000000000000009093041661010082015260049091015463ffffffff80821661012084015264010000000082041661014083015260ff680100000000000000009091041615156101608201819052909150611076576040517f69b8d0fe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80610140015163ffffffff1642106110ba576040517f04a5e67c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006110c58261271a565b9050670de0b6b3a76400008883610100015167ffffffffffffffff166110eb9190613b5f565b6110f59190613b76565b94506111018582613bb1565b611113670de0b6b3a76400008a613b5f565b61111d9190613b76565b955081602001516fffffffffffffffffffffffffffffffff1686111561118f578615611175576040517ffc43992200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81602001516fffffffffffffffffffffffffffffffff1695505b61119a856002613b5f565b6111a49082613bb1565b93505050509250925092565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614611237576040517f1b6d1fa000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61124083611d7a565b5090949350505050565b6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810191909152600482815481106112be576112be613a55565b60009182526020918290206040805161018081018252600590930290910180546fffffffffffffffffffffffffffffffff808216855270010000000000000000000000000000000091829004811695850195909552600182015480861693850193909352918290048416606084015260028101548085166080850152829004841660a0840152600381015493841660c084015267ffffffffffffffff918404821660e084015278010000000000000000000000000000000000000000000000009093041661010082015260049091015463ffffffff80821661012084015264010000000082041661014083015260ff6801000000000000000090910416151561016082015292915050565b6000806113d461288c565b6113dc612b2c565b6004546000906113ee90600190613a42565b905060006004828154811061140557611405613a55565b906000526020600020906005020190508060040160089054906101000a900460ff1661145d576040517f69b8d0fe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60028101546114a1907f0000000000000000000000000000000000000000000000000000000000000000906fffffffffffffffffffffffffffffffff166001612b35565b80546114f6907f00000000000000000000000000000000000000000000000000000000000000009070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff166001612b35565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015611580573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115a49190613ac9565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529094507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015611631573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116559190613ac9565b6004820180547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff1690556002820180546fffffffffffffffffffffffffffffffff8088167fffffffffffffffffffffffffffffffff0000000000000000000000000000000090921691909117909155825481831670010000000000000000000000000000000002911617825592506116ed6000612d79565b60408051838152602081018690529081018490527fdeb58d7180330f713ed3023619d340a8f4f264aee7cd0707f8997ce863182e999060600160405180910390a1505061173a6001600055565b9091565b60608142111561177a576040517f203d82d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611787876001610f07565b50509050858110156117cf576040517fd28d3eb500000000000000000000000000000000000000000000000000000000815260048101879052602481018290526044016106b4565b61181173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001633308a612dd1565b61184a60008286825b6040519080825280601f01601f191660200182016040528015611844576020820181803683370190505b5061066e565b6040805160028082526060820183529091602083019080368337019050509150868260008151811061187e5761187e613a55565b602002602001018181525050808260018151811061189e5761189e613a55565b6020026020010181815250505095945050505050565b6118bc612b2c565b61060e81612e17565b6040517fd623472500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6118ff612b2c565b611907612e8e565b6119116000612e17565b61191b6000612e97565b565b60048054600091611a4e9161193490600190613a42565b8154811061194457611944613a55565b60009182526020918290206040805161018081018252600590930290910180546fffffffffffffffffffffffffffffffff808216855270010000000000000000000000000000000091829004811695850195909552600182015480861693850193909352918290048416606084015260028101548085166080850152829004841660a0840152600381015493841660c084015267ffffffffffffffff918404821660e084015278010000000000000000000000000000000000000000000000009093041661010082015260049091015463ffffffff80821661012084015264010000000082041661014083015260ff6801000000000000000090910416151561016082015261271a565b905090565b6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081018290526101608101919091526004546000819003611ac4575090565b60048054611ad490600190613a42565b815481106112be576112be613a55565b6000806000806001600480549050611afc9190613a42565b9050600060048281548110611b1357611b13613a55565b60009182526020918290206040805161018081018252600590930290910180546fffffffffffffffffffffffffffffffff8082168552700100000000000000000000000000000000918290048116958501869052600183015480821694860194909452928190048316606085015260028201548084166080860152819004831660a0850152600382015492831660c085015267ffffffffffffffff908304811660e085015278010000000000000000000000000000000000000000000000009092049091166101008301526004015463ffffffff80821661012084015264010000000082041661014083015260ff680100000000000000009091041615156101608201529150611c24908290612955565b9450945094505050909192565b606081421115611c6d576040517f203d82d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611c7888611d7a565b5050905086811115611cc0576040517f4c67496b00000000000000000000000000000000000000000000000000000000815260048101889052602481018290526044016106b4565b611d0273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016333084612dd1565b611d0f600089868261181a565b60408051600280825260608201835290916020830190803683370190505091508082600081518110611d4357611d43613a55565b6020026020010181815250508782600181518110611d6357611d63613a55565b602002602001018181525050509695505050505050565b6000806000806001600480549050611d929190613a42565b9050600060048281548110611da957611da9613a55565b60009182526020918290206040805161018081018252600590930290910180546fffffffffffffffffffffffffffffffff808216855270010000000000000000000000000000000091829004811695850195909552600182015480861693850193909352918290048416606084015260028101548085166080850152829004841660a0840152600381015493841660c084015267ffffffffffffffff918404821660e084015278010000000000000000000000000000000000000000000000009093041661010082015260049091015463ffffffff80821661012084015264010000000082041661014083015260ff680100000000000000009091041615156101608201529050611eba8187612955565b91989097509095509350505050565b60048181548110611ed957600080fd5b6000918252602090912060059091020180546001820154600283015460038401546004909401546fffffffffffffffffffffffffffffffff8085169650700100000000000000000000000000000000948590048116958185169594859004821694828516948190048316939282169290820467ffffffffffffffff9081169278010000000000000000000000000000000000000000000000009004169063ffffffff8082169164010000000081049091169068010000000000000000900460ff168c565b6000611fa761288c565b611faf612b2c565b42611fc060c0840160a08501613bc4565b63ffffffff161015611ffe576040517f203d82d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6305f5e1006120106020840184613bdf565b6fffffffffffffffffffffffffffffffff16101561205a576040517fc60f14dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61206a6060830160408401613bdf565b6fffffffffffffffffffffffffffffffff1661208c6040840160208501613bdf565b6fffffffffffffffffffffffffffffffff1610156120d6576040517f501b4f1500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6120e66060830160408401613bdf565b6fffffffffffffffffffffffffffffffff1615801561211c575061211060a0830160808401613bfa565b67ffffffffffffffff16155b15612153576040517fcdcc1fea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5060045480156122bd576000600461216c600184613a42565b8154811061217c5761217c613a55565b60009182526020918290206040805161018081018252600590930290910180546fffffffffffffffffffffffffffffffff808216855270010000000000000000000000000000000091829004811695850195909552600182015480861693850193909352918290048416606084015260028101548085166080850152829004841660a0840152600381015493841660c084015267ffffffffffffffff918404821660e084015278010000000000000000000000000000000000000000000000009093041661010082015260049091015463ffffffff80821661012084015264010000000082041661014083015260ff68010000000000000000909104161580156101608301529091506122bb576040517f800eee7100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b604080516101808101909152600490806122da6020860186613bdf565b6fffffffffffffffffffffffffffffffff16815260209081019061230090860186613bdf565b6fffffffffffffffffffffffffffffffff16815260200160006fffffffffffffffffffffffffffffffff16815260200160006fffffffffffffffffffffffffffffffff16815260200160006fffffffffffffffffffffffffffffffff1681526020018460200160208101906123759190613bdf565b6fffffffffffffffffffffffffffffffff16815260200161239c6060860160408701613bdf565b6fffffffffffffffffffffffffffffffff1681526020016123c36080860160608701613bfa565b67ffffffffffffffff1681526020016123e260a0860160808701613bfa565b67ffffffffffffffff16815263ffffffff4216602082015260400161240d60c0860160a08701613bc4565b63ffffffff908116825260016020928301819052845480820186556000958652948390208451858501516fffffffffffffffffffffffffffffffff91821670010000000000000000000000000000000091831682021760059098029092019687556040860151606087015190821690821683021792870192909255608085015160a0860151908316908316820217600287015560c085015160038701805460e0880151610100890151939095167fffffffffffffffff0000000000000000000000000000000000000000000000009091161767ffffffffffffffff9485169093029290921777ffffffffffffffffffffffffffffffffffffffffffffffff167801000000000000000000000000000000000000000000000000939091169290920291909117905561012083015160049094018054610140850151610160909501519583167fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000909116176401000000009490921693909302177fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff1668010000000000000000931515939093029290921790557f49f979d434de33c8feec553b9de34d0b7b5ee6a11f0df00c3b60c742ae17f1679082906125ee90850185613bdf565b6125fe6040860160208701613bdf565b61260e6060870160408801613bdf565b61261e6080880160608901613bfa565b61262e60a0890160808a01613bfa565b61263e60c08a0160a08b01613bc4565b604080519788526fffffffffffffffffffffffffffffffff96871660208901529486168786015292909416606086015267ffffffffffffffff908116608086015290921660a084015263ffffffff90911660c0830152519081900360e00190a16126a86001612d79565b61270b33306126ba6020860186613bdf565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169291906fffffffffffffffffffffffffffffffff16612dd1565b6127156001600055565b919050565b60008082610120015163ffffffff16426127349190613a42565b8360e0015167ffffffffffffffff1661274d9190613b5f565b9050808360a001516fffffffffffffffffffffffffffffffff16101561278857505060c001516fffffffffffffffffffffffffffffffff1690565b808360a001516fffffffffffffffffffffffffffffffff166127aa9190613a42565b91508260c001516fffffffffffffffffffffffffffffffff168210156127e4578260c001516fffffffffffffffffffffffffffffffff1691505b50919050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614612871576040517fd70f29d200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611240836000610f07565b612884612e8e565b61191b612f25565b6002600054036128c8576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002600055565b60405173ffffffffffffffffffffffffffffffffffffffff83811660248301526044820183905261295091859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050612f56565b505050565b6000806000846101600151612996576040517f69b8d0fe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84610140015163ffffffff1642106129da576040517f04a5e67c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84602001516fffffffffffffffffffffffffffffffff16841115612a2a576040517ffc43992200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612a358661271a565b9050670de0b6b3a764000086610100015167ffffffffffffffff1686612a5b9190613b5f565b612a659190613b76565b612a7790670de0b6b3a7640000613a42565b612a818287613b5f565b612a8b9190613b76565b9350670de0b6b3a76400008487610100015167ffffffffffffffff16612ab19190613b5f565b612abb9190613b76565b9250612ac8836002613b5f565b612ad29082613bb1565b9150509250925092565b60006fffffffffffffffffffffffffffffffff821115612b28576040517f35278d1200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5090565b61191b33612fec565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009073ffffffffffffffffffffffffffffffffffffffff8516906370a0823190602401602060405180830381865afa158015612ba2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bc69190613ac9565b905082811115610e08576000612bdc8483613a42565b90508215612d51576004805460009190612bf890600190613a42565b81548110612c0857612c08613a55565b906000526020600020906005020190507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1603612cd557612c7482612adc565b600182018054600090612c9a9084906fffffffffffffffffffffffffffffffff16613c15565b92506101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff160217905550612d4f565b612cde82612adc565b600182018054601090612d1890849070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16613c15565b92506101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055505b505b612d7273ffffffffffffffffffffffffffffffffffffffff861633836128cf565b5050505050565b612da57f0000000000000000000000000000000000000000000000000000000000000000600083612b35565b61060e7f0000000000000000000000000000000000000000000000000000000000000000600083612b35565b60405173ffffffffffffffffffffffffffffffffffffffff8481166024830152838116604483015260648201839052610e089186918216906323b872dd90608401612909565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff838116918217909255600254604051919216907f162998b90abc2507f3953aa797827b03a14c42dbd9a35f09feaf02e0d592773a90600090a350565b61191b33613064565b60025460405173ffffffffffffffffffffffffffffffffffffffff8084169216907f31b6c5a04b069b6ec1b3cef44c4e7c1eadd721349cda9823d0b1877b3551cdc690600090a3600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b600180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905561191b33612e97565b6000612f7873ffffffffffffffffffffffffffffffffffffffff8416836130dc565b90508051600014158015612f9d575080806020019051810190612f9b9190613c3e565b155b15612950576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff841660048201526024016106b4565b60025473ffffffffffffffffffffffffffffffffffffffff82811691161461060e576002546040517f443dc2b400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff918216600482015290821660248201526044016106b4565b60015473ffffffffffffffffffffffffffffffffffffffff82811691161461060e576001546040517fbe5a953700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff918216600482015290821660248201526044016106b4565b60606130ea838360006130f3565b90505b92915050565b606081471015613131576040517fcd7860590000000000000000000000000000000000000000000000000000000081523060048201526024016106b4565b6000808573ffffffffffffffffffffffffffffffffffffffff16848660405161315a9190613c5b565b60006040518083038185875af1925050503d8060008114613197576040519150601f19603f3d011682016040523d82523d6000602084013e61319c565b606091505b50915091506131ac8683836131b8565b925050505b9392505050565b6060826131cd576131c882613247565b6131b1565b81511580156131f1575073ffffffffffffffffffffffffffffffffffffffff84163b155b15613240576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff851660048201526024016106b4565b50806131b1565b8051156132575780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b803573ffffffffffffffffffffffffffffffffffffffff8116811461271557600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610180810167ffffffffffffffff81118282101715613300576133006132ad565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561334d5761334d6132ad565b604052919050565b6000806000806080858703121561336b57600080fd5b84359350602080860135935061338360408701613289565b9250606086013567ffffffffffffffff808211156133a057600080fd5b818801915088601f8301126133b457600080fd5b8135818111156133c6576133c66132ad565b6133f6847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601613306565b9150808252898482850101111561340c57600080fd5b808484018584013760008482840101525080935050505092959194509250565b60008060006060848603121561344157600080fd5b505081359360208301359350604090920135919050565b60005b8381101561347357818101518382015260200161345b565b50506000910152565b60008151808452613494816020860160208601613458565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006130ea602083018461347c565b801515811461060e57600080fd5b8035612715816134d9565b6000806040838503121561350557600080fd5b823591506020830135613517816134d9565b809150509250929050565b6000806040838503121561353557600080fd5b8235915061354560208401613289565b90509250929050565b60006020828403121561356057600080fd5b5035919050565b81516fffffffffffffffffffffffffffffffff168152610180810160208301516135a560208401826fffffffffffffffffffffffffffffffff169052565b5060408301516135c960408401826fffffffffffffffffffffffffffffffff169052565b5060608301516135ed60608401826fffffffffffffffffffffffffffffffff169052565b50608083015161361160808401826fffffffffffffffffffffffffffffffff169052565b5060a083015161363560a08401826fffffffffffffffffffffffffffffffff169052565b5060c083015161365960c08401826fffffffffffffffffffffffffffffffff169052565b5060e083015161367560e084018267ffffffffffffffff169052565b506101008381015167ffffffffffffffff16908301526101208084015163ffffffff908116918401919091526101408085015190911690830152610160928301511515929091019190915290565b600080600080600060a086880312156136db57600080fd5b853594506020808701359450604087013567ffffffffffffffff8082111561370257600080fd5b818901915089601f83011261371657600080fd5b813581811115613728576137286132ad565b8060051b9150613739848301613306565b818152918301840191848101908c84111561375357600080fd5b938501935b838510156137785761376985613289565b82529385019390850190613758565b80985050505050505061378d60608701613289565b949793965091946080013592915050565b6020808252825182820181905260009190848201906040850190845b818110156137d6578351835292840192918401916001016137ba565b50909695505050505050565b6000602082840312156137f457600080fd5b6130ea82613289565b6000806040838503121561381057600080fd5b61381983613289565b915061354560208401613289565b60008060008060008060a0878903121561384057600080fd5b8635955060208701359450604087013567ffffffffffffffff8082111561386657600080fd5b818901915089601f83011261387a57600080fd5b81358181111561388957600080fd5b8a60208260051b850101111561389e57600080fd5b6020830196508095505050506138b660608801613289565b9150608087013590509295509295509295565b600060c082840312156127e457600080fd5b80356fffffffffffffffffffffffffffffffff8116811461271557600080fd5b803567ffffffffffffffff8116811461271557600080fd5b803563ffffffff8116811461271557600080fd5b6000610180828403121561393a57600080fd5b6139426132dc565b61394b836138db565b8152613959602084016138db565b602082015261396a604084016138db565b604082015261397b606084016138db565b606082015261398c608084016138db565b608082015261399d60a084016138db565b60a08201526139ae60c084016138db565b60c08201526139bf60e084016138fb565b60e08201526101006139d28185016138fb565b908201526101206139e4848201613913565b908201526101406139f6848201613913565b90820152610160613a088482016134e7565b908201529392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b818103818111156130ed576130ed613a13565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b73ffffffffffffffffffffffffffffffffffffffff85168152836020820152826040820152608060608201526000613abf608083018461347c565b9695505050505050565b600060208284031215613adb57600080fd5b5051919050565b6fffffffffffffffffffffffffffffffff828116828216039080821115613b0b57613b0b613a13565b5092915050565b600181811c90821680613b2657607f821691505b6020821081036127e4577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b80820281158282048414176130ed576130ed613a13565b600082613bac577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b808201808211156130ed576130ed613a13565b600060208284031215613bd657600080fd5b6130ea82613913565b600060208284031215613bf157600080fd5b6130ea826138db565b600060208284031215613c0c57600080fd5b6130ea826138fb565b6fffffffffffffffffffffffffffffffff818116838216019080821115613b0b57613b0b613a13565b600060208284031215613c5057600080fd5b81516131b1816134d9565b60008251613c6d818460208701613458565b919091019291505056fea26469706673582212208ec73c478f099ff03b90c422145c33e3f767a8e355a0920077a210d2face11b464736f6c63430008180033a264697066735822122008314d1a0b5ae7db8d9a1f179674d616184fe6eedf0080a52177b51be77ed77364736f6c63430008180033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in FRAX
0
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.