Source Code
Latest 25 from a total of 66 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Claim Order | 10274645 | 465 days ago | IN | 0.009 ETH | 0.00000037 | ||||
| Claim Order | 10274642 | 465 days ago | IN | 0.009 ETH | 0.00000037 | ||||
| Cancel Order | 10274634 | 465 days ago | IN | 0 ETH | 0.00000115 | ||||
| Cancel Order | 10274631 | 465 days ago | IN | 0 ETH | 0.00000118 | ||||
| Cancel Order | 7420525 | 531 days ago | IN | 0 ETH | 0.00000011 | ||||
| Cancel Order | 7420524 | 531 days ago | IN | 0 ETH | 0.00000083 | ||||
| Claim Order | 7129068 | 538 days ago | IN | 0.0003 ETH | 0.00000011 | ||||
| Claim Order | 5470800 | 576 days ago | IN | 0.0003 ETH | 0.00000086 | ||||
| Cancel Order | 5397282 | 578 days ago | IN | 0 ETH | 0.00000317 | ||||
| New Order | 5378142 | 578 days ago | IN | 0 ETH | 0.0000074 | ||||
| New Order | 5378095 | 578 days ago | IN | 0 ETH | 0.00000698 | ||||
| New Order | 5283087 | 580 days ago | IN | 0 ETH | 0.00000548 | ||||
| New Order | 5283065 | 580 days ago | IN | 0 ETH | 0.00000599 | ||||
| New Order | 5283055 | 580 days ago | IN | 0 ETH | 0.00000559 | ||||
| Cancel Order | 5282640 | 580 days ago | IN | 0 ETH | 0.00000252 | ||||
| Cancel Order | 5282637 | 580 days ago | IN | 0 ETH | 0.00000258 | ||||
| Cancel Order | 5282635 | 580 days ago | IN | 0 ETH | 0.00000255 | ||||
| New Order | 5281794 | 580 days ago | IN | 0 ETH | 0.00000601 | ||||
| New Order | 5281776 | 580 days ago | IN | 0 ETH | 0.00000619 | ||||
| New Order | 5281757 | 580 days ago | IN | 0 ETH | 0.00000564 | ||||
| Setup Limit Orde... | 5281655 | 580 days ago | IN | 0 ETH | 0.00000072 | ||||
| Setup Limit Orde... | 5281650 | 580 days ago | IN | 0 ETH | 0.00000072 | ||||
| Setup Limit Orde... | 5281645 | 580 days ago | IN | 0 ETH | 0.00000073 | ||||
| Setup Limit Orde... | 5281640 | 580 days ago | IN | 0 ETH | 0.00000073 | ||||
| Setup Limit Orde... | 5281635 | 580 days ago | IN | 0 ETH | 0.00000073 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Cross-Chain Transactions
Loading...
Loading
Contract Name:
LimitOrderRegistry
Compiler Version
v0.8.16+commit.07a7930e
Optimization Enabled:
Yes with 200 runs
Other Settings:
london EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;
// Used to interact with ERC20 tokens
import { ERC20 } from "@solmate/tokens/ERC20.sol";
// Used to perform the safeTransfer
import { SafeTransferLib } from "@solmate/utils/SafeTransferLib.sol";
// Used for chainlink automation
import { AutomationCompatibleInterface } from "@chainlink/contracts/src/v0.8/interfaces/AutomationCompatibleInterface.sol";
// used to have an owner for our contract
import { Owned } from "@solmate/auth/Owned.sol";
// for interacting with uniswap pools,
import { UniswapV3Pool } from "src/interfaces/uniswapV3/UniswapV3Pool.sol";
// for creating uniswap NFT positions
import { NonFungiblePositionManager } from "src/interfaces/uniswapV3/NonFungiblePositionManager.sol";
// dealing with NFTs
import { ERC721Holder } from "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol";
// used to maintain upkeep
import { LinkTokenInterface } from "@chainlink/contracts/src/v0.8/interfaces/LinkTokenInterface.sol";
// keeper for chainlink automation
import { IKeeperRegistrar, RegistrationParams } from "src/interfaces/chainlink/IKeeperRegistrar.sol";
// used to define _msgSender() for future metatransaction support
import { Context } from "@openzeppelin/contracts/utils/Context.sol";
// used to get the gas price from the chainlink gas oracle
import { IChainlinkAggregator } from "src/interfaces/chainlink/IChainlinkAggregator.sol";
/**
* @title Limit Order Registry
* @notice Allows users to create decentralized limit orders.
* @dev DO NOT PLACE LIMIT ORDERS FOR STRONGLY CORRELATED ASSETS.
* - If a stable coin pair were to temporarily depeg, and a user places a limit order
* whose tick range encompasses the normal trading tick, there is NO way to cancel the order
* because the order is mixed. The user would have to wait for another depeg event to happen
* so that the order can be fulfilled, or the order can be cancelled.
* @author crispymangoes
*/
contract LimitOrderRegistry is Owned, AutomationCompatibleInterface, ERC721Holder, Context {
using SafeTransferLib for ERC20;
using SafeTransferLib for address;
/*//////////////////////////////////////////////////////////////
STRUCTS
//////////////////////////////////////////////////////////////*/
/**
* @notice Stores linked list center values, and frequently used pool values.
* @param centerHead Linked list center value closer to head of the list
* @param centerTail Linked list center value closer to tail of the list
* @param token0 ERC20 token0 of the pool
* @param token1 ERC20 token1 of the pool
* @param fee Uniswap V3 pool fee
*/
struct PoolData {
uint256 centerHead;
uint256 centerTail;
ERC20 token0;
ERC20 token1;
uint24 fee;
}
/**
* @notice Stores information about batches of orders.
* @dev User orders can be batched together if they share the same target price.
* @param direction Determines what direction the tick must move in order for the order to be filled
* - true, pool tick must INCREASE to fill this order
* - false, pool tick must DECREASE to fill this order
* @param tickUpper The upper tick of the underlying LP position
* @param tickLower The lower tick of the underlying LP position
* @param userCount The number of users in this batch order
* @param batchId Unique id used to distinguish this batch order from another batch order in the past that used the same LP position
* @param token0Amount The amount of token0 in this order
* @param token1Amount The amount of token1 in this order
* @param head The next node in the linked list when moving toward the head
* @param tail The next node in the linked list when moving toward the tail
*/
struct BatchOrder {
bool direction;
int24 tickUpper;
int24 tickLower;
uint64 userCount;
uint128 batchId;
uint128 token0Amount;
uint128 token1Amount;
uint256 head;
uint256 tail;
}
/**
* @notice Stores information needed for users to make claims.
* @param pool The Uniswap V3 pool the batch order was in
* @param token0Amount The amount of token0 in the order
* @param token1Amount The amount of token1 in the order
* @param feePerUser The native token fee that must be paid on order claiming
* @param direction The underlying order direction, used to determine input/output token of the order
* @param isReadyForClaim Explicit bool indicating whether or not this order is ready to be claimed
*/
struct Claim {
UniswapV3Pool pool;
uint128 token0Amount; //Can either be the deposit amount or the amount got out of liquidity changing to the other token
uint128 token1Amount;
uint128 feePerUser; // Fee in terms of network native asset.
bool direction; //Determines the token out
bool isReadyForClaim;
}
/**
* @notice Struct used to store variables needed during order creation.
* @param tick The target tick of the order
* @param upper The upper tick of the underlying LP position
* @param lower The lower tick of the underlying LP position
* @param userTotal The total amount of assets the user has in the order
* @param positionId The underling LP position token id this order is adding liquidity to
* @param amount0 Can be the amount of assets user added to the order, based off orders direction
* @param amount1 Can be the amount of assets user added to the order, based off orders direction
*/
struct OrderDetails {
int24 tick;
int24 upper;
int24 lower;
uint128 userTotal;
uint256 positionId;
uint128 amount0;
uint128 amount1;
}
/*//////////////////////////////////////////////////////////////
GLOBAL STATE
//////////////////////////////////////////////////////////////*/
/**
* @notice Stores swap fees earned from limit order where the input token earns swap fees.
*/
mapping(address => uint256) public tokenToSwapFees;
/**
* @notice Used to store claim information needed when users are claiming their orders.
*/
mapping(uint128 => Claim) public claim;
/**
* @notice Stores the pools center head/tail, as well as frequently read values.
*/
mapping(UniswapV3Pool => PoolData) public poolToData;
/**
* @notice Maps tick ranges to LP positions owned by this contract.
* @dev maps pool -> direction -> lower -> upper -> positionId
*/
mapping(UniswapV3Pool => mapping(bool => mapping(int24 => mapping(int24 => uint256)))) public getPositionFromTicks;
/**
* @notice The minimum amount of assets required to create a `newOrder`.
* @dev Changeable by owner.
*/
mapping(ERC20 => uint256) public minimumAssets;
/**
* @notice Approximated amount of gas needed to fulfill 1 BatchOrder.
* @dev Changeable by owner.
*/
uint32 public upkeepGasLimit = 300_000;
/**
* @notice Approximated gas price used to fulfill orders.
* @dev Changeable by owner.
*/
uint32 public upkeepGasPrice = 30;
/**
* @notice Max number of orders that can be filled in 1 upkeep call.
* @dev Changeable by owner.
*/
uint16 public maxFillsPerUpkeep = 10;
/**
* @notice Value is incremented whenever a new BatchOrder is added to the `orderBook`.
* @dev Zero is reserved.
*/
uint128 public batchCount = 1;
/**
* @notice Mapping is used to store user deposit amounts in each BatchOrder.
*/
mapping(uint128 => mapping(address => uint128)) public batchIdToUserDepositAmount;
/**
* @notice The `orderBook` maps Uniswap V3 token ids to BatchOrder information.
* @dev Each BatchOrder contains a head and tail value which effectively,
* which means BatchOrders are connected using a doubly linked list.
*/
mapping(uint256 => BatchOrder) public orderBook;
/**
* @notice Chainlink Automation Registrar contract.
*/
IKeeperRegistrar public registrar;
/**
* @notice Whether or not the contract is shutdown in case of an emergency.
*/
bool public isShutdown;
/**
* @notice Chainlink Fast Gas Feed.
* @dev Feed for ETH Mainnet 0x169E633A2D1E6c10dD91238Ba11c4A708dfEF37C.
*/
address public fastGasFeed;
/**
* @notice The max possible gas the owner can set for the gas limit.
*/
uint32 public constant MAX_GAS_LIMIT = 750_000;
/**
* @notice The max possible gas price the owner can set for the gas price.
* @dev In units of gwei.
*/
uint32 public constant MAX_GAS_PRICE = 1_000;
/**
* @notice The max number of orders that can be fulfilled in a single upkeep TX.
*/
uint16 public constant MAX_FILLS_PER_UPKEEP = 20;
/**
* @notice The ETH Fast Gas Feed heartbeat.
* @dev If answer is stale, owner set gas price is used.
*/
uint256 public constant FAST_GAS_HEARTBEAT = 7200;
/**
* @notice Function signature used to create V1 Upkeep versions.
*/
string private constant FUNC_SIGNATURE = "register(string,bytes,address,uint32,address,bytes,uint96,uint8,address)";
/**
* @notice Function selector used to create V1 Upkeep versions.
*/
bytes4 private constant FUNC_SELECTOR = bytes4(keccak256(bytes(FUNC_SIGNATURE)));
/*//////////////////////////////////////////////////////////////
MODIFIERS
//////////////////////////////////////////////////////////////*/
/**
* @notice Prevent a function from being called during a shutdown.
*/
modifier whenNotShutdown() {
if (isShutdown) revert LimitOrderRegistry__ContractShutdown();
_;
}
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
// On new limit order created
event NewOrder(address user, address pool, uint128 amount, uint128 userTotal, BatchOrder affectedOrder);
// On limit order claimed
event ClaimOrder(address user, uint128 batchId, uint256 amount);
// On limit order cancelled
event CancelOrder(address user, uint128 amount0, uint128 amount1, BatchOrder affectedOrder);
// On limit order filled
event OrderFilled(uint256 batchId, address pool);
// On change of shutdown condition
event ShutdownChanged(bool isShutdown);
// On setup of limit order for the pool
event LimitOrderSetup(address pool);
/*//////////////////////////////////////////////////////////////
ERRORS
//////////////////////////////////////////////////////////////*/
// @notice When attempting to submit an order that is ITM
error LimitOrderRegistry__OrderITM(int24 currentTick, int24 targetTick, bool direction);
// @notice When attempting to setup a pool that is already setup
error LimitOrderRegistry__PoolAlreadySetup(address pool);
// @notice When pool is not setup and one tries to make an order
error LimitOrderRegistry__PoolNotSetup(address pool);
// @notice When an invalid target tick is provided for creating an order
error LimitOrderRegistry__InvalidTargetTick(int24 targetTick, int24 tickSpacing);
// @notice When the user for the batchid is not found
error LimitOrderRegistry__UserNotFound(address user, uint256 batchId);
// @notice When the position id is invalid
error LimitOrderRegistry__InvalidPositionId();
// @notice When there is no liquidity in the order
error LimitOrderRegistry__NoLiquidityInOrder();
// @notice When there are no orders to fulfill
error LimitOrderRegistry__NoOrdersToFulfill();
// @notice When the center is ITM
error LimitOrderRegistry__CenterITM();
// @notice When the order does not appear in the linked list
error LimitOrderRegistry__OrderNotInList(uint256 tokenId);
// @notice When the minimum for the asset is not set
error LimitOrderRegistry__MinimumNotSet(address asset);
// @notice When the minimum for the asset is not met
error LimitOrderRegistry__MinimumNotMet(address asset, uint256 minimum, uint256 amount);
// @notice When the tick range specified is incorrect
error LimitOrderRegistry__InvalidTickRange(int24 upper, int24 lower);
// @notice When there are no fees to withdraw
error LimitOrderRegistry__ZeroFeesToWithdraw(address token);
// @notice When there is no native balance to withdraw
error LimitOrderRegistry__ZeroNativeBalance();
// @notice When an invalid batch id is provided
error LimitOrderRegistry__InvalidBatchId();
// @notice When the order is not yet ready to claim
error LimitOrderRegistry__OrderNotReadyToClaim(uint128 batchId);
// @notice When the contract is shutdown and actions are performed
error LimitOrderRegistry__ContractShutdown();
// @notice When the contract is not shutdown and shutdown is attempted to be ended
error LimitOrderRegistry__ContractNotShutdown();
// @notice When an invalid gas limit, above the max, is provided
error LimitOrderRegistry__InvalidGasLimit();
// @notice When an invalid gas price, above the max, is provided
error LimitOrderRegistry__InvalidGasPrice();
// @notice When the fills for the upkeep are invalid
error LimitOrderRegistry__InvalidFillsPerUpkeep();
// @notice When amounts should be 0 but is not
error LimitOrderRegistry__AmountShouldBeZero();
// @notice When direction for the order doesn't match what state has.
error LimitOrderRegistry__DirectionMisMatch();
/*//////////////////////////////////////////////////////////////
ENUMS
//////////////////////////////////////////////////////////////*/
// @notice OrderStatus is used to show the status of an order
enum OrderStatus {
// When the order is through the book, it is considered ITM. this means that either the order was filled, or it should not exist.
ITM,
// When an order is not yet filled, it is considered OTM.
OTM,
// When the current tick is within the ticks of the limit order, it is considered MIXED.
MIXED
}
/*//////////////////////////////////////////////////////////////
IMMUTABLES
//////////////////////////////////////////////////////////////*/
// @notice the token addres of the wrapped native token
ERC20 public immutable WRAPPED_NATIVE; // Mainnet 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
// @notice the address of the position manager
NonFungiblePositionManager public immutable POSITION_MANAGER; // Mainnet 0xC36442b4a4522E871399CD717aBDD847Ab11FE88
// @notice the address of the link token
LinkTokenInterface public immutable LINK; // Mainnet 0x514910771AF9Ca656af840dff83E8264EcF986CA
constructor(
address _owner,
NonFungiblePositionManager _positionManager,
ERC20 wrappedNative,
LinkTokenInterface link,
IKeeperRegistrar _registrar,
address _fastGasFeed
) Owned(_owner) {
POSITION_MANAGER = _positionManager;
WRAPPED_NATIVE = wrappedNative;
LINK = link;
registrar = _registrar;
fastGasFeed = _fastGasFeed;
}
/*//////////////////////////////////////////////////////////////
OWNER LOGIC
//////////////////////////////////////////////////////////////*/
/**
* @notice No input validation is done because it is in the owners best interest to choose a valid registrar.
*/
function setRegistrar(IKeeperRegistrar _registrar) external onlyOwner {
registrar = _registrar;
}
/**
* @notice Allows owner to set the fills per upkeep.
*/
function setMaxFillsPerUpkeep(uint16 newVal) external onlyOwner {
if (newVal == 0 || newVal > MAX_FILLS_PER_UPKEEP) revert LimitOrderRegistry__InvalidFillsPerUpkeep();
maxFillsPerUpkeep = newVal;
}
/**
* @notice Allows owner to setup a new limit order for a new pool.
* @param pool The uniswap v3 pool to setup limit orders for
* @param initialUpkeepFunds the amount of initial upkeep funds to provide for the pool
* @dev New Limit orders, should have a keeper to fulfill orders.
* @dev If `initialUpkeepFunds` is zero, upkeep creation is skipped.
*/
function setupLimitOrder(UniswapV3Pool pool, uint256 initialUpkeepFunds) external onlyOwner {
// Check if Limit Order is already setup for `pool`.
if (address(poolToData[pool].token0) != address(0)) revert LimitOrderRegistry__PoolAlreadySetup(address(pool));
// Create Upkeep, transfering funds only if initialUpkeepFunds is above 0.
if (initialUpkeepFunds > 0) {
// Owner wants to automatically create an upkeep for new pool.
ERC20(address(LINK)).safeTransferFrom(owner, address(this), initialUpkeepFunds);
// check the upkeep registration version
if (bytes(registrar.typeAndVersion())[16] == bytes("1")[0]) {
// Use V1 Upkeep Registration.
bytes memory data = abi.encodeWithSelector(
FUNC_SELECTOR,
"Limit Order Registry",
abi.encode(0),
address(this),
uint32(maxFillsPerUpkeep * upkeepGasLimit),
owner,
abi.encode(pool),
uint96(initialUpkeepFunds),
77,
address(this)
);
LINK.transferAndCall(address(registrar), initialUpkeepFunds, data);
} else {
// Use V2 Upkeep Registration.
ERC20(address(LINK)).safeApprove(address(registrar), initialUpkeepFunds);
RegistrationParams memory params = RegistrationParams({
name: "Limit Order Registry",
encryptedEmail: abi.encode(0),
upkeepContract: address(this),
gasLimit: uint32(maxFillsPerUpkeep * upkeepGasLimit),
adminAddress: owner,
checkData: abi.encode(pool),
offchainConfig: abi.encode(0),
amount: uint96(initialUpkeepFunds)
});
registrar.registerUpkeep(params);
}
}
// initialize the data for the pool. the center and tail of the linked list are 0, while the tokens and fees are set to the correct
// ones for the pool
poolToData[pool] = PoolData({
centerHead: 0,
centerTail: 0,
token0: ERC20(pool.token0()),
token1: ERC20(pool.token1()),
fee: pool.fee()
});
emit LimitOrderSetup(address(pool));
}
/**
* @notice Allows owner to set the minimum assets used to create `newOrder`s.
* @param amount the amount to set minimum assets for the token to
* @param asset the erc20 token address to set minimum assets for
* @dev This value can be zero, but then this contract can be griefed by an attacker spamming low liquidity orders.
*/
function setMinimumAssets(uint256 amount, ERC20 asset) external onlyOwner {
minimumAssets[asset] = amount;
}
/**
* @notice Allows owner to change the gas limit value used to determine the Native asset fee needed to claim orders.
* @param gasLimit the gas limit that the upkeepGasLimit will be set to
* @dev premium should be factored into this value.
*/
function setUpkeepGasLimit(uint32 gasLimit) external onlyOwner {
// should revert if the gas limit provided is greater than the provided max gas limit.
if (gasLimit > MAX_GAS_LIMIT) revert LimitOrderRegistry__InvalidGasLimit();
upkeepGasLimit = gasLimit;
}
/**
* @notice Allows owner to change the gas price used to determine the Native asset fee needed to claim orders.
* @param gasPrice the gas limit that the upkeepGasPrice will be set to
* @dev `gasPrice` uses units of gwei.
*/
function setUpkeepGasPrice(uint32 gasPrice) external onlyOwner {
// should revert if the gas price provided is greater than the provided max gas price.
if (gasPrice > MAX_GAS_PRICE) revert LimitOrderRegistry__InvalidGasPrice();
upkeepGasPrice = gasPrice;
}
/**
* @notice Allows owner to set the fast gas feed.
* @param feed the address of the chainlink-compatible gas oracle
* @dev The feed should be a chainlink-compatible gas oracle
*/
function setFastGasFeed(address feed) external onlyOwner {
fastGasFeed = feed;
}
/**
* @notice Allows owner to withdraw swap fees earned from the input token of orders.
* @param tokenFeeIsIn the address of the token fee.
*/
function withdrawSwapFees(address tokenFeeIsIn) external onlyOwner {
uint256 fee = tokenToSwapFees[tokenFeeIsIn];
// Make sure there are actually fees to withdraw;
if (fee == 0) revert LimitOrderRegistry__ZeroFeesToWithdraw(tokenFeeIsIn);
// set fees to 0
tokenToSwapFees[tokenFeeIsIn] = 0;
// transfer fees to the user
ERC20(tokenFeeIsIn).safeTransfer(owner, fee);
}
/**
* @notice Allows owner to withdraw wrapped native and native assets from this contract.
*/
function withdrawNative() external onlyOwner {
uint256 wrappedNativeBalance = WRAPPED_NATIVE.balanceOf(address(this));
uint256 nativeBalance = address(this).balance;
// Make sure there is something to withdraw.
if (wrappedNativeBalance == 0 && nativeBalance == 0) revert LimitOrderRegistry__ZeroNativeBalance();
// transfer wrappedNativeBalance if it exists
if (wrappedNativeBalance > 0) WRAPPED_NATIVE.safeTransfer(owner, wrappedNativeBalance);
// transfer nativeBalance if it exists
if (nativeBalance > 0) owner.safeTransferETH(nativeBalance);
}
/**
* @notice Shutdown the registry. Used in an emergency or if the registry has been deprecated.
*/
function initiateShutdown() external whenNotShutdown onlyOwner {
isShutdown = true;
emit ShutdownChanged(true);
}
/**
* @notice Restart the registry.
*/
function liftShutdown() external onlyOwner {
if (!isShutdown) revert LimitOrderRegistry__ContractNotShutdown();
isShutdown = false;
emit ShutdownChanged(false);
}
/*//////////////////////////////////////////////////////////////
USER ORDER MANAGEMENT LOGIC
//////////////////////////////////////////////////////////////*/
/**
* @notice Creates a new limit order for a specific pool.
* @dev Limit orders can be created to buy either token0, or token1 of the pool.
* @param pool the Uniswap V3 pool to create a limit order on.
* @param targetTick the tick, that when `pool`'s tick passes, the order will be completely fulfilled
* @param amount the amount of the input token to sell for the desired token out
* @param direction bool indicating what the desired token out is
* - true token in = token0 ; token out = token1
* - false token in = token1 ; token out = token0
* @param startingNode an NFT position id indicating where this contract should start searching for a spot in the list
* - can be zero which defaults to starting the search at center of list
* @dev reverts if
* - pool is not setup
* - targetTick is not divisible by the pools tick spacing
* - the new order would be ITM, or in a MIXED state
* - the new order does not meet minimum liquidity requirements
* - transferFrom fails
* @dev Emits a `NewOrder` event which contains meta data about the order including the orders `batchId`(which is used for claiming/cancelling).
*/
function newOrder(
UniswapV3Pool pool,
int24 targetTick,
uint128 amount,
bool direction,
uint256 startingNode,
uint256 deadline
) external whenNotShutdown returns (uint128) {
if (address(poolToData[pool].token0) == address(0)) revert LimitOrderRegistry__PoolNotSetup(address(pool));
address sender = _msgSender();
// Transfer assets into contract before setting/checking any state.
{
// if direction is true, it means that assetIn is token0
ERC20 assetIn = direction ? poolToData[pool].token0 : poolToData[pool].token1;
// we make sure that there is enough amount of the assetIn
_enforceMinimumLiquidity(amount, assetIn);
// and transfer
assetIn.safeTransferFrom(sender, address(this), amount);
}
OrderDetails memory details;
// initialize the order =details tick with the pool slot0 value
(, details.tick, , , , , ) = pool.slot0();
// Determine upper and lower ticks.
{
// we need to grab the tickspace from the pool because we must send our order so that it aligns to ticks.
int24 tickSpacing = pool.tickSpacing();
// Make sure targetTick is divisible by spacing.
if (targetTick % tickSpacing != 0) revert LimitOrderRegistry__InvalidTargetTick(targetTick, tickSpacing);
if (direction) {
// if assetIn is token0, then the limit goes from targetTick to targetTick-tickSpacing
details.upper = targetTick;
details.lower = targetTick - tickSpacing;
} else {
// if assetIn is token1, then the limit goes from targetTick to targetTick+tickSpacing
details.upper = targetTick + tickSpacing;
details.lower = targetTick;
}
}
// Validate lower, upper,and direction.
{
OrderStatus status = _getOrderStatus(details.tick, details.lower, details.upper, direction);
// forbid orders that are "ITM". basically, if your order is through the market, then instead of limit order, you should swap
if (status != OrderStatus.OTM) revert LimitOrderRegistry__OrderITM(details.tick, targetTick, direction);
}
// Get the position id. this is the underlying position that we are managing
details.positionId = getPositionFromTicks[pool][direction][details.lower][details.upper];
// the amount should match with the tokenIn, so if tokenIn is token0, then set amount0, else set amount1
if (direction) details.amount0 = amount;
else details.amount1 = amount;
// check if the position exists in the nft contract
if (details.positionId == 0) {
// Create new LP position(which adds liquidity)
PoolData memory data = poolToData[pool];
details.positionId = _mintPosition(
data,
details.upper,
details.lower,
details.amount0,
details.amount1,
direction,
deadline
);
// Add it to the list.
_addPositionToList(data, startingNode, targetTick, details.positionId, direction);
// Set new orders upper and lower tick.
orderBook[details.positionId].tickLower = details.lower;
orderBook[details.positionId].tickUpper = details.upper;
// Setup BatchOrder, setting batchId, direction.
_setupOrder(direction, details.positionId);
// Update token0Amount, token1Amount, batchIdToUserDepositAmount mapping.
details.userTotal = _updateOrder(details.positionId, sender, amount);
// Update the center values if need be.
_updateCenter(pool, details.positionId, details.tick, details.upper, details.lower);
// Update getPositionFromTicks since we have a new LP position.
getPositionFromTicks[pool][direction][details.lower][details.upper] = details.positionId;
} else {
// Check if the position id is already being used in List.
BatchOrder memory order = orderBook[details.positionId];
if (order.token0Amount > 0 || order.token1Amount > 0) {
// Check that supplied direction and order.direction are the same.
if (direction != order.direction) revert LimitOrderRegistry__DirectionMisMatch();
// Need to add liquidity.
PoolData memory data = poolToData[pool];
_addToPosition(data, details.positionId, details.amount0, details.amount1, direction, deadline);
// Update token0Amount, token1Amount, batchIdToUserDepositAmount mapping.
details.userTotal = _updateOrder(details.positionId, sender, amount);
} else {
// We already have an LP position with given tick ranges, but it is not in linked list.
PoolData memory data = poolToData[pool];
// Add it to the list.
_addPositionToList(data, startingNode, targetTick, details.positionId, direction);
// Setup BatchOrder, setting batchId, direction.
_setupOrder(direction, details.positionId);
// Need to add liquidity.
_addToPosition(data, details.positionId, details.amount0, details.amount1, direction, deadline);
// Update token0Amount, token1Amount, batchIdToUserDepositAmount mapping.
details.userTotal = _updateOrder(details.positionId, sender, amount);
// Update the center values if need be.
_updateCenter(pool, details.positionId, details.tick, details.upper, details.lower);
}
}
// emit the event
emit NewOrder(sender, address(pool), amount, details.userTotal, orderBook[details.positionId]);
// return the batch id of the position
return orderBook[details.positionId].batchId;
}
/**
* @notice Users can claim fulfilled orders by passing in the `batchId` corresponding to the order they want to claim.
* @param batchId the batchId corresponding to a fulfilled order to claim
* @param user the address of the user in the order to claim for
* @return address erc20 address
* @return uint256 amount claimed
* @dev Caller must either approve this contract to spend their Wrapped Native token, and have at least `getFeePerUser` tokens in their wallet.
* Or caller must send `getFeePerUser` value with this call.
*/
function claimOrder(uint128 batchId, address user) external payable returns (ERC20, uint256) {
Claim storage userClaim = claim[batchId];
if (!userClaim.isReadyForClaim) revert LimitOrderRegistry__OrderNotReadyToClaim(batchId);
uint256 depositAmount = batchIdToUserDepositAmount[batchId][user];
if (depositAmount == 0) revert LimitOrderRegistry__UserNotFound(user, batchId);
// Zero out user balance.
delete batchIdToUserDepositAmount[batchId][user];
// Calculate owed amount.
uint256 totalTokenDeposited;
uint256 totalTokenOut;
ERC20 tokenOut;
// again, remembering that direction == true means that the input token is token0.
if (userClaim.direction) {
totalTokenDeposited = userClaim.token0Amount;
totalTokenOut = userClaim.token1Amount;
tokenOut = poolToData[userClaim.pool].token1;
} else {
totalTokenDeposited = userClaim.token1Amount;
totalTokenOut = userClaim.token0Amount;
tokenOut = poolToData[userClaim.pool].token0;
}
uint256 owed = (totalTokenOut * depositAmount) / totalTokenDeposited;
// Transfer tokens owed to user.
tokenOut.safeTransfer(user, owed);
// Transfer fee in.
address sender = _msgSender();
if (msg.value >= userClaim.feePerUser) {
// refund if necessary.
uint256 refund = msg.value - userClaim.feePerUser;
if (refund > 0) sender.safeTransferETH(refund);
} else {
WRAPPED_NATIVE.safeTransferFrom(sender, address(this), userClaim.feePerUser);
// If value is non zero send it back to caller.
if (msg.value > 0) sender.safeTransferETH(msg.value);
}
emit ClaimOrder(user, batchId, owed);
return (tokenOut, owed);
}
/**
* @notice Allows users to cancel orders as long as they are completely OTM.
* @param pool the Uniswap V3 pool that contains the limit order to cancel
* @param targetTick the targetTick of the order you want to cancel
* @param direction bool indication the direction of the order
* @return amount0 amount0 withdrawn
* @return amount1 amount1 withdrawn
* @return batchId batch id withdrawn
*/
function cancelOrder(
UniswapV3Pool pool,
int24 targetTick,
bool direction,
uint256 deadline
) external returns (uint128 amount0, uint128 amount1, uint128 batchId) {
// defined here since we want to grab it out of the closure
uint256 positionId;
// this is in a closure to avoid namespace pollusion
{
// Make sure order is OTM.
(, int24 tick, , , , , ) = pool.slot0();
// Determine upper and lower ticks.
int24 upper;
int24 lower;
{
int24 tickSpacing = pool.tickSpacing();
// Make sure targetTick is divisible by spacing.
if (targetTick % tickSpacing != 0) revert LimitOrderRegistry__InvalidTargetTick(targetTick, tickSpacing);
if (direction) {
upper = targetTick;
lower = targetTick - tickSpacing;
} else {
upper = targetTick + tickSpacing;
lower = targetTick;
}
}
// Validate lower, upper,and direction. Make sure order is not ITM or MIXED
{
OrderStatus status = _getOrderStatus(tick, lower, upper, direction);
if (status != OrderStatus.OTM) revert LimitOrderRegistry__OrderITM(tick, targetTick, direction);
}
// Get the position id.
positionId = getPositionFromTicks[pool][direction][lower][upper];
if (positionId == 0) revert LimitOrderRegistry__InvalidPositionId();
}
// Get the users deposit amount in the order.
BatchOrder storage order = orderBook[positionId];
// the batch id can't be zero
if (order.batchId == 0) revert LimitOrderRegistry__InvalidBatchId();
// this variable is set conditionally, so we declare it here first
uint256 liquidityPercentToTake;
// grab sender for shorthand.
address sender = _msgSender();
{
// set the batchId return variable
batchId = order.batchId;
// grab the deposit amount from the mapping
uint128 depositAmount = batchIdToUserDepositAmount[batchId][sender];
// if there is no deposit, then there is nothing to do for this batch
if (depositAmount == 0) revert LimitOrderRegistry__UserNotFound(sender, batchId);
// Remove one from the userCount.
order.userCount--;
// Zero out user balance.
delete batchIdToUserDepositAmount[batchId][sender];
uint128 orderAmount;
// remember, direction=true, tokenIn = token0
if (order.direction) {
orderAmount = order.token0Amount;
if (orderAmount == depositAmount) {
liquidityPercentToTake = 1e18;
// Update order tokenAmount.
order.token0Amount = 0;
} else {
liquidityPercentToTake = (1e18 * uint256(depositAmount)) / orderAmount;
// Update order tokenAmount.
order.token0Amount = orderAmount - depositAmount;
}
} else {
orderAmount = order.token1Amount;
if (orderAmount == depositAmount) {
liquidityPercentToTake = 1e18;
// Update order tokenAmount.
order.token1Amount = 0;
} else {
liquidityPercentToTake = (1e18 * uint256(depositAmount)) / orderAmount;
// Update order tokenAmount.
order.token1Amount = orderAmount - depositAmount;
}
}
// actual movement of money is here
(amount0, amount1) = _takeFromPosition(positionId, pool, liquidityPercentToTake, deadline);
// emit event
emit CancelOrder(sender, amount0, amount1, order);
// special case for percent is 100%
if (liquidityPercentToTake == 1e18) {
_removeOrderFromList(positionId, pool, order);
// Zero out balances for cancelled order.
order.token0Amount = 0;
order.token1Amount = 0;
order.batchId = 0;
}
}
if (order.direction) {
if (amount0 > 0) poolToData[pool].token0.safeTransfer(sender, amount0);
else revert LimitOrderRegistry__NoLiquidityInOrder();
if (amount1 > 0) revert LimitOrderRegistry__AmountShouldBeZero();
} else {
if (amount1 > 0) poolToData[pool].token1.safeTransfer(sender, amount1);
else revert LimitOrderRegistry__NoLiquidityInOrder();
if (amount0 > 0) revert LimitOrderRegistry__AmountShouldBeZero();
}
}
/*//////////////////////////////////////////////////////////////
CHAINLINK AUTOMATION LOGIC
//////////////////////////////////////////////////////////////*/
/**
* @notice Returned `performData` simply contains a bool indicating which direction in the `orderBook` has orders that need to be fulfilled.
* @param checkData the data to decode when calling this from automation
*/
function checkUpkeep(bytes calldata checkData) external view returns (bool upkeepNeeded, bytes memory performData) {
UniswapV3Pool pool = abi.decode(checkData, (UniswapV3Pool));
(, int24 currentTick, , , , , ) = pool.slot0();
PoolData memory data = poolToData[pool];
BatchOrder memory order;
OrderStatus status;
bool walkDirection;
uint256 deadline = block.timestamp + 900;
if (data.centerHead != 0) {
// centerHead is set, check if it is ITM.
order = orderBook[data.centerHead];
status = _getOrderStatus(currentTick, order.tickLower, order.tickUpper, order.direction);
if (status == OrderStatus.ITM) {
walkDirection = true; // Walk towards head of list.
upkeepNeeded = true;
performData = abi.encode(pool, walkDirection, deadline);
return (upkeepNeeded, performData);
}
}
if (data.centerTail != 0) {
// If walk direction has not been set, then we know, no head orders are ITM.
// So check tail orders.
order = orderBook[data.centerTail];
status = _getOrderStatus(currentTick, order.tickLower, order.tickUpper, order.direction);
if (status == OrderStatus.ITM) {
walkDirection = false; // Walk towards tail of list.
upkeepNeeded = true;
performData = abi.encode(pool, walkDirection, deadline);
return (upkeepNeeded, performData);
}
}
return (false, abi.encode(0));
}
/**
* @notice Callable by anyone, as long as there are orders ITM, that need to be fulfilled.
* @param performData checkData the data to decode when calling this from automation
* @dev Does not use _removeOrderFromList, so that the center head/tail
* value is not updated every single time and order is fulfilled, instead we just update it once at the end.
*/
function performUpkeep(bytes calldata performData) external {
(UniswapV3Pool pool, bool walkDirection, uint256 deadline) = abi.decode(
performData,
(UniswapV3Pool, bool, uint256)
);
if (address(poolToData[pool].token0) == address(0)) revert LimitOrderRegistry__PoolNotSetup(address(pool));
PoolData storage data = poolToData[pool];
// Estimate gas cost.
uint256 estimatedFee = uint256(upkeepGasLimit * getGasPrice());
(, int24 currentTick, , , , , ) = pool.slot0();
bool orderFilled;
// Fulfill orders.
uint256 target = walkDirection ? data.centerHead : data.centerTail;
for (uint256 i; i < maxFillsPerUpkeep; ++i) {
if (target == 0) break;
BatchOrder storage order = orderBook[target];
OrderStatus status = _getOrderStatus(currentTick, order.tickLower, order.tickUpper, order.direction);
if (status == OrderStatus.ITM) {
_fulfillOrder(target, pool, order, estimatedFee, deadline);
target = walkDirection ? order.head : order.tail;
// Reconnect List and Zero out orders head and tail values removing order from the list.
orderBook[order.tail].head = order.head;
orderBook[order.head].tail = order.tail;
order.head = 0;
order.tail = 0;
// Update bool to indicate batch order is ready to handle claims.
claim[order.batchId].isReadyForClaim = true;
// Zero out orders batch id.
order.batchId = 0;
// Reset user count.
order.userCount = 0;
orderFilled = true;
} else break;
}
if (!orderFilled) revert LimitOrderRegistry__NoOrdersToFulfill();
// Update appropriate center value.
if (walkDirection) {
data.centerHead = target;
} else {
data.centerTail = target;
}
}
/*//////////////////////////////////////////////////////////////
INTERNAL ORDER LOGIC
//////////////////////////////////////////////////////////////*/
/**
* @notice Check if a given Uniswap V3 position is already in the `orderBook`.
* @dev Looks at Nodes head and tail, and checks for edge case of node being the only node in the `orderBook`
*/
function _checkThatNodeIsInList(uint256 node, BatchOrder memory order, PoolData memory data) internal pure {
if (order.head == 0 && order.tail == 0) {
// Possible but the order may be centerTail or centerHead.
if (data.centerHead != node && data.centerTail != node) revert LimitOrderRegistry__OrderNotInList(node);
}
}
/**
* @notice Finds appropriate spot in `orderBook` for an order.
* @param data the linked list in memory
* @param startingNode the index to start searching from
* @param targetTick the tick to stop searching at
* @param direction the direction to traverse the list
* @dev implemented as a linked list
*/
function _findSpot(
PoolData memory data,
uint256 startingNode,
int24 targetTick,
bool direction
) internal view returns (uint256 proposedHead, uint256 proposedTail) {
BatchOrder memory node;
if (startingNode == 0) {
if (direction && data.centerHead != 0) {
startingNode = data.centerHead;
node = orderBook[startingNode];
} else if (!direction && data.centerTail != 0) {
startingNode = data.centerTail;
node = orderBook[startingNode];
} else return (0, 0);
} else {
node = orderBook[startingNode];
if (node.direction != direction) revert LimitOrderRegistry__OrderNotInList(startingNode);
_checkThatNodeIsInList(startingNode, node, data);
}
uint256 nodeId = startingNode;
while (true) {
if (direction) {
// Go until we find an order with a tick lower GREATER or equal to targetTick, then set proposedTail equal to the tail, and proposed head to the current node.
if (node.tickLower >= targetTick) {
return (nodeId, node.tail);
} else if (node.head == 0) {
// Made it to head of list.
return (0, nodeId);
} else {
nodeId = node.head;
node = orderBook[nodeId];
}
} else {
// Go until we find tick upper that is LESS than or equal to targetTick
if (node.tickUpper <= targetTick) {
return (node.head, nodeId);
} else if (node.tail == 0) {
// Made it to the tail of the list.
return (nodeId, 0);
} else {
nodeId = node.tail;
node = orderBook[nodeId];
}
}
}
}
/**
* @notice Checks if newly added order should be made the new center head/tail.
* @param pool the uniswap v3 pool
* @param currentTick the current tick
* @param upper the upper tick
* @param lower the lower tick
*/
function _updateCenter(
UniswapV3Pool pool,
uint256 positionId,
int24 currentTick,
int24 upper,
int24 lower
) internal {
PoolData memory data = poolToData[pool];
if (currentTick > upper) {
// Check if centerTail needs to be updated.
if (data.centerTail == 0) {
// Currently no centerTail, so this order must become it.
poolToData[pool].centerTail = positionId;
} else {
BatchOrder memory centerTail = orderBook[data.centerTail];
if (upper > centerTail.tickUpper) {
// New position is closer to the current pool tick, so it becomes new centerTail.
poolToData[pool].centerTail = positionId;
}
// else nothing to do.
}
} else if (currentTick < lower) {
// Check if centerHead needs to be updated.
if (data.centerHead == 0) {
// Currently no centerHead, so this order must become it.
poolToData[pool].centerHead = positionId;
} else {
BatchOrder memory centerHead = orderBook[data.centerHead];
if (lower < centerHead.tickLower) {
// New position is closer to the current pool tick, so it becomes new centerHead.
poolToData[pool].centerHead = positionId;
}
// else nothing to do.
}
}
}
/**
* @notice Add a Uniswap V3 LP position to the `orderBook`.
* @param data the linked list in memory
* @param startingNode the index to start searching from
* @param targetTick the tick to stop searching at
* @param position the position to add the item to the list at
* @param direction the direction to traverse the list
*/
function _addPositionToList(
PoolData memory data,
uint256 startingNode,
int24 targetTick,
uint256 position,
bool direction
) internal {
// seek to find a free spot
(uint256 head, uint256 tail) = _findSpot(data, startingNode, targetTick, direction);
// one of head or tail will be not zero. insert into the one that is not zero
if (tail != 0) {
orderBook[tail].head = position;
orderBook[position].tail = tail;
}
if (head != 0) {
orderBook[head].tail = position;
orderBook[position].head = head;
}
}
/**
* @notice Setup a newly minted LP position, or one being reused.
* @param position the position to add the item to the list at
* @param direction the direction to traverse the list
* @dev Sets batchId, and direction.
*/
function _setupOrder(bool direction, uint256 position) internal {
BatchOrder storage order = orderBook[position];
order.batchId = batchCount++;
order.direction = direction;
}
/**
* @notice Updates a BatchOrder's token0/token1 amount, as well as associated
* `batchIdToUserDepositAmount` mapping value.
* @param positionId the id of the position to update
* @param user the user
* @param amount the amount to update the order by
* @return userTotal the new total
* @dev If user is new to the order, increment userCount.
*/
function _updateOrder(uint256 positionId, address user, uint128 amount) internal returns (uint128 userTotal) {
BatchOrder storage order = orderBook[positionId];
if (order.direction) {
// token1
order.token0Amount += amount;
} else {
// token0
order.token1Amount += amount;
}
// Check if user is already in the order.
uint128 batchId = order.batchId;
uint128 originalDepositAmount = batchIdToUserDepositAmount[batchId][user];
// If this is a new user in the order, add 1 to userCount.
if (originalDepositAmount == 0) order.userCount++;
batchIdToUserDepositAmount[batchId][user] = originalDepositAmount + amount;
return (originalDepositAmount + amount);
}
/**
* @notice Mints a new Uniswap V3 LP position.
* @param data the linked list in memory
* @param upper the upper tick for position
* @param lower the lower tick for position
* @param amount0 the amount of token0 for position
* @param amount1 the amount of token1 for position
* @param direction the direction of the order (bid/ask)
* @return positionId the id of the position
* @param deadline replay protection deadline
*/
function _mintPosition(
PoolData memory data,
int24 upper,
int24 lower,
uint128 amount0,
uint128 amount1,
bool direction,
uint256 deadline
) internal returns (uint256) {
if (direction) data.token0.safeApprove(address(POSITION_MANAGER), amount0);
else data.token1.safeApprove(address(POSITION_MANAGER), amount1);
// 0.9999e4 accounts for rounding errors in the Uniswap V3 protocol.
uint128 amount0Min = amount0 == 0 ? 0 : (amount0 * 0.9999e4) / 1e4;
uint128 amount1Min = amount1 == 0 ? 0 : (amount1 * 0.9999e4) / 1e4;
// Create mint params.
NonFungiblePositionManager.MintParams memory params = NonFungiblePositionManager.MintParams({
token0: address(data.token0),
token1: address(data.token1),
fee: data.fee,
tickLower: lower,
tickUpper: upper,
amount0Desired: amount0,
amount1Desired: amount1,
amount0Min: amount0Min,
amount1Min: amount1Min,
recipient: address(this),
deadline: deadline
});
// Supply liquidity to pool.
(uint256 tokenId, , , ) = POSITION_MANAGER.mint(params);
// Revert if tokenId received is 0 id.
// Zero token id is reserved for NULL values in linked list.
if (tokenId == 0) revert LimitOrderRegistry__InvalidPositionId();
// If position manager still has allowance, zero it out.
if (direction && data.token0.allowance(address(this), address(POSITION_MANAGER)) > 0)
data.token0.safeApprove(address(POSITION_MANAGER), 0);
if (!direction && data.token1.allowance(address(this), address(POSITION_MANAGER)) > 0)
data.token1.safeApprove(address(POSITION_MANAGER), 0);
return tokenId;
}
/**
* @notice Adds liquidity to a given `positionId`.
* @param data the linked list in memory
* @param positionId the id of the position to update
* @param amount0 the amount of token0 for position
* @param amount1 the amount of token1 for position
* @param direction the direction of the order (bid/ask)
* @param deadline replay protection deadline
*/
function _addToPosition(
PoolData memory data,
uint256 positionId,
uint128 amount0,
uint128 amount1,
bool direction,
uint256 deadline
) internal {
if (direction) data.token0.safeApprove(address(POSITION_MANAGER), amount0);
else data.token1.safeApprove(address(POSITION_MANAGER), amount1);
uint128 amount0Min = amount0 == 0 ? 0 : (amount0 * 0.9999e4) / 1e4;
uint128 amount1Min = amount1 == 0 ? 0 : (amount1 * 0.9999e4) / 1e4;
// Create increase liquidity params.
NonFungiblePositionManager.IncreaseLiquidityParams memory params = NonFungiblePositionManager
.IncreaseLiquidityParams({
tokenId: positionId,
amount0Desired: amount0,
amount1Desired: amount1,
amount0Min: amount0Min,
amount1Min: amount1Min,
deadline: deadline
});
// Increase liquidity in pool.
POSITION_MANAGER.increaseLiquidity(params);
// If position manager still has allowance, zero it out.
if (direction && data.token0.allowance(address(this), address(POSITION_MANAGER)) > 0)
data.token0.safeApprove(address(POSITION_MANAGER), 0);
if (!direction && data.token1.allowance(address(this), address(POSITION_MANAGER)) > 0)
data.token1.safeApprove(address(POSITION_MANAGER), 0);
}
/**
* @notice Enforces minimum liquidity requirements for orders.
* @param amount the amount to check
* @param asset the asset to check the amount against
* @dev this will revert if we fail checks
*/
function _enforceMinimumLiquidity(uint256 amount, ERC20 asset) internal view {
uint256 minimum = minimumAssets[asset];
// special case for 0, for increasing clarity
if (minimum == 0) revert LimitOrderRegistry__MinimumNotSet(address(asset));
if (amount < minimum) revert LimitOrderRegistry__MinimumNotMet(address(asset), minimum, amount);
}
/**
* @notice Helper function to determine an orders status.
* @param currentTick the current tick
* @param lower the lower tick of order
* @param upper the upper tick of order
* @param direction the direction of the order
* @return status the OrderStatus enum of an order created with the said current tick
* @dev Returns
* - ITM if order is ready to be filled, and is composed of wanted asset
* - OTM if order is not ready to be filled, but order can still be cancelled, because order is composed of asset to sell
* - MIXED order is composed of both wanted asset, and asset to sell, can not be fulfilled or cancelled.
*/
function _getOrderStatus(
int24 currentTick,
int24 lower,
int24 upper,
bool direction
) internal pure returns (OrderStatus status) {
if (upper == lower) revert LimitOrderRegistry__InvalidTickRange(upper, lower);
if (direction) {
// Indicates we want to go lower -> upper.
if (currentTick > upper) return OrderStatus.ITM;
if (currentTick >= lower) return OrderStatus.MIXED;
else return OrderStatus.OTM;
} else {
// Indicates we want to go upper -> lower.
if (currentTick < lower) return OrderStatus.ITM;
if (currentTick <= upper) return OrderStatus.MIXED;
else return OrderStatus.OTM;
}
}
/**
* @notice Called during `performUpkeep` to fulfill an ITM order.
* @dev Sets Claim info, removes all liquidity from position, and zeroes out BatchOrder amount0 and amount1 values.
*/
function _fulfillOrder(
uint256 target,
UniswapV3Pool pool,
BatchOrder storage order,
uint256 estimatedFee,
uint256 deadline
) internal {
// Save fee per user in Claim Struct.
uint256 totalUsers = order.userCount;
Claim storage newClaim = claim[order.batchId];
newClaim.feePerUser = uint128(estimatedFee / totalUsers);
newClaim.pool = pool;
// Take all liquidity from the order.
uint128 amount0;
uint128 amount1;
(amount0, amount1) = _takeFromPosition(target, pool, 1e18, deadline);
if (order.direction) {
// Copy the tokenIn amount from the order, this is the total user deposit.
newClaim.token0Amount = order.token0Amount;
// Total token out is amount1.
newClaim.token1Amount = amount1;
} else {
// Copy the tokenIn amount from the order, this is the total user deposit.
newClaim.token1Amount = order.token1Amount;
// Total token out is amount0.
newClaim.token0Amount = amount0;
}
newClaim.direction = order.direction;
// Zero out order balances.
order.token0Amount = 0;
order.token1Amount = 0;
emit OrderFilled(order.batchId, address(pool));
}
/**
* @notice Removes liquidity from `target` Uniswap V3 LP position.
* @dev Collects fees from `target` position, and saves them in `tokenToSwapFees`.
*/
function _takeFromPosition(
uint256 target,
UniswapV3Pool pool,
uint256 liquidityPercent,
uint256 deadline
) internal returns (uint128, uint128) {
(, , , , , , , uint128 liquidity, , , , ) = POSITION_MANAGER.positions(target);
liquidity = uint128(uint256(liquidity * liquidityPercent) / 1e18);
// Create decrease liquidity params.
// NB: because the amount0Min and amount1Min are 0 here, it is technically possible to front run this
// that is probably okay, but it should be noted
NonFungiblePositionManager.DecreaseLiquidityParams memory params = NonFungiblePositionManager
.DecreaseLiquidityParams({
tokenId: target,
liquidity: liquidity,
amount0Min: 0,
amount1Min: 0,
deadline: deadline
});
// Decrease liquidity in pool.
uint128 amount0;
uint128 amount1;
{
(uint256 a0, uint256 a1) = POSITION_MANAGER.decreaseLiquidity(params);
// downcast to uint128 since those are the units we use
amount0 = uint128(a0);
amount1 = uint128(a1);
}
// If completely closing position, then collect fees as well.
NonFungiblePositionManager.CollectParams memory collectParams;
{
uint128 amount0Max;
uint128 amount1Max;
if (liquidityPercent == 1e18) {
amount0Max = type(uint128).max;
amount1Max = type(uint128).max;
} else {
// Otherwise only collect principal.
amount0Max = amount0;
amount1Max = amount1;
}
// Create fee collection params.
collectParams = NonFungiblePositionManager.CollectParams({
tokenId: target,
recipient: address(this),
amount0Max: amount0Max,
amount1Max: amount1Max
});
}
// Save token balances.
ERC20 token0 = poolToData[pool].token0;
ERC20 token1 = poolToData[pool].token1;
uint256 token0Balance = token0.balanceOf(address(this));
uint256 token1Balance = token1.balanceOf(address(this));
// Collect fees.
POSITION_MANAGER.collect(collectParams);
// Save fees earned, take the total token amount out - the amount removed from liquidity to get the fees earned.
uint128 token0Fees = uint128(token0.balanceOf(address(this)) - token0Balance) - amount0;
uint128 token1Fees = uint128(token1.balanceOf(address(this)) - token1Balance) - amount1;
// Save any swap fees.
if (token0Fees > 0) tokenToSwapFees[address(token0)] += token0Fees;
if (token1Fees > 0) tokenToSwapFees[address(token1)] += token1Fees;
return (amount0, amount1);
}
/**
* @notice Removes an order from the `orderBook`.
* @dev Checks if order is one of the center values, and updates the head if need be.
*/
function _removeOrderFromList(uint256 target, UniswapV3Pool pool, BatchOrder storage order) internal {
// grab the centerHead and centerTail from mapping
uint256 centerHead = poolToData[pool].centerHead;
uint256 centerTail = poolToData[pool].centerTail;
if (target == centerHead) {
// if the target is the current center, set it to the center orders head
uint256 newHead = orderBook[centerHead].head;
// it is okay to be zero
poolToData[pool].centerHead = newHead;
} else if (target == centerTail) {
// do the same check with tail
uint256 newTail = orderBook[centerTail].tail;
// it is okay to be zero
poolToData[pool].centerTail = newTail;
}
// Remove order from linked list.
orderBook[order.tail].head = order.head;
orderBook[order.head].tail = order.tail;
order.head = 0;
order.tail = 0;
}
/*//////////////////////////////////////////////////////////////
VIEW LOGIC
//////////////////////////////////////////////////////////////*/
/**
* @notice Helper function to get the gas price used for fee calculation.
*/
function getGasPrice() public view returns (uint256) {
// If gas feed is set use it.
if (fastGasFeed != address(0)) {
(, int256 _answer, , uint256 _timestamp, ) = IChainlinkAggregator(fastGasFeed).latestRoundData();
uint256 timeSinceLastUpdate = block.timestamp - _timestamp;
// Check answer is not stale.
if (timeSinceLastUpdate > FAST_GAS_HEARTBEAT) {
// If answer is stale use owner set value.
// Multiply by 1e9 to convert gas price to gwei
return uint256(upkeepGasPrice) * 1e9;
} else {
// Else use the datafeed value.
uint256 answer = uint256(_answer);
return answer;
}
}
// Else use owner set value.
return uint256(upkeepGasPrice) * 1e9; // Multiply by 1e9 to convert gas price to gwei
}
/**
* @notice Helper function that finds the appropriate spot in the linked list for a new order.
* @param pool the Uniswap V3 pool you want to create an order in
* @param startingNode the UniV3 position Id to start looking
* @param targetTick the targetTick of the order you want to place
* @param direction the direction of the order
* @return proposedHead , proposedTail pr the correct head and tail for the new order
* @dev if both head and tail are zero, just pass in zero for the `startingNode`
* otherwise pass in either the nonzero head or nonzero tail for the `startingNode`
*/
function findSpot(
UniswapV3Pool pool,
uint256 startingNode,
int24 targetTick,
bool direction
) external view returns (uint256 proposedHead, uint256 proposedTail) {
PoolData memory data = poolToData[pool];
int24 tickSpacing = pool.tickSpacing();
// Make sure targetTick is divisible by spacing.
if (targetTick % tickSpacing != 0) revert LimitOrderRegistry__InvalidTargetTick(targetTick, tickSpacing);
(proposedHead, proposedTail) = _findSpot(data, startingNode, targetTick, direction);
}
/**
* @notice Helper function to get the fee per user for a specific order.
* @param batchId the batch id to get info for
*/
function getFeePerUser(uint128 batchId) external view returns (uint128) {
return claim[batchId].feePerUser;
}
/**
* @notice Helper function to view if a BatchOrder is ready to claim.
* @param batchId the batch id to get info for
* @return bool true if order is ready to claim, else false
*/
function isOrderReadyForClaim(uint128 batchId) external view returns (bool) {
return claim[batchId].isReadyForClaim;
}
/**
* @notice Helper function to get OrderBook/BatchOrder
* @param id the id to get info for
* @return Batchorder the batch order at id
*/
function getOrderBook(uint256 id) external view returns (BatchOrder memory) {
return orderBook[id];
}
/**
* @notice Helper function to get claim
* @param batchId the id to get info for
* @return Claim the claim info at id
*/
function getClaim(uint128 batchId) external view returns (Claim memory) {
return claim[batchId];
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
abstract contract ERC20 {
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
event Transfer(address indexed from, address indexed to, uint256 amount);
event Approval(address indexed owner, address indexed spender, uint256 amount);
/*//////////////////////////////////////////////////////////////
METADATA STORAGE
//////////////////////////////////////////////////////////////*/
string public name;
string public symbol;
uint8 public immutable decimals;
/*//////////////////////////////////////////////////////////////
ERC20 STORAGE
//////////////////////////////////////////////////////////////*/
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
/*//////////////////////////////////////////////////////////////
EIP-2612 STORAGE
//////////////////////////////////////////////////////////////*/
uint256 internal immutable INITIAL_CHAIN_ID;
bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;
mapping(address => uint256) public nonces;
/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/
constructor(
string memory _name,
string memory _symbol,
uint8 _decimals
) {
name = _name;
symbol = _symbol;
decimals = _decimals;
INITIAL_CHAIN_ID = block.chainid;
INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
}
/*//////////////////////////////////////////////////////////////
ERC20 LOGIC
//////////////////////////////////////////////////////////////*/
function approve(address spender, uint256 amount) public virtual returns (bool) {
allowance[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
function transfer(address to, uint256 amount) public virtual returns (bool) {
balanceOf[msg.sender] -= amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(msg.sender, to, amount);
return true;
}
function transferFrom(
address from,
address to,
uint256 amount
) public virtual returns (bool) {
uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.
if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;
balanceOf[from] -= amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(from, to, amount);
return true;
}
/*//////////////////////////////////////////////////////////////
EIP-2612 LOGIC
//////////////////////////////////////////////////////////////*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual {
require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");
// Unchecked because the only math done is incrementing
// the owner's nonce which cannot realistically overflow.
unchecked {
address recoveredAddress = ecrecover(
keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR(),
keccak256(
abi.encode(
keccak256(
"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
),
owner,
spender,
value,
nonces[owner]++,
deadline
)
)
)
),
v,
r,
s
);
require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");
allowance[recoveredAddress][spender] = value;
}
emit Approval(owner, spender, value);
}
function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
}
function computeDomainSeparator() internal view virtual returns (bytes32) {
return
keccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes(name)),
keccak256("1"),
block.chainid,
address(this)
)
);
}
/*//////////////////////////////////////////////////////////////
INTERNAL MINT/BURN LOGIC
//////////////////////////////////////////////////////////////*/
function _mint(address to, uint256 amount) internal virtual {
totalSupply += amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(address(0), to, amount);
}
function _burn(address from, uint256 amount) internal virtual {
balanceOf[from] -= amount;
// Cannot underflow because a user's balance
// will never be larger than the total supply.
unchecked {
totalSupply -= amount;
}
emit Transfer(from, address(0), amount);
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
import {ERC20} from "../tokens/ERC20.sol";
/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer.
/// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller.
library SafeTransferLib {
/*//////////////////////////////////////////////////////////////
ETH OPERATIONS
//////////////////////////////////////////////////////////////*/
function safeTransferETH(address to, uint256 amount) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Transfer the ETH and store if it succeeded or not.
success := call(gas(), to, amount, 0, 0, 0, 0)
}
require(success, "ETH_TRANSFER_FAILED");
}
/*//////////////////////////////////////////////////////////////
ERC20 OPERATIONS
//////////////////////////////////////////////////////////////*/
function safeTransferFrom(
ERC20 token,
address from,
address to,
uint256 amount
) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Get a pointer to some free memory.
let freeMemoryPointer := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.
mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), from) // Append the "from" argument.
mstore(add(freeMemoryPointer, 36), to) // Append the "to" argument.
mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument.
success := and(
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data.
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
// We use 100 because the length of our calldata totals up like so: 4 + 32 * 3.
// We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
// Counterintuitively, this call must be positioned second to the or() call in the
// surrounding and() call or else returndatasize() will be zero during the computation.
call(gas(), token, 0, freeMemoryPointer, 100, 0, 32)
)
}
require(success, "TRANSFER_FROM_FAILED");
}
function safeTransfer(
ERC20 token,
address to,
uint256 amount
) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Get a pointer to some free memory.
let freeMemoryPointer := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.
mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument.
mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument.
success := and(
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data.
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
// We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
// We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
// Counterintuitively, this call must be positioned second to the or() call in the
// surrounding and() call or else returndatasize() will be zero during the computation.
call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
)
}
require(success, "TRANSFER_FAILED");
}
function safeApprove(
ERC20 token,
address to,
uint256 amount
) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Get a pointer to some free memory.
let freeMemoryPointer := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.
mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument.
mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument.
success := and(
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data.
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
// We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
// We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
// Counterintuitively, this call must be positioned second to the or() call in the
// surrounding and() call or else returndatasize() will be zero during the computation.
call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
)
}
require(success, "APPROVE_FAILED");
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface AutomationCompatibleInterface {
/**
* @notice method that is simulated by the keepers to see if any work actually
* needs to be performed. This method does does not actually need to be
* executable, and since it is only ever simulated it can consume lots of gas.
* @dev To ensure that it is never called, you may want to add the
* cannotExecute modifier from KeeperBase to your implementation of this
* method.
* @param checkData specified in the upkeep registration so it is always the
* same for a registered upkeep. This can easily be broken down into specific
* arguments using `abi.decode`, so multiple upkeeps can be registered on the
* same contract and easily differentiated by the contract.
* @return upkeepNeeded boolean to indicate whether the keeper should call
* performUpkeep or not.
* @return performData bytes that the keeper should call performUpkeep with, if
* upkeep is needed. If you would like to encode data to decode later, try
* `abi.encode`.
*/
function checkUpkeep(bytes calldata checkData) external returns (bool upkeepNeeded, bytes memory performData);
/**
* @notice method that is actually executed by the keepers, via the registry.
* The data returned by the checkUpkeep simulation will be passed into
* this method to actually be executed.
* @dev The input to this method should not be trusted, and the caller of the
* method should not even be restricted to any single registry. Anyone should
* be able call it, and the input should be validated, there is no guarantee
* that the data passed in is the performData returned from checkUpkeep. This
* could happen due to malicious keepers, racing keepers, or simply a state
* change while the performUpkeep transaction is waiting for confirmation.
* Always validate the data passed in.
* @param performData is the data which was passed back from the checkData
* simulation. If it is encoded, it can easily be decoded into other types by
* calling `abi.decode`. This data should not be trusted, and should be
* validated against the contract's current state.
*/
function performUpkeep(bytes calldata performData) external;
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
/// @notice Simple single owner authorization mixin.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Owned.sol)
abstract contract Owned {
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
event OwnershipTransferred(address indexed user, address indexed newOwner);
/*//////////////////////////////////////////////////////////////
OWNERSHIP STORAGE
//////////////////////////////////////////////////////////////*/
address public owner;
modifier onlyOwner() virtual {
require(msg.sender == owner, "UNAUTHORIZED");
_;
}
/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/
constructor(address _owner) {
owner = _owner;
emit OwnershipTransferred(address(0), _owner);
}
/*//////////////////////////////////////////////////////////////
OWNERSHIP LOGIC
//////////////////////////////////////////////////////////////*/
function transferOwnership(address newOwner) public virtual onlyOwner {
owner = newOwner;
emit OwnershipTransferred(msg.sender, newOwner);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;
interface UniswapV3Pool {
event Burn(
address indexed owner,
int24 indexed tickLower,
int24 indexed tickUpper,
uint128 amount,
uint256 amount0,
uint256 amount1
);
event Collect(
address indexed owner,
address recipient,
int24 indexed tickLower,
int24 indexed tickUpper,
uint128 amount0,
uint128 amount1
);
event CollectProtocol(address indexed sender, address indexed recipient, uint128 amount0, uint128 amount1);
event Flash(
address indexed sender,
address indexed recipient,
uint256 amount0,
uint256 amount1,
uint256 paid0,
uint256 paid1
);
event IncreaseObservationCardinalityNext(
uint16 observationCardinalityNextOld,
uint16 observationCardinalityNextNew
);
event Initialize(uint160 sqrtPriceX96, int24 tick);
event Mint(
address sender,
address indexed owner,
int24 indexed tickLower,
int24 indexed tickUpper,
uint128 amount,
uint256 amount0,
uint256 amount1
);
event SetFeeProtocol(uint8 feeProtocol0Old, uint8 feeProtocol1Old, uint8 feeProtocol0New, uint8 feeProtocol1New);
event Swap(
address indexed sender,
address indexed recipient,
int256 amount0,
int256 amount1,
uint160 sqrtPriceX96,
uint128 liquidity,
int24 tick
);
function burn(int24 tickLower, int24 tickUpper, uint128 amount) external returns (uint256 amount0, uint256 amount1);
function collect(
address recipient,
int24 tickLower,
int24 tickUpper,
uint128 amount0Requested,
uint128 amount1Requested
) external returns (uint128 amount0, uint128 amount1);
function collectProtocol(
address recipient,
uint128 amount0Requested,
uint128 amount1Requested
) external returns (uint128 amount0, uint128 amount1);
function factory() external view returns (address);
function fee() external view returns (uint24);
function feeGrowthGlobal0X128() external view returns (uint256);
function feeGrowthGlobal1X128() external view returns (uint256);
function flash(address recipient, uint256 amount0, uint256 amount1, bytes memory data) external;
function increaseObservationCardinalityNext(uint16 observationCardinalityNext) external;
function initialize(uint160 sqrtPriceX96) external;
function liquidity() external view returns (uint128);
function maxLiquidityPerTick() external view returns (uint128);
function mint(
address recipient,
int24 tickLower,
int24 tickUpper,
uint128 amount,
bytes memory data
) external returns (uint256 amount0, uint256 amount1);
function observations(
uint256
)
external
view
returns (
uint32 blockTimestamp,
int56 tickCumulative,
uint160 secondsPerLiquidityCumulativeX128,
bool initialized
);
function observe(
uint32[] memory secondsAgos
) external view returns (int56[] memory tickCumulatives, uint160[] memory secondsPerLiquidityCumulativeX128s);
function positions(
bytes32
)
external
view
returns (
uint128 liquidity,
uint256 feeGrowthInside0LastX128,
uint256 feeGrowthInside1LastX128,
uint128 tokensOwed0,
uint128 tokensOwed1
);
function protocolFees() external view returns (uint128 token0, uint128 token1);
function setFeeProtocol(uint8 feeProtocol0, uint8 feeProtocol1) external;
function slot0()
external
view
returns (
uint160 sqrtPriceX96,
int24 tick,
uint16 observationIndex,
uint16 observationCardinality,
uint16 observationCardinalityNext,
uint8 feeProtocol,
bool unlocked
);
function snapshotCumulativesInside(
int24 tickLower,
int24 tickUpper
) external view returns (int56 tickCumulativeInside, uint160 secondsPerLiquidityInsideX128, uint32 secondsInside);
function swap(
address recipient,
bool zeroForOne,
int256 amountSpecified,
uint160 sqrtPriceLimitX96,
bytes memory data
) external returns (int256 amount0, int256 amount1);
function tickBitmap(int16) external view returns (uint256);
function tickSpacing() external view returns (int24);
function ticks(
int24
)
external
view
returns (
uint128 liquidityGross,
int128 liquidityNet,
uint256 feeGrowthOutside0X128,
uint256 feeGrowthOutside1X128,
int56 tickCumulativeOutside,
uint160 secondsPerLiquidityOutsideX128,
uint32 secondsOutside,
bool initialized
);
function token0() external view returns (address);
function token1() external view returns (address);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;
interface NonFungiblePositionManager {
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
event Collect(uint256 indexed tokenId, address recipient, uint256 amount0, uint256 amount1);
event DecreaseLiquidity(uint256 indexed tokenId, uint128 liquidity, uint256 amount0, uint256 amount1);
event IncreaseLiquidity(uint256 indexed tokenId, uint128 liquidity, uint256 amount0, uint256 amount1);
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
struct CollectParams {
uint256 tokenId;
address recipient;
uint128 amount0Max;
uint128 amount1Max;
}
struct DecreaseLiquidityParams {
uint256 tokenId;
uint128 liquidity;
uint256 amount0Min;
uint256 amount1Min;
uint256 deadline;
}
struct IncreaseLiquidityParams {
uint256 tokenId;
uint256 amount0Desired;
uint256 amount1Desired;
uint256 amount0Min;
uint256 amount1Min;
uint256 deadline;
}
struct MintParams {
address token0;
address token1;
uint24 fee;
int24 tickLower;
int24 tickUpper;
uint256 amount0Desired;
uint256 amount1Desired;
uint256 amount0Min;
uint256 amount1Min;
address recipient;
uint256 deadline;
}
function DOMAIN_SEPARATOR() external view returns (bytes32);
function PERMIT_TYPEHASH() external view returns (bytes32);
function WETH9() external view returns (address);
function approve(address to, uint256 tokenId) external;
function balanceOf(address owner) external view returns (uint256);
function baseURI() external pure returns (string memory);
function burn(uint256 tokenId) external payable;
function collect(CollectParams memory params) external payable returns (uint256 amount0, uint256 amount1);
function createAndInitializePoolIfNecessary(
address token0,
address token1,
uint24 fee,
uint160 sqrtPriceX96
) external payable returns (address pool);
function decreaseLiquidity(
DecreaseLiquidityParams memory params
) external payable returns (uint256 amount0, uint256 amount1);
function factory() external view returns (address);
function getApproved(uint256 tokenId) external view returns (address);
function increaseLiquidity(
IncreaseLiquidityParams memory params
) external payable returns (uint128 liquidity, uint256 amount0, uint256 amount1);
function isApprovedForAll(address owner, address operator) external view returns (bool);
function mint(
MintParams memory params
) external payable returns (uint256 tokenId, uint128 liquidity, uint256 amount0, uint256 amount1);
function multicall(bytes[] memory data) external payable returns (bytes[] memory results);
function name() external view returns (string memory);
function ownerOf(uint256 tokenId) external view returns (address);
function permit(address spender, uint256 tokenId, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external payable;
function positions(
uint256 tokenId
)
external
view
returns (
uint96 nonce,
address operator,
address token0,
address token1,
uint24 fee,
int24 tickLower,
int24 tickUpper,
uint128 liquidity,
uint256 feeGrowthInside0LastX128,
uint256 feeGrowthInside1LastX128,
uint128 tokensOwed0,
uint128 tokensOwed1
);
function refundETH() external payable;
function safeTransferFrom(address from, address to, uint256 tokenId) external;
function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) external;
function selfPermit(address token, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external payable;
function selfPermitAllowed(
address token,
uint256 nonce,
uint256 expiry,
uint8 v,
bytes32 r,
bytes32 s
) external payable;
function selfPermitAllowedIfNecessary(
address token,
uint256 nonce,
uint256 expiry,
uint8 v,
bytes32 r,
bytes32 s
) external payable;
function selfPermitIfNecessary(
address token,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external payable;
function setApprovalForAll(address operator, bool approved) external;
function supportsInterface(bytes4 interfaceId) external view returns (bool);
function sweepToken(address token, uint256 amountMinimum, address recipient) external payable;
function symbol() external view returns (string memory);
function tokenByIndex(uint256 index) external view returns (uint256);
function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);
function tokenURI(uint256 tokenId) external view returns (string memory);
function totalSupply() external view returns (uint256);
function transferFrom(address from, address to, uint256 tokenId) external;
function uniswapV3MintCallback(uint256 amount0Owed, uint256 amount1Owed, bytes memory data) external;
function unwrapWETH9(uint256 amountMinimum, address recipient) external payable;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC721/utils/ERC721Holder.sol)
pragma solidity ^0.8.0;
import "../IERC721Receiver.sol";
/**
* @dev Implementation of the {IERC721Receiver} interface.
*
* Accepts all token transfers.
* Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or {IERC721-setApprovalForAll}.
*/
contract ERC721Holder is IERC721Receiver {
/**
* @dev See {IERC721Receiver-onERC721Received}.
*
* Always returns `IERC721Receiver.onERC721Received.selector`.
*/
function onERC721Received(
address,
address,
uint256,
bytes memory
) public virtual override returns (bytes4) {
return this.onERC721Received.selector;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface LinkTokenInterface {
function allowance(address owner, address spender) external view returns (uint256 remaining);
function approve(address spender, uint256 value) external returns (bool success);
function balanceOf(address owner) external view returns (uint256 balance);
function decimals() external view returns (uint8 decimalPlaces);
function decreaseApproval(address spender, uint256 addedValue) external returns (bool success);
function increaseApproval(address spender, uint256 subtractedValue) external;
function name() external view returns (string memory tokenName);
function symbol() external view returns (string memory tokenSymbol);
function totalSupply() external view returns (uint256 totalTokensIssued);
function transfer(address to, uint256 value) external returns (bool success);
function transferAndCall(
address to,
uint256 value,
bytes calldata data
) external returns (bool success);
function transferFrom(
address from,
address to,
uint256 value
) external returns (bool success);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;
struct RegistrationParams {
string name;
bytes encryptedEmail;
address upkeepContract;
uint32 gasLimit;
address adminAddress;
bytes checkData;
bytes offchainConfig;
uint96 amount;
}
/**
* @notice Contract to accept requests for upkeep registrations
* @dev There are 2 registration workflows in this contract
* Flow 1. auto approve OFF / manual registration - UI calls `register` function on this contract, this contract owner at a later time then manually
* calls `approve` to register upkeep and emit events to inform UI and others interested.
* Flow 2. auto approve ON / real time registration - UI calls `register` function as before, which calls the `registerUpkeep` function directly on
* keeper registry and then emits approved event to finish the flow automatically without manual intervention.
* The idea is to have same interface(functions,events) for UI or anyone using this contract irrespective of auto approve being enabled or not.
* they can just listen to `RegistrationRequested` & `RegistrationApproved` events and know the status on registrations.
*/
interface IKeeperRegistrar {
/**
* @notice register can only be called through transferAndCall on LINK contract
* @param name string of the upkeep to be registered
* @param encryptedEmail email address of upkeep contact
* @param upkeepContract address to perform upkeep on
* @param gasLimit amount of gas to provide the target contract when performing upkeep
* @param adminAddress address to cancel upkeep and withdraw remaining funds
* @param checkData data passed to the contract when checking for upkeep
* @param amount quantity of LINK upkeep is funded with (specified in Juels)
* @param source application sending this request
* @param sender address of the sender making the request
*/
function register(
string memory name,
bytes calldata encryptedEmail,
address upkeepContract,
uint32 gasLimit,
address adminAddress,
bytes calldata checkData,
uint96 amount,
uint8 source,
address sender
) external;
function registerUpkeep(RegistrationParams calldata requestParams) external returns (uint256);
function typeAndVersion() external view returns (string memory);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @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
pragma solidity 0.8.16;
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV2V3Interface.sol";
interface IChainlinkAggregator is AggregatorV2V3Interface {
function maxAnswer() external view returns (int192);
function minAnswer() external view returns (int192);
function aggregator() external view returns (address);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)
pragma solidity ^0.8.0;
/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 asset contracts.
*/
interface IERC721Receiver {
/**
* @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
* by `operator` from `from`, this function is called.
*
* It must return its Solidity selector to confirm the token transfer.
* If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
*
* The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
*/
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./AggregatorInterface.sol";
import "./AggregatorV3Interface.sol";
interface AggregatorV2V3Interface is AggregatorInterface, AggregatorV3Interface {}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface AggregatorInterface {
function latestAnswer() external view returns (int256);
function latestTimestamp() external view returns (uint256);
function latestRound() external view returns (uint256);
function getAnswer(uint256 roundId) external view returns (int256);
function getTimestamp(uint256 roundId) external view returns (uint256);
event AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 updatedAt);
event NewRound(uint256 indexed roundId, address indexed startedBy, uint256 startedAt);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface AggregatorV3Interface {
function decimals() external view returns (uint8);
function description() external view returns (string memory);
function version() external view returns (uint256);
function getRoundData(uint80 _roundId)
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
function latestRoundData()
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
}{
"remappings": [
"@forge-std/=lib/forge-std/src/",
"@ds-test/=lib/forge-std/lib/ds-test/src/",
"ds-test/=lib/forge-std/lib/ds-test/src/",
"@openzeppelin/=lib/openzeppelin-contracts/",
"@chainlink/=lib/chainlink/",
"@solmate/=lib/solmate/src/",
"chainlink/=lib/chainlink/",
"forge-std/=lib/forge-std/src/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"solmate/=lib/solmate/src/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs"
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "london",
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"contract NonFungiblePositionManager","name":"_positionManager","type":"address"},{"internalType":"contract ERC20","name":"wrappedNative","type":"address"},{"internalType":"contract LinkTokenInterface","name":"link","type":"address"},{"internalType":"contract IKeeperRegistrar","name":"_registrar","type":"address"},{"internalType":"address","name":"_fastGasFeed","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"LimitOrderRegistry__AmountShouldBeZero","type":"error"},{"inputs":[],"name":"LimitOrderRegistry__CenterITM","type":"error"},{"inputs":[],"name":"LimitOrderRegistry__ContractNotShutdown","type":"error"},{"inputs":[],"name":"LimitOrderRegistry__ContractShutdown","type":"error"},{"inputs":[],"name":"LimitOrderRegistry__DirectionMisMatch","type":"error"},{"inputs":[],"name":"LimitOrderRegistry__InvalidBatchId","type":"error"},{"inputs":[],"name":"LimitOrderRegistry__InvalidFillsPerUpkeep","type":"error"},{"inputs":[],"name":"LimitOrderRegistry__InvalidGasLimit","type":"error"},{"inputs":[],"name":"LimitOrderRegistry__InvalidGasPrice","type":"error"},{"inputs":[],"name":"LimitOrderRegistry__InvalidPositionId","type":"error"},{"inputs":[{"internalType":"int24","name":"targetTick","type":"int24"},{"internalType":"int24","name":"tickSpacing","type":"int24"}],"name":"LimitOrderRegistry__InvalidTargetTick","type":"error"},{"inputs":[{"internalType":"int24","name":"upper","type":"int24"},{"internalType":"int24","name":"lower","type":"int24"}],"name":"LimitOrderRegistry__InvalidTickRange","type":"error"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"minimum","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"LimitOrderRegistry__MinimumNotMet","type":"error"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"LimitOrderRegistry__MinimumNotSet","type":"error"},{"inputs":[],"name":"LimitOrderRegistry__NoLiquidityInOrder","type":"error"},{"inputs":[],"name":"LimitOrderRegistry__NoOrdersToFulfill","type":"error"},{"inputs":[{"internalType":"int24","name":"currentTick","type":"int24"},{"internalType":"int24","name":"targetTick","type":"int24"},{"internalType":"bool","name":"direction","type":"bool"}],"name":"LimitOrderRegistry__OrderITM","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"LimitOrderRegistry__OrderNotInList","type":"error"},{"inputs":[{"internalType":"uint128","name":"batchId","type":"uint128"}],"name":"LimitOrderRegistry__OrderNotReadyToClaim","type":"error"},{"inputs":[{"internalType":"address","name":"pool","type":"address"}],"name":"LimitOrderRegistry__PoolAlreadySetup","type":"error"},{"inputs":[{"internalType":"address","name":"pool","type":"address"}],"name":"LimitOrderRegistry__PoolNotSetup","type":"error"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"batchId","type":"uint256"}],"name":"LimitOrderRegistry__UserNotFound","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"LimitOrderRegistry__ZeroFeesToWithdraw","type":"error"},{"inputs":[],"name":"LimitOrderRegistry__ZeroNativeBalance","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint128","name":"amount0","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"amount1","type":"uint128"},{"components":[{"internalType":"bool","name":"direction","type":"bool"},{"internalType":"int24","name":"tickUpper","type":"int24"},{"internalType":"int24","name":"tickLower","type":"int24"},{"internalType":"uint64","name":"userCount","type":"uint64"},{"internalType":"uint128","name":"batchId","type":"uint128"},{"internalType":"uint128","name":"token0Amount","type":"uint128"},{"internalType":"uint128","name":"token1Amount","type":"uint128"},{"internalType":"uint256","name":"head","type":"uint256"},{"internalType":"uint256","name":"tail","type":"uint256"}],"indexed":false,"internalType":"struct LimitOrderRegistry.BatchOrder","name":"affectedOrder","type":"tuple"}],"name":"CancelOrder","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint128","name":"batchId","type":"uint128"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ClaimOrder","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"pool","type":"address"}],"name":"LimitOrderSetup","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"address","name":"pool","type":"address"},{"indexed":false,"internalType":"uint128","name":"amount","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"userTotal","type":"uint128"},{"components":[{"internalType":"bool","name":"direction","type":"bool"},{"internalType":"int24","name":"tickUpper","type":"int24"},{"internalType":"int24","name":"tickLower","type":"int24"},{"internalType":"uint64","name":"userCount","type":"uint64"},{"internalType":"uint128","name":"batchId","type":"uint128"},{"internalType":"uint128","name":"token0Amount","type":"uint128"},{"internalType":"uint128","name":"token1Amount","type":"uint128"},{"internalType":"uint256","name":"head","type":"uint256"},{"internalType":"uint256","name":"tail","type":"uint256"}],"indexed":false,"internalType":"struct LimitOrderRegistry.BatchOrder","name":"affectedOrder","type":"tuple"}],"name":"NewOrder","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"batchId","type":"uint256"},{"indexed":false,"internalType":"address","name":"pool","type":"address"}],"name":"OrderFilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"isShutdown","type":"bool"}],"name":"ShutdownChanged","type":"event"},{"inputs":[],"name":"FAST_GAS_HEARTBEAT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LINK","outputs":[{"internalType":"contract LinkTokenInterface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_FILLS_PER_UPKEEP","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_GAS_LIMIT","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_GAS_PRICE","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"POSITION_MANAGER","outputs":[{"internalType":"contract NonFungiblePositionManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WRAPPED_NATIVE","outputs":[{"internalType":"contract ERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"batchCount","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint128","name":"","type":"uint128"},{"internalType":"address","name":"","type":"address"}],"name":"batchIdToUserDepositAmount","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract UniswapV3Pool","name":"pool","type":"address"},{"internalType":"int24","name":"targetTick","type":"int24"},{"internalType":"bool","name":"direction","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"cancelOrder","outputs":[{"internalType":"uint128","name":"amount0","type":"uint128"},{"internalType":"uint128","name":"amount1","type":"uint128"},{"internalType":"uint128","name":"batchId","type":"uint128"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"checkData","type":"bytes"}],"name":"checkUpkeep","outputs":[{"internalType":"bool","name":"upkeepNeeded","type":"bool"},{"internalType":"bytes","name":"performData","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint128","name":"","type":"uint128"}],"name":"claim","outputs":[{"internalType":"contract UniswapV3Pool","name":"pool","type":"address"},{"internalType":"uint128","name":"token0Amount","type":"uint128"},{"internalType":"uint128","name":"token1Amount","type":"uint128"},{"internalType":"uint128","name":"feePerUser","type":"uint128"},{"internalType":"bool","name":"direction","type":"bool"},{"internalType":"bool","name":"isReadyForClaim","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint128","name":"batchId","type":"uint128"},{"internalType":"address","name":"user","type":"address"}],"name":"claimOrder","outputs":[{"internalType":"contract ERC20","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"fastGasFeed","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract UniswapV3Pool","name":"pool","type":"address"},{"internalType":"uint256","name":"startingNode","type":"uint256"},{"internalType":"int24","name":"targetTick","type":"int24"},{"internalType":"bool","name":"direction","type":"bool"}],"name":"findSpot","outputs":[{"internalType":"uint256","name":"proposedHead","type":"uint256"},{"internalType":"uint256","name":"proposedTail","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint128","name":"batchId","type":"uint128"}],"name":"getClaim","outputs":[{"components":[{"internalType":"contract UniswapV3Pool","name":"pool","type":"address"},{"internalType":"uint128","name":"token0Amount","type":"uint128"},{"internalType":"uint128","name":"token1Amount","type":"uint128"},{"internalType":"uint128","name":"feePerUser","type":"uint128"},{"internalType":"bool","name":"direction","type":"bool"},{"internalType":"bool","name":"isReadyForClaim","type":"bool"}],"internalType":"struct LimitOrderRegistry.Claim","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint128","name":"batchId","type":"uint128"}],"name":"getFeePerUser","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getGasPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getOrderBook","outputs":[{"components":[{"internalType":"bool","name":"direction","type":"bool"},{"internalType":"int24","name":"tickUpper","type":"int24"},{"internalType":"int24","name":"tickLower","type":"int24"},{"internalType":"uint64","name":"userCount","type":"uint64"},{"internalType":"uint128","name":"batchId","type":"uint128"},{"internalType":"uint128","name":"token0Amount","type":"uint128"},{"internalType":"uint128","name":"token1Amount","type":"uint128"},{"internalType":"uint256","name":"head","type":"uint256"},{"internalType":"uint256","name":"tail","type":"uint256"}],"internalType":"struct LimitOrderRegistry.BatchOrder","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract UniswapV3Pool","name":"","type":"address"},{"internalType":"bool","name":"","type":"bool"},{"internalType":"int24","name":"","type":"int24"},{"internalType":"int24","name":"","type":"int24"}],"name":"getPositionFromTicks","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initiateShutdown","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"batchId","type":"uint128"}],"name":"isOrderReadyForClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isShutdown","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liftShutdown","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"maxFillsPerUpkeep","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ERC20","name":"","type":"address"}],"name":"minimumAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract UniswapV3Pool","name":"pool","type":"address"},{"internalType":"int24","name":"targetTick","type":"int24"},{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"bool","name":"direction","type":"bool"},{"internalType":"uint256","name":"startingNode","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"newOrder","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"orderBook","outputs":[{"internalType":"bool","name":"direction","type":"bool"},{"internalType":"int24","name":"tickUpper","type":"int24"},{"internalType":"int24","name":"tickLower","type":"int24"},{"internalType":"uint64","name":"userCount","type":"uint64"},{"internalType":"uint128","name":"batchId","type":"uint128"},{"internalType":"uint128","name":"token0Amount","type":"uint128"},{"internalType":"uint128","name":"token1Amount","type":"uint128"},{"internalType":"uint256","name":"head","type":"uint256"},{"internalType":"uint256","name":"tail","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"performData","type":"bytes"}],"name":"performUpkeep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract UniswapV3Pool","name":"","type":"address"}],"name":"poolToData","outputs":[{"internalType":"uint256","name":"centerHead","type":"uint256"},{"internalType":"uint256","name":"centerTail","type":"uint256"},{"internalType":"contract ERC20","name":"token0","type":"address"},{"internalType":"contract ERC20","name":"token1","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"registrar","outputs":[{"internalType":"contract IKeeperRegistrar","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"feed","type":"address"}],"name":"setFastGasFeed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"newVal","type":"uint16"}],"name":"setMaxFillsPerUpkeep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"contract ERC20","name":"asset","type":"address"}],"name":"setMinimumAssets","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IKeeperRegistrar","name":"_registrar","type":"address"}],"name":"setRegistrar","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"gasLimit","type":"uint32"}],"name":"setUpkeepGasLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"gasPrice","type":"uint32"}],"name":"setUpkeepGasPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract UniswapV3Pool","name":"pool","type":"address"},{"internalType":"uint256","name":"initialUpkeepFunds","type":"uint256"}],"name":"setupLimitOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"tokenToSwapFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"upkeepGasLimit","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"upkeepGasPrice","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawNative","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenFeeIsIn","type":"address"}],"name":"withdrawSwapFees","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60e0604052600680546001600160d01b0319166a01000a0000001e000493e01790553480156200002e57600080fd5b50604051620061fa380380620061fa8339810160408190526200005191620000f7565b600080546001600160a01b0319166001600160a01b03881690811782556040518892907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3506001600160a01b0394851660a05292841660805290831660c052600980549184166001600160a01b0319928316179055600a8054929093169116179055506200018b565b6001600160a01b0381168114620000f457600080fd5b50565b60008060008060008060c087890312156200011157600080fd5b86516200011e81620000de565b60208801519096506200013181620000de565b60408801519095506200014481620000de565b60608801519094506200015781620000de565b60808801519093506200016a81620000de565b60a08801519092506200017d81620000de565b809150509295509295509295565b60805160a05160c051615f9e6200025c600039600081816103b301528181612b0101528181612cce0152612d660152600081816103ff01528181613b4101528181613b8801528181613cc801528181613da501528181613e3501528181613e8601528181613f1601528181614479015281816144c0015281816145d2015281816146740152818161470401528181614755015281816147e50152818161481d0152818161495b0152614b9a015260008181610bf5015281816110270152818161167001526117270152615f9e6000f3fe60806040526004361061027d5760003560e01c80638ac9972f1161014f578063bf86d690116100c1578063e3bbb4f11161007a578063e3bbb4f114610c17578063e3f5aa5114610c2d578063ec81205514610c44578063ed12b33514610c64578063f2fde38b14610c91578063faab9d3914610cb157600080fd5b8063bf86d69014610b28578063c9d6e63014610b49578063cd3547b414610b69578063cda5197614610b96578063d368f97614610bb6578063d999984d14610be357600080fd5b8063a20b6e3411610113578063a20b6e341461096a578063a31d1b7614610a55578063a9ea1f8014610a75578063b17a24ae14610a92578063b1e057a414610ab2578063b752ceb214610ad457600080fd5b80638ac9972f146106f05780638da5cb5b1461073a5780638e06ffd51461075a578063935f450e1461079b57806397bb2b83146108d257600080fd5b80632c1f969e116101f357806350431ce4116101ac57806350431ce41461059357806353410e7b146105a85780635e2c576e146105c857806360e72adb146105dd5780636e04ff0d1461069a578063713b9dc1146106c857600080fd5b80632c1f969e146104d357806330e7c992146104e95780633cccf2291461050957806343854af514610529578063455259cb1461055e5780634585e33b1461057357600080fd5b8063151da32e11610245578063151da32e1461036f5780631b6b6d23146103a15780631bea83fe146103ed5780631c4c4d56146104215780631dd969d21461045e5780632b20e397146104b357600080fd5b806306f13056146102825780630a680e18146102c65780630cc2106d146102dd5780631467feac146102fd578063150b7a0214610336575b600080fd5b34801561028e57600080fd5b506006546102a990600160501b90046001600160801b031681565b6040516001600160801b0390911681526020015b60405180910390f35b3480156102d257600080fd5b506102db610cd1565b005b3480156102e957600080fd5b506102db6102f8366004614f8d565b610d79565b34801561030957600080fd5b5060065461032190600160201b900463ffffffff1681565b60405163ffffffff90911681526020016102bd565b34801561034257600080fd5b5061035661035136600461503f565b610df3565b6040516001600160e01b031990911681526020016102bd565b61038261037d366004615102565b610e04565b604080516001600160a01b0390931683526020830191909152016102bd565b3480156103ad57600080fd5b506103d57f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016102bd565b3480156103f957600080fd5b506103d57f000000000000000000000000000000000000000000000000000000000000000081565b34801561042d57600080fd5b506102a961043c36600461513b565b6001600160801b03908116600090815260026020819052604090912001541690565b34801561046a57600080fd5b506104a5610479366004615175565b600460209081526000948552604080862082529385528385208152918452828420909152825290205481565b6040519081526020016102bd565b3480156104bf57600080fd5b506009546103d5906001600160a01b031681565b3480156104df57600080fd5b506104a5611c2081565b3480156104f557600080fd5b506102db610504366004614f8d565b6110d7565b34801561051557600080fd5b506102db6105243660046151d1565b611147565b34801561053557600080fd5b506105496105443660046151ee565b611193565b604080519283526020830191909152016102bd565b34801561056a57600080fd5b506104a56112a3565b34801561057f57600080fd5b506102db61058e366004615236565b6113a3565b34801561059f57600080fd5b506102db61162e565b3480156105b457600080fd5b506102a96105c33660046152a7565b611770565b3480156105d457600080fd5b506102db611f6f565b3480156105e957600080fd5b506106516105f836600461513b565b60026020819052600091825260409091208054600182015491909201546001600160a01b03909216916001600160801b0380831692600160801b908190048216929182169160ff918104821691600160881b9091041686565b604080516001600160a01b0390971687526001600160801b03958616602088015293851693860193909352921660608401529015156080830152151560a082015260c0016102bd565b3480156106a657600080fd5b506106ba6106b5366004615236565b612001565b6040516102bd929190615365565b3480156106d457600080fd5b506106dd601481565b60405161ffff90911681526020016102bd565b3480156106fc57600080fd5b5061071061070b366004615380565b612352565b604080516001600160801b03948516815292841660208401529216918101919091526060016102bd565b34801561074657600080fd5b506000546103d5906001600160a01b031681565b34801561076657600080fd5b506102a9610775366004615102565b60076020908152600092835260408084209091529082529020546001600160801b031681565b3480156107a757600080fd5b5061086b6107b636600461513b565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a0810191909152506001600160801b03908116600090815260026020818152604092839020835160c08101855281546001600160a01b03168152600182015480871693820193909352600160801b9283900486169481019490945290910154928316606083015260ff908304811615156080830152600160881b909204909116151560a082015290565b6040516102bd919081516001600160a01b031681526020808301516001600160801b03908116918301919091526040808401518216908301526060808401519091169082015260808083015115159082015260a09182015115159181019190915260c00190565b3480156108de57600080fd5b506109316108ed3660046151d1565b600360208190526000918252604090912080546001820154600283015492909301549092916001600160a01b039081169190811690600160a01b900462ffffff1685565b6040805195865260208601949094526001600160a01b039283169385019390935216606083015262ffffff16608082015260a0016102bd565b34801561097657600080fd5b506109f66109853660046153d1565b60086020526000908152604090208054600182015460028084015460039094015460ff8416946101008504830b94600160201b810490930b936001600160401b03600160381b850416936001600160801b03600160781b90910481169382821693600160801b909304909116919089565b604080519915158a52600298890b60208b01529690970b958801959095526001600160401b0390931660608701526001600160801b039182166080870152811660a08601521660c084015260e0830152610100820152610120016102bd565b348015610a6157600080fd5b506102db610a703660046151d1565b61295e565b348015610a8157600080fd5b506006546103219063ffffffff1681565b348015610a9e57600080fd5b506102db610aad3660046153fa565b6129f5565b348015610abe57600080fd5b506006546106dd90600160401b900461ffff1681565b348015610ae057600080fd5b50610b18610aef36600461513b565b6001600160801b031660009081526002602081905260409091200154600160881b900460ff1690565b60405190151581526020016102bd565b348015610b3457600080fd5b50600954610b1890600160a01b900460ff1681565b348015610b5557600080fd5b506102db610b64366004615417565b612a79565b348015610b7557600080fd5b506104a5610b843660046151d1565b60016020526000908152604090205481565b348015610ba257600080fd5b506102db610bb1366004615443565b61312e565b348015610bc257600080fd5b50610bd6610bd13660046153d1565b613172565b6040516102bd9190615468565b348015610bef57600080fd5b506103d57f000000000000000000000000000000000000000000000000000000000000000081565b348015610c2357600080fd5b506103216103e881565b348015610c3957600080fd5b50610321620b71b081565b348015610c5057600080fd5b50600a546103d5906001600160a01b031681565b348015610c7057600080fd5b506104a5610c7f3660046151d1565b60056020526000908152604090205481565b348015610c9d57600080fd5b506102db610cac3660046151d1565b61321f565b348015610cbd57600080fd5b506102db610ccc3660046151d1565b613294565b600954600160a01b900460ff1615610cfc57604051637856112960e11b815260040160405180910390fd5b6000546001600160a01b03163314610d2f5760405162461bcd60e51b8152600401610d2690615521565b60405180910390fd5b6009805460ff60a01b1916600160a01b179055604051600181527fb8527b93c36dabdfe078af41be789ba946a4adcfeafcf9d8de21d51629859e3c906020015b60405180910390a1565b6000546001600160a01b03163314610da35760405162461bcd60e51b8152600401610d2690615521565b6103e863ffffffff82161115610dcc5760405163eec915d760e01b815260040160405180910390fd5b6006805463ffffffff909216600160201b0267ffffffff0000000019909216919091179055565b630a85bd0160e11b5b949350505050565b6001600160801b0382166000908152600260208190526040822090810154829190600160881b900460ff16610e575760405163327c783360e01b81526001600160801b0386166004820152602401610d26565b6001600160801b0380861660009081526007602090815260408083206001600160a01b038916845290915281205490911690819003610ec35760405163775c73bf60e01b81526001600160a01b03861660048201526001600160801b0387166024820152604401610d26565b6001600160801b03861660009081526007602090815260408083206001600160a01b0389168452909152812080546001600160801b0319169055600283015481908190600160801b900460ff1615610f5857505050600182015482546001600160a01b03908116600090815260036020819052604090912001546001600160801b0380841693600160801b9004169116610f95565b505050600182015482546001600160a01b039081166000908152600360205260409020600201546001600160801b03600160801b84048116931691165b600083610fa2868561555d565b610fac9190615592565b9050610fc26001600160a01b0383168a836132e0565b600286015433906001600160801b03163410611014576002870154600090610ff3906001600160801b0316346155a6565b9050801561100e5761100e6001600160a01b0383168261335e565b50611073565b600287015461105a906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690839030906001600160801b03166133b4565b3415611073576110736001600160a01b0382163461335e565b604080516001600160a01b038c1681526001600160801b038d1660208201529081018390527f7694d48c5e21d47a725e1e62a0159727e60d57f1e42d9f83e30199fffaefc8ac9060600160405180910390a1509096509450505050505b9250929050565b6000546001600160a01b031633146111015760405162461bcd60e51b8152600401610d2690615521565b620b71b063ffffffff8216111561112b576040516301eadab160e31b815260040160405180910390fd5b6006805463ffffffff191663ffffffff92909216919091179055565b6000546001600160a01b031633146111715760405162461bcd60e51b8152600401610d2690615521565b600a80546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b038481166000818152600360208181526040808420815160a0810183528154815260018201548185015260028201548816818401529301549586166060840152600160a01b90950462ffffff16608083015284516334324e9f60e21b8152945192948594929385939263d0c93a7c92600480820193918290030181865afa158015611229573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061124d91906155cf565b905061125981876155ec565b60020b15611288576040516327deee8960e21b8152600287810b600483015282900b6024820152604401610d26565b6112948288888861343e565b90999098509650505050505050565b600a546000906001600160a01b03161561138057600080600a60009054906101000a90046001600160a01b03166001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa15801561130d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113319190615628565b509350509250506000814261134691906155a6565b9050611c208111156113785760065461137090600160201b900463ffffffff16633b9aca0061555d565b935050505090565b509092915050565b60065461139e90600160201b900463ffffffff16633b9aca0061555d565b905090565b600080806113b384860186615678565b6001600160a01b038084166000908152600360205260409020600201549396509194509250166114015760405163d495675960e01b81526001600160a01b0384166004820152602401610d26565b6001600160a01b0383166000908152600360205260408120906114226112a3565b600654611435919063ffffffff1661555d565b90506000856001600160a01b0316633850c7bd6040518163ffffffff1660e01b815260040160e060405180830381865afa158015611477573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061149b91906156b9565b5050505050915050600080866114b55784600101546114b8565b84545b905060005b600654600160401b900461ffff168110156115ed5781156115ed576000828152600860205260408120805490919061150f908790600160201b8104600290810b91610100810490910b9060ff16613890565b905060008160028111156115255761152561575b565b036115d357611537848c848a8d61392d565b8961154657816003015461154c565b81600201545b6002808401805460038087018054600090815260086020908152604080832088018690558354958352808320909401949094559384905583905586546001600160801b03600160781b90910416835290839052902001805460ff60881b1916600160881b1790558254670100000000000000600160f81b03191683556001955093506115da565b50506115ed565b5050806115e690615771565b90506114bd565b508161160c57604051630f72fa0160e11b815260040160405180910390fd5b861561161a57808555611622565b600185018190555b50505050505050505050565b6000546001600160a01b031633146116585760405162461bcd60e51b8152600401610d2690615521565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156116bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116e3919061578a565b905047811580156116f2575080155b15611710576040516336f53c8f60e21b815260040160405180910390fd5b811561175057600054611750906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081169116846132e0565b801561176c5760005461176c906001600160a01b03168261335e565b5050565b600954600090600160a01b900460ff161561179e57604051637856112960e11b815260040160405180910390fd5b6001600160a01b03878116600090815260036020526040902060020154166117e45760405163d495675960e01b81526001600160a01b0388166004820152602401610d26565b33600085611810576001600160a01b03808a16600090815260036020819052604090912001541661182f565b6001600160a01b03808a16600090815260036020526040902060020154165b9050611844876001600160801b031682613aa6565b6118626001600160a01b03821683306001600160801b038b166133b4565b506040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810191909152886001600160a01b0316633850c7bd6040518163ffffffff1660e01b815260040160e060405180830381865afa1580156118da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118fe91906156b9565b5050505060029190910b83525050604080516334324e9f60e21b815290516000916001600160a01b038c169163d0c93a7c916004808201926020929091908290030181865afa158015611955573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061197991906155cf565b9050611985818a6155ec565b60020b156119b4576040516327deee8960e21b815260028a810b600483015282900b6024820152604401610d26565b86156119db57600289900b60208301526119ce818a6157a3565b60020b60408301526119f8565b6119e5818a6157c8565b600290810b602084015289900b60408301525b506000611a138260000151836040015184602001518a613890565b90506001816002811115611a2957611a2961575b565b14611a6057815160405163ea7469e760e01b8152600291820b6004820152908a900b60248201528715156044820152606401610d26565b506001600160a01b038916600090815260046020908152604080832089158015855290835281842085830151600290810b86529084528285208685015190910b8552909252909120546080830152611ac6576001600160801b03871660a0820152611ad6565b6001600160801b03871660c08201525b8060800151600003611c6d576001600160a01b03898116600090815260036020818152604092839020835160a0808201865282548252600183015482850152600283015487168287015291909301549485166060840152600160a01b90940462ffffff166080830152840151918401519284015160c08501519193611b619385939092908c8b613b25565b60808301819052611b7890829088908c908b613f4b565b604080830151608084018051600090815260086020908152848220805462ffffff958616600160201b0266ffffff0000000019909116179055860151825182529390208054939092166101000263ffffff001990931692909217905551611be0908890613fb7565b611bef8260800151848a614048565b6001600160801b031660608301526080820151825160208401516040850151611c1d938e93909290916141df565b5060808101516001600160a01b038a1660009081526004602090815260408083208a15158452825280832081860151600290810b85529083528184208387015190910b8452909152902055611ee5565b608080820151600090815260086020908152604091829020825161012081018452815460ff811615158252610100808204600290810b95840195909552600160201b8204850b958301959095526001600160401b03600160381b82041660608301526001600160801b03600160781b909104811695820195909552600182015480861660a08301819052600160801b90910490951660c08201529181015460e0830152600301549181019190915290151580611d36575060008160c001516001600160801b0316115b15611e05578051151587151514611d605760405163e86e44c160e01b815260040160405180910390fd5b6001600160a01b038a8116600090815260036020818152604092839020835160a08082018652825482526001830154938201939093526002820154861694810194909452909101549283166060830152600160a01b90920462ffffff166080808301919091528401519184015160c08501519192611de2928492908c8b61445f565b611df18360800151858b614048565b6001600160801b0316606084015250611ee3565b6001600160a01b038a8116600090815260036020818152604092839020835160a0810185528154815260018201549281019290925260028101548516938201939093529101549182166060820152600160a01b90910462ffffff16608080830191909152830151611e7c90829089908d908c613f4b565b611e8a888460800151613fb7565b611ea48184608001518560a001518660c001518c8b61445f565b611eb38360800151858b614048565b6001600160801b031660608401526080830151835160208501516040860151611ee1938f93909290916141df565b505b505b7f559322b66708f28c8fe1386f8cd96634d0c2fdb250d925b71a6c15e11e26069c828a8984606001516008600087608001518152602001908152602001600020604051611f36959493929190615873565b60405180910390a160800151600090815260086020526040902054600160781b90046001600160801b03169150505b9695505050505050565b6000546001600160a01b03163314611f995760405162461bcd60e51b8152600401610d2690615521565b600954600160a01b900460ff16611fc357604051632960b58960e11b815260040160405180910390fd5b6009805460ff60a01b19169055604051600081527fb8527b93c36dabdfe078af41be789ba946a4adcfeafcf9d8de21d51629859e3c90602001610d6f565b6000606081612012848601866151d1565b90506000816001600160a01b0316633850c7bd6040518163ffffffff1660e01b815260040160e060405180830381865afa158015612054573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061207891906156b9565b505050506001600160a01b03858116600090815260036020818152604092839020835160a0810185528154815260018201549281019290925260028101548516938201939093529101549182166060820152600160a01b90910462ffffff1660808201529193509091506120ec9050614f41565b600080806120fc426103846158b0565b85519091501561221b578451600090815260086020908152604091829020825161012081018452815460ff81161515808352610100808304600290810b968501879052600160201b8404810b978501889052600160381b84046001600160401b03166060860152600160781b9093046001600160801b039081166080860152600186015480821660a0870152600160801b90041660c08501529184015460e08401526003909301549082015296506121b79289929091613890565b925060008360028111156121cd576121cd61575b565b0361221b57604080516001600160a01b03891660208201526001918101829052606081018390529099508992506080015b6040516020818303038152906040529750505050505050506110d0565b60208501511561232257602085810151600090815260088252604090819020815161012081018352815460ff81161515808352610100808304600290810b978501889052600160201b8404810b968501879052600160381b84046001600160401b03166060860152600160781b9093046001600160801b039081166080860152600186015480821660a0870152600160801b90041660c08501529184015460e08401526003909301549082015296506122d692899291613890565b925060008360028111156122ec576122ec61575b565b0361232257604080516001600160a01b038916602082015260009181018290526060810183905260019a509092506080016121fe565b60408051600060208201819052910160405160208183030381529060405298509850505050505050509250929050565b6000806000806000886001600160a01b0316633850c7bd6040518163ffffffff1660e01b815260040160e060405180830381865afa158015612398573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123bc91906156b9565b505050505091505060008060008b6001600160a01b031663d0c93a7c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612407573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061242b91906155cf565b9050612437818c6155ec565b60020b15612466576040516327deee8960e21b815260028c810b600483015282900b6024820152604401610d26565b8915612480578a925061247981846157a3565b9150612490565b61248a818c6157c8565b92508a91505b50600061249f8483858d613890565b905060018160028111156124b5576124b561575b565b146124e95760405163ea7469e760e01b8152600285810b60048301528c900b60248201528a15156044820152606401610d26565b506001600160a01b038b1660009081526004602090815260408083208c151584528252808320600285810b85529083528184209086900b8452909152812054945084900361254a576040516327bd01f960e21b815260040160405180910390fd5b505050600081815260086020526040812080549091600160781b9091046001600160801b0316900361258f5760405163d17ecf4960e01b815260040160405180910390fd5b8054600160781b90046001600160801b03908116600081815260076020908152604080832033808552925282205492965090929091168083036125ff5760405163775c73bf60e01b81526001600160a01b03831660048201526001600160801b0387166024820152604401610d26565b8354600160381b90046001600160401b031684600761261d836158c3565b82546001600160401b039182166101009390930a9283029190920219909116179055506001600160801b03861660009081526007602090815260408083206001600160a01b0386168452909152812080546001600160801b0319169055845460ff1615612724575060018401546001600160801b0390811690821681036126c0576001850180546001600160801b0319169055670de0b6b3a764000093506127c3565b806001600160801b0316826001600160801b0316670de0b6b3a76400006126e7919061555d565b6126f19190615592565b93506126fd82826158e6565b6001860180546001600160801b0319166001600160801b03929092169190911790556127c3565b5060018401546001600160801b03600160801b90910481169082168103612766576001850180546001600160801b03169055670de0b6b3a764000093506127c3565b806001600160801b0316826001600160801b0316670de0b6b3a764000061278d919061555d565b6127979190615592565b93506127a382826158e6565b6001860180546001600160801b03928316600160801b0292169190911790555b6127cf868e868d614816565b604051919a5098507f61e6e7599d7fb0402072db6fa40efca86866f1c441dc2515a79575743ab59cf79061280a9085908c908c908a9061590d565b60405180910390a183670de0b6b3a76400000361284e5761282c868e87614db6565b6000600186015584546fffffffffffffffffffffffffffffffff60781b191685555b5050825460ff16156128e6576001600160801b038716156128a0576001600160a01b03808c1660009081526003602052604090206002015461289b9116826001600160801b038a166132e0565b6128b9565b604051634a68d63560e11b815260040160405180910390fd5b6001600160801b038616156128e1576040516395f95a0760e01b815260040160405180910390fd5b612950565b6001600160801b038616156128a0576001600160a01b03808c16600090815260036020819052604090912001546129289116826001600160801b0389166132e0565b6001600160801b03871615612950576040516395f95a0760e01b815260040160405180910390fd5b505050509450945094915050565b6000546001600160a01b031633146129885760405162461bcd60e51b8152600401610d2690615521565b6001600160a01b038116600090815260016020526040812054908190036129cd5760405163117373e160e01b81526001600160a01b0383166004820152602401610d26565b6001600160a01b0380831660008181526001602052604081208190555461176c9216836132e0565b6000546001600160a01b03163314612a1f5760405162461bcd60e51b8152600401610d2690615521565b61ffff81161580612a345750601461ffff8216115b15612a52576040516394aa3c9160e01b815260040160405180910390fd5b6006805461ffff909216600160401b0269ffff000000000000000019909216919091179055565b6000546001600160a01b03163314612aa35760405162461bcd60e51b8152600401610d2690615521565b6001600160a01b038281166000908152600360205260409020600201541615612aea57604051635edc3a1b60e11b81526001600160a01b0383166004820152602401610d26565b8015612f1c57600054612b2b906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116911630846133b4565b60408051808201825260018152603160f81b6020909101819052600954825163181f5a7760e01b8152925191926001600160a01b039091169163181f5a77916004808201926000929091908290030181865afa158015612b8f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612bb79190810190615961565b601081518110612bc957612bc961594b565b01602001516001600160f81b03191603612d55576000604051806080016040528060488152602001615f216048913980516020918201206040805160008185015281518082039094018452810190526006549091903090612c3c9063ffffffff811690600160401b900461ffff166159ce565b600054604080516001600160a01b038a81166020830152909216910160408051601f1981840301815290829052612c8095949392918990604d9030906024016159fa565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092526009549151630200057560e51b81529092506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811692634000aea092612d0b92919091169086908690600401615ab1565b6020604051808303816000875af1158015612d2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d4e9190615ad8565b5050612f1c565b600954612d8f906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116911683614e7a565b604080516101408101825260146101008201908152734c696d6974204f7264657220526567697374727960601b61012083015281528151600060208083018290529093908301910160408051808303601f19018152918152908252306020830152600654910190612e129063ffffffff811690600160401b900461ffff166159ce565b63ffffffff1681526000546001600160a01b031660208083019190915260408051920191612e51918791016001600160a01b0391909116815260200190565b60405160208183030381529060405281526020016000604051602001612e80919060ff91909116815260200190565b60408051808303601f190181529181529082526001600160601b038516602090920191909152600954905163022de76960e21b81529192506001600160a01b0316906308b79da490612ed6908490600401615af5565b6020604051808303816000875af1158015612ef5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f19919061578a565b50505b6040518060a001604052806000815260200160008152602001836001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015612f73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f979190615be3565b6001600160a01b03168152602001836001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa158015612fe3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130079190615be3565b6001600160a01b03168152602001836001600160a01b031663ddca3f436040518163ffffffff1660e01b8152600401602060405180830381865afa158015613053573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130779190615c13565b62ffffff9081169091526001600160a01b0384811660008181526003602081815260409283902087518155878201516001820155878401516002820180549188166001600160a01b0319909216919091179055606088015192018054608090980151909616600160a01b026001600160b81b031990971691909416179490941790925591519081527f250d91a5317f78e9f385385f5e6073f9a759b17cfa6f5d2374163436fbb44ae4910160405180910390a15050565b6000546001600160a01b031633146131585760405162461bcd60e51b8152600401610d2690615521565b6001600160a01b0316600090815260056020526040902055565b61317a614f41565b50600090815260086020908152604091829020825161012081018452815460ff811615158252610100808204600290810b95840195909552600160201b8204850b958301959095526001600160401b03600160381b82041660608301526001600160801b03600160781b90910481166080830152600183015480821660a0840152600160801b90041660c08201529181015460e0830152600301549181019190915290565b6000546001600160a01b031633146132495760405162461bcd60e51b8152600401610d2690615521565b600080546001600160a01b0319166001600160a01b0383169081178255604051909133917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a350565b6000546001600160a01b031633146132be5760405162461bcd60e51b8152600401610d2690615521565b600980546001600160a01b0319166001600160a01b0392909216919091179055565b600060405163a9059cbb60e01b8152836004820152826024820152602060006044836000895af13d15601f3d11600160005114161716915050806133585760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b6044820152606401610d26565b50505050565b600080600080600085875af19050806133af5760405162461bcd60e51b815260206004820152601360248201527211551217d514905394d1915497d19052531151606a1b6044820152606401610d26565b505050565b60006040516323b872dd60e01b81528460048201528360248201528260448201526020600060648360008a5af13d15601f3d11600160005114161716915050806134375760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b6044820152606401610d26565b5050505050565b600080613449614f41565b856000036135db5783801561345e5750865115155b1561350f57508551600081815260086020908152604091829020825161012081018452815460ff811615158252610100808204600290810b95840195909552600160201b8204850b958301959095526001600160401b03600160381b82041660608301526001600160801b03600160781b90910481166080830152600183015480821660a0840152600160801b90041660c08201529181015460e083015260030154918101919091529095506136b0565b831580156135205750602087015115155b156135ce5750602080870151600081815260088352604090819020815161012081018352815460ff811615158252610100808204600290810b97840197909752600160201b8204870b948301949094526001600160401b03600160381b82041660608301526001600160801b03600160781b90910481166080830152600183015480821660a0840152600160801b90041660c08201529381015460e0850152600301549083015295506136b0565b6000809250925050613887565b50600085815260086020908152604091829020825161012081018452815460ff81161515808352610100808304600290810b96850196909652600160201b8304860b96840196909652600160381b82046001600160401b03166060840152600160781b9091046001600160801b039081166080840152600184015480821660a0850152600160801b90041660c08301529282015460e082015260039091015492810192909252841515146136a557604051630eb5001960e41b815260048101879052602401610d26565b6136b0868289614ef1565b855b84156137a1578560020b826040015160020b126136da57610100909101519092509050613887565b8160e001516000036136f3576000935091506138879050565b5060e090810151600081815260086020908152604091829020825161012081018452815460ff811615158252610100808204600290810b95840195909552600160201b8204850b958301959095526001600160401b03600160381b82041660608301526001600160801b03600160781b90910481166080830152600183015480821660a0840152600160801b90041660c08201529181015494820194909452600390930154908301526136b2565b8560020b826020015160020b136137c15760e09091015192509050613887565b8161010001516000036137db579250600091506138879050565b5061010090810151600081815260086020908152604091829020825161012081018452815460ff811615158252868104600290810b94830194909452600160201b8104840b94820194909452600160381b84046001600160401b03166060820152600160781b9093046001600160801b039081166080850152600182015480821660a0860152600160801b90041660c08401529081015460e083015260030154928101929092526136b2565b94509492505050565b60008360020b8360020b036138c957604051600162993c7b60e01b03198152600284810b600483015285900b6024820152604401610d26565b8115613902578260020b8560020b13156138e557506000610dfc565b8360020b8560020b126138fa57506002610dfc565b506001610dfc565b8360020b8560020b121561391857506000610dfc565b8260020b8560020b136138fa57506002610dfc565b8254600160781b81046001600160801b03166000908152600260205260409020600160381b9091046001600160401b0316906139698285615592565b6002820180546001600160801b0319166001600160801b039290921691909117905580546001600160a01b0319166001600160a01b0387161781556000806139bb8989670de0b6b3a764000088614816565b8854919350915060ff16156139ed576001808801546001600160801b03838116600160801b0291161790840155613a1d565b6001878101546001600160801b0319600160801b918290046001600160801b039081169092021690841617908401555b865460028401805460ff9092161515600160801b0260ff60801b1990921691909117905560006001880155865460408051600160781b9092046001600160801b031682526001600160a01b038a1660208301527f74ebbab24ee8774729982ac100f931306b160f431f7f1483cc380186d56754bc910160405180910390a1505050505050505050565b6001600160a01b03811660009081526005602052604081205490819003613aeb57604051630b90e8fb60e21b81526001600160a01b0383166004820152602401610d26565b808310156133af576040516360d7e97160e01b81526001600160a01b03831660048201526024810182905260448101849052606401610d26565b60008215613b74576040880151613b6f906001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160801b038816614e7a565b613bb6565b6060880151613bb6906001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160801b038716614e7a565b60006001600160801b03861615613be557612710613bd68761270f615c2e565b613be09190615c54565b613be8565b60005b905060006001600160801b03861615613c1957612710613c0a8761270f615c2e565b613c149190615c54565b613c1c565b60005b905060006040518061016001604052808c604001516001600160a01b031681526020018c606001516001600160a01b031681526020018c6080015162ffffff1681526020018a60020b81526020018b60020b8152602001896001600160801b03168152602001886001600160801b03168152602001846001600160801b03168152602001836001600160801b03168152602001306001600160a01b0316815260200186815250905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166388316456836040518263ffffffff1660e01b8152600401613d129190615c7a565b6080604051808303816000875af1158015613d31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d559190615d49565b505050905080600003613d7b576040516327bd01f960e21b815260040160405180910390fd5b868015613e1c575060408c8101519051636eb1769f60e11b81523060048201526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166024830152600092169063dd62ed3e90604401602060405180830381865afa158015613df6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e1a919061578a565b115b15613e5b5760408c0151613e5b906001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006000614e7a565b86158015613efd575060608c0151604051636eb1769f60e11b81523060048201526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166024830152600092169063dd62ed3e90604401602060405180830381865afa158015613ed7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613efb919061578a565b115b15613f3c5760608c0151613f3c906001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006000614e7a565b9b9a5050505050505050505050565b600080613f5a8787878661343e565b9150915080600014613f875760008181526008602052604080822060020186905585825290206003018190555b8115613fae5760008281526008602052604080822060030186905585825290206002018290555b50505050505050565b600081815260086020526040902060068054600160501b90046001600160801b031690600a613fe583615d87565b82546101009290920a6001600160801b0381810219909316918316021790915582547fff00000000000000000000000000000000ffffffffffffffffffffffffffff0016600160781b929091169190910260ff1916179215159290921790915550565b6000838152600860205260408120805460ff16156140a9576001810180548491906000906140809084906001600160801b0316615dad565b92506101000a8154816001600160801b0302191690836001600160801b031602179055506140f4565b828160010160108282829054906101000a90046001600160801b03166140cf9190615dad565b92506101000a8154816001600160801b0302191690836001600160801b031602179055505b80546001600160801b03600160781b909104811660008181526007602090815260408083206001600160a01b038a1684529091528120549192919091169081900361417d578254600160381b90046001600160401b031683600761415783615dcd565b91906101000a8154816001600160401b0302191690836001600160401b03160217905550505b6141878582615dad565b6001600160801b0383811660009081526007602090815260408083206001600160a01b038c168452909152902080546001600160801b031916929091169190911790556141d48582615dad565b979650505050505050565b6001600160a01b03858116600090815260036020818152604092839020835160a08101855281548152600182015492810192909252600280820154861694830194909452909101549283166060820152600160a01b90920462ffffff16608083015283810b9085900b131561435357806020015160000361427d576001600160a01b0386166000908152600360205260409020600101859055614457565b602081810151600090815260088252604090819020815161012081018352815460ff811615158252610100808204600290810b968401879052600160201b8304810b95840195909552600160381b82046001600160401b03166060840152600160781b9091046001600160801b039081166080840152600184015480821660a0850152600160801b90041660c08301528383015460e083015260039092015491810191909152919085900b131561434d576001600160a01b03871660009081526003602052604090206001018690555b50614457565b8160020b8460020b121561445757805160000361438a576001600160a01b0386166000908152600360205260409020859055614457565b8051600090815260086020908152604091829020825161012081018452815460ff811615158252610100808204600290810b95840195909552600160201b8204850b958301869052600160381b82046001600160401b03166060840152600160781b9091046001600160801b039081166080840152600184015480821660a0850152600160801b90041660c08301528383015460e083015260039092015491810191909152919084900b1215613fae576001600160a01b0387166000908152600360205260409020869055505b505050505050565b81156144ac5760408601516144a7906001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160801b038716614e7a565b6144ee565b60608601516144ee906001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160801b038616614e7a565b60006001600160801b0385161561451d5761271061450e8661270f615c2e565b6145189190615c54565b614520565b60005b905060006001600160801b03851615614551576127106145428661270f615c2e565b61454c9190615c54565b614554565b60005b6040805160c0810182528981526001600160801b0389811660208301908152898216838501908152878316606085019081529286166080850190815260a085018a8152955163219f5d1760e01b81528551600482015292516024840152905160448301529151606482015290516084820152915160a48301529192507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063219f5d179060c4016060604051808303816000875af1158015614623573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146479190615de9565b5050508480156146eb57506040898101519051636eb1769f60e11b81523060048201526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166024830152600092169063dd62ed3e90604401602060405180830381865afa1580156146c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146e9919061578a565b115b1561472a57604089015161472a906001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006000614e7a565b841580156147cc57506060890151604051636eb1769f60e11b81523060048201526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166024830152600092169063dd62ed3e90604401602060405180830381865afa1580156147a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147ca919061578a565b115b1561480b57606089015161480b906001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006000614e7a565b505050505050505050565b60008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166399fbab88886040518263ffffffff1660e01b815260040161486991815260200190565b61018060405180830381865afa158015614887573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148ab9190615e20565b50505050975050505050505050670de0b6b3a764000085826001600160801b03166148d6919061555d565b6148e09190615592565b6040805160a0810182528981526001600160801b0380841660208301908152600083850181815260608501828152608086018c81529651630624e65f60e11b81528651600482015293519094166024840152516044830152915160648201529251608484015292935091908190819081906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690630c49ccbe9060a40160408051808303816000875af11580156149a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149c79190615efc565b604080516080810182526000808252602082018190529181018290526060810191909152919550935091506149f99050565b6000808a670de0b6b3a764000003614a1c57506001600160801b03905080614a22565b50839050825b604080516080810182528e81523060208083018290526001600160801b03958616838501529390941660608201526001600160a01b038e81166000908152600394859052838120600281015495015493516370a0823160e01b815260048101969096529195509283169391909216919083906370a0823190602401602060405180830381865afa158015614aba573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614ade919061578a565b6040516370a0823160e01b81523060048201529091506000906001600160a01b038416906370a0823190602401602060405180830381865afa158015614b28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614b4c919061578a565b6040805163fc6f786560e01b81528751600482015260208801516001600160a01b039081166024830152918801516001600160801b03908116604483015260608901511660648201529192507f0000000000000000000000000000000000000000000000000000000000000000169063fc6f78659060840160408051808303816000875af1158015614be2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614c069190615efc565b50506040516370a0823160e01b8152306004820152600090889084906001600160a01b038816906370a0823190602401602060405180830381865afa158015614c53573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614c77919061578a565b614c8191906155a6565b614c8b91906158e6565b6040516370a0823160e01b8152306004820152909150600090889084906001600160a01b038816906370a0823190602401602060405180830381865afa158015614cd9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614cfd919061578a565b614d0791906155a6565b614d1191906158e6565b90506001600160801b03821615614d59576001600160a01b038616600090815260016020526040812080546001600160801b0385169290614d539084906158b0565b90915550505b6001600160801b03811615614d9f576001600160a01b038516600090815260016020526040812080546001600160801b0384169290614d999084906158b0565b90915550505b50969f959e50949c50505050505050505050505050565b6001600160a01b03821660009081526003602052604090208054600190910154818503614e0c576000828152600860209081526040808320600201546001600160a01b0388168452600390925290912055614e40565b808503614e405760008181526008602090815260408083206003908101546001600160a01b03891685529252909120600101555b5050600280820180546003938401805460009081526008602052604080822090950183905581549281529384209094015581905590555050565b600060405163095ea7b360e01b8152836004820152826024820152602060006044836000895af13d15601f3d11600160005114161716915050806133585760405162461bcd60e51b815260206004820152600e60248201526d1054141493d59157d1905253115160921b6044820152606401610d26565b60e0820151158015614f065750610100820151155b156133af5780518314801590614f20575082816020015114155b156133af57604051630eb5001960e41b815260048101849052602401610d26565b6040805161012081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081019190915290565b600060208284031215614f9f57600080fd5b813563ffffffff81168114614fb357600080fd5b9392505050565b6001600160a01b0381168114614fcf57600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171561501057615010614fd2565b604052919050565b60006001600160401b0382111561503157615031614fd2565b50601f01601f191660200190565b6000806000806080858703121561505557600080fd5b843561506081614fba565b9350602085013561507081614fba565b92506040850135915060608501356001600160401b0381111561509257600080fd5b8501601f810187136150a357600080fd5b80356150b66150b182615018565b614fe8565b8181528860208385010111156150cb57600080fd5b8160208401602083013760006020838301015280935050505092959194509250565b6001600160801b0381168114614fcf57600080fd5b6000806040838503121561511557600080fd5b8235615120816150ed565b9150602083013561513081614fba565b809150509250929050565b60006020828403121561514d57600080fd5b8135614fb3816150ed565b8015158114614fcf57600080fd5b8060020b8114614fcf57600080fd5b6000806000806080858703121561518b57600080fd5b843561519681614fba565b935060208501356151a681615158565b925060408501356151b681615166565b915060608501356151c681615166565b939692955090935050565b6000602082840312156151e357600080fd5b8135614fb381614fba565b6000806000806080858703121561520457600080fd5b843561520f81614fba565b935060208501359250604085013561522681615166565b915060608501356151c681615158565b6000806020838503121561524957600080fd5b82356001600160401b038082111561526057600080fd5b818501915085601f83011261527457600080fd5b81358181111561528357600080fd5b86602082850101111561529557600080fd5b60209290920196919550909350505050565b60008060008060008060c087890312156152c057600080fd5b86356152cb81614fba565b955060208701356152db81615166565b945060408701356152eb816150ed565b935060608701356152fb81615158565b9598949750929560808101359460a0909101359350915050565b60005b83811015615330578181015183820152602001615318565b50506000910152565b60008151808452615351816020860160208601615315565b601f01601f19169290920160200192915050565b8215158152604060208201526000610dfc6040830184615339565b6000806000806080858703121561539657600080fd5b84356153a181614fba565b935060208501356153b181615166565b925060408501356153c181615158565b9396929550929360600135925050565b6000602082840312156153e357600080fd5b5035919050565b61ffff81168114614fcf57600080fd5b60006020828403121561540c57600080fd5b8135614fb3816153ea565b6000806040838503121561542a57600080fd5b823561543581614fba565b946020939093013593505050565b6000806040838503121561545657600080fd5b82359150602083013561513081614fba565b600061012082019050825115158252602083015160020b60208301526040830151615498604084018260020b9052565b5060608301516154b360608401826001600160401b03169052565b5060808301516154ce60808401826001600160801b03169052565b5060a08301516154e960a08401826001600160801b03169052565b5060c083015161550460c08401826001600160801b03169052565b5060e083015160e083015261010080840151818401525092915050565b6020808252600c908201526b15539055551213d49256915160a21b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b600081600019048311821515161561557757615577615547565b500290565b634e487b7160e01b600052601260045260246000fd5b6000826155a1576155a161557c565b500490565b818103818111156155b9576155b9615547565b92915050565b80516155ca81615166565b919050565b6000602082840312156155e157600080fd5b8151614fb381615166565b60008260020b806155ff576155ff61557c565b808360020b0791505092915050565b805169ffffffffffffffffffff811681146155ca57600080fd5b600080600080600060a0868803121561564057600080fd5b6156498661560e565b945060208601519350604086015192506060860151915061566c6080870161560e565b90509295509295909350565b60008060006060848603121561568d57600080fd5b833561569881614fba565b925060208401356156a881615158565b929592945050506040919091013590565b600080600080600080600060e0888a0312156156d457600080fd5b87516156df81614fba565b60208901519097506156f081615166565b6040890151909650615701816153ea565b6060890151909550615712816153ea565b6080890151909450615723816153ea565b60a089015190935060ff8116811461573a57600080fd5b60c089015190925061574b81615158565b8091505092959891949750929550565b634e487b7160e01b600052602160045260246000fd5b60006001820161578357615783615547565b5060010190565b60006020828403121561579c57600080fd5b5051919050565b600282810b9082900b03627fffff198112627fffff821317156155b9576155b9615547565b600281810b9083900b01627fffff8113627fffff19821217156155b9576155b9615547565b805460ff811615158352600881901c60020b6020840152602081901c60020b6040840152603881901c6001600160401b031660608401526001600160801b03607882901c8116608085015260018301546001600160801b038282161660a0860152915050608081901c60c084015250600281015460e08301526003015461010090910152565b6001600160a01b038681168252851660208201526001600160801b038481166040830152831660608201526101a08101611f6560808301846157ed565b808201808211156155b9576155b9615547565b60006001600160401b038216806158dc576158dc615547565b6000190192915050565b6001600160801b0382811682821603908082111561590657615906615547565b5092915050565b6001600160a01b03851681526001600160801b03848116602083015283166040820152610180810161594260608301846157ed565b95945050505050565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561597357600080fd5b81516001600160401b0381111561598957600080fd5b8201601f8101841361599a57600080fd5b80516159a86150b182615018565b8181528560208385010111156159bd57600080fd5b615942826020830160208601615315565b600063ffffffff808316818516818304811182151516156159f1576159f1615547565b02949350505050565b600061012080835260148184015250734c696d6974204f7264657220526567697374727960601b610140830152610160806020840152615a3c8184018c615339565b6001600160a01b038b8116604086015263ffffffff8b1660608601528916608085015283810360a08501529050615a738188615339565b9150506001600160601b03851660c083015260ff841660e0830152615aa46101008301846001600160a01b03169052565b9998505050505050505050565b60018060a01b03841681528260208201526060604082015260006159426060830184615339565b600060208284031215615aea57600080fd5b8151614fb381615158565b6020815260008251610100806020850152615b14610120850183615339565b91506020850151601f1980868503016040870152615b328483615339565b935060408701519150615b5060608701836001600160a01b03169052565b606087015163ffffffff81166080880152915060808701516001600160a01b03811660a0880152915060a08701519150808685030160c0870152615b948483615339565b935060c08701519150808685030160e087015250615bb28382615339565b92505060e0850151615bce828601826001600160601b03169052565b5090949350505050565b80516155ca81614fba565b600060208284031215615bf557600080fd5b8151614fb381614fba565b805162ffffff811681146155ca57600080fd5b600060208284031215615c2557600080fd5b614fb382615c00565b60006001600160801b03808316818516818304811182151516156159f1576159f1615547565b60006001600160801b0380841680615c6e57615c6e61557c565b92169190910492915050565b81516001600160a01b0316815261016081016020830151615ca660208401826001600160a01b03169052565b506040830151615cbd604084018262ffffff169052565b506060830151615cd2606084018260020b9052565b506080830151615ce7608084018260020b9052565b5060a083015160a083015260c083015160c083015260e083015160e083015261010080840151818401525061012080840151615d2d828501826001600160a01b03169052565b505061014092830151919092015290565b80516155ca816150ed565b60008060008060808587031215615d5f57600080fd5b845193506020850151615d71816150ed565b6040860151606090960151949790965092505050565b60006001600160801b03808316818103615da357615da3615547565b6001019392505050565b6001600160801b0381811683821601908082111561590657615906615547565b60006001600160401b03808316818103615da357615da3615547565b600080600060608486031215615dfe57600080fd5b8351615e09816150ed565b602085015160409095015190969495509392505050565b6000806000806000806000806000806000806101808d8f031215615e4357600080fd5b8c516001600160601b0381168114615e5a57600080fd5b9b50615e6860208e01615bd8565b9a50615e7660408e01615bd8565b9950615e8460608e01615bd8565b9850615e9260808e01615c00565b9750615ea060a08e016155bf565b9650615eae60c08e016155bf565b9550615ebc60e08e01615d3e565b94506101008d015193506101208d01519250615edb6101408e01615d3e565b9150615eea6101608e01615d3e565b90509295989b509295989b509295989b565b60008060408385031215615f0f57600080fd5b50508051602090910151909290915056fe726567697374657228737472696e672c62797465732c616464726573732c75696e7433322c616464726573732c62797465732c75696e7439362c75696e74382c6164647265737329a2646970667358221220050050e9eeef002bff0490b18116493419b20249972b8e2abbd9ef060d3e423f64736f6c63430008100033000000000000000000000000e75358526ef4441db03ccaeb9a87f180fae80eb9000000000000000000000000b218e4f7cf0533d4696fdfc419a0023d33345f280000000000000000000000004300000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x60806040526004361061027d5760003560e01c80638ac9972f1161014f578063bf86d690116100c1578063e3bbb4f11161007a578063e3bbb4f114610c17578063e3f5aa5114610c2d578063ec81205514610c44578063ed12b33514610c64578063f2fde38b14610c91578063faab9d3914610cb157600080fd5b8063bf86d69014610b28578063c9d6e63014610b49578063cd3547b414610b69578063cda5197614610b96578063d368f97614610bb6578063d999984d14610be357600080fd5b8063a20b6e3411610113578063a20b6e341461096a578063a31d1b7614610a55578063a9ea1f8014610a75578063b17a24ae14610a92578063b1e057a414610ab2578063b752ceb214610ad457600080fd5b80638ac9972f146106f05780638da5cb5b1461073a5780638e06ffd51461075a578063935f450e1461079b57806397bb2b83146108d257600080fd5b80632c1f969e116101f357806350431ce4116101ac57806350431ce41461059357806353410e7b146105a85780635e2c576e146105c857806360e72adb146105dd5780636e04ff0d1461069a578063713b9dc1146106c857600080fd5b80632c1f969e146104d357806330e7c992146104e95780633cccf2291461050957806343854af514610529578063455259cb1461055e5780634585e33b1461057357600080fd5b8063151da32e11610245578063151da32e1461036f5780631b6b6d23146103a15780631bea83fe146103ed5780631c4c4d56146104215780631dd969d21461045e5780632b20e397146104b357600080fd5b806306f13056146102825780630a680e18146102c65780630cc2106d146102dd5780631467feac146102fd578063150b7a0214610336575b600080fd5b34801561028e57600080fd5b506006546102a990600160501b90046001600160801b031681565b6040516001600160801b0390911681526020015b60405180910390f35b3480156102d257600080fd5b506102db610cd1565b005b3480156102e957600080fd5b506102db6102f8366004614f8d565b610d79565b34801561030957600080fd5b5060065461032190600160201b900463ffffffff1681565b60405163ffffffff90911681526020016102bd565b34801561034257600080fd5b5061035661035136600461503f565b610df3565b6040516001600160e01b031990911681526020016102bd565b61038261037d366004615102565b610e04565b604080516001600160a01b0390931683526020830191909152016102bd565b3480156103ad57600080fd5b506103d57f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016102bd565b3480156103f957600080fd5b506103d57f000000000000000000000000b218e4f7cf0533d4696fdfc419a0023d33345f2881565b34801561042d57600080fd5b506102a961043c36600461513b565b6001600160801b03908116600090815260026020819052604090912001541690565b34801561046a57600080fd5b506104a5610479366004615175565b600460209081526000948552604080862082529385528385208152918452828420909152825290205481565b6040519081526020016102bd565b3480156104bf57600080fd5b506009546103d5906001600160a01b031681565b3480156104df57600080fd5b506104a5611c2081565b3480156104f557600080fd5b506102db610504366004614f8d565b6110d7565b34801561051557600080fd5b506102db6105243660046151d1565b611147565b34801561053557600080fd5b506105496105443660046151ee565b611193565b604080519283526020830191909152016102bd565b34801561056a57600080fd5b506104a56112a3565b34801561057f57600080fd5b506102db61058e366004615236565b6113a3565b34801561059f57600080fd5b506102db61162e565b3480156105b457600080fd5b506102a96105c33660046152a7565b611770565b3480156105d457600080fd5b506102db611f6f565b3480156105e957600080fd5b506106516105f836600461513b565b60026020819052600091825260409091208054600182015491909201546001600160a01b03909216916001600160801b0380831692600160801b908190048216929182169160ff918104821691600160881b9091041686565b604080516001600160a01b0390971687526001600160801b03958616602088015293851693860193909352921660608401529015156080830152151560a082015260c0016102bd565b3480156106a657600080fd5b506106ba6106b5366004615236565b612001565b6040516102bd929190615365565b3480156106d457600080fd5b506106dd601481565b60405161ffff90911681526020016102bd565b3480156106fc57600080fd5b5061071061070b366004615380565b612352565b604080516001600160801b03948516815292841660208401529216918101919091526060016102bd565b34801561074657600080fd5b506000546103d5906001600160a01b031681565b34801561076657600080fd5b506102a9610775366004615102565b60076020908152600092835260408084209091529082529020546001600160801b031681565b3480156107a757600080fd5b5061086b6107b636600461513b565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a0810191909152506001600160801b03908116600090815260026020818152604092839020835160c08101855281546001600160a01b03168152600182015480871693820193909352600160801b9283900486169481019490945290910154928316606083015260ff908304811615156080830152600160881b909204909116151560a082015290565b6040516102bd919081516001600160a01b031681526020808301516001600160801b03908116918301919091526040808401518216908301526060808401519091169082015260808083015115159082015260a09182015115159181019190915260c00190565b3480156108de57600080fd5b506109316108ed3660046151d1565b600360208190526000918252604090912080546001820154600283015492909301549092916001600160a01b039081169190811690600160a01b900462ffffff1685565b6040805195865260208601949094526001600160a01b039283169385019390935216606083015262ffffff16608082015260a0016102bd565b34801561097657600080fd5b506109f66109853660046153d1565b60086020526000908152604090208054600182015460028084015460039094015460ff8416946101008504830b94600160201b810490930b936001600160401b03600160381b850416936001600160801b03600160781b90910481169382821693600160801b909304909116919089565b604080519915158a52600298890b60208b01529690970b958801959095526001600160401b0390931660608701526001600160801b039182166080870152811660a08601521660c084015260e0830152610100820152610120016102bd565b348015610a6157600080fd5b506102db610a703660046151d1565b61295e565b348015610a8157600080fd5b506006546103219063ffffffff1681565b348015610a9e57600080fd5b506102db610aad3660046153fa565b6129f5565b348015610abe57600080fd5b506006546106dd90600160401b900461ffff1681565b348015610ae057600080fd5b50610b18610aef36600461513b565b6001600160801b031660009081526002602081905260409091200154600160881b900460ff1690565b60405190151581526020016102bd565b348015610b3457600080fd5b50600954610b1890600160a01b900460ff1681565b348015610b5557600080fd5b506102db610b64366004615417565b612a79565b348015610b7557600080fd5b506104a5610b843660046151d1565b60016020526000908152604090205481565b348015610ba257600080fd5b506102db610bb1366004615443565b61312e565b348015610bc257600080fd5b50610bd6610bd13660046153d1565b613172565b6040516102bd9190615468565b348015610bef57600080fd5b506103d57f000000000000000000000000430000000000000000000000000000000000000481565b348015610c2357600080fd5b506103216103e881565b348015610c3957600080fd5b50610321620b71b081565b348015610c5057600080fd5b50600a546103d5906001600160a01b031681565b348015610c7057600080fd5b506104a5610c7f3660046151d1565b60056020526000908152604090205481565b348015610c9d57600080fd5b506102db610cac3660046151d1565b61321f565b348015610cbd57600080fd5b506102db610ccc3660046151d1565b613294565b600954600160a01b900460ff1615610cfc57604051637856112960e11b815260040160405180910390fd5b6000546001600160a01b03163314610d2f5760405162461bcd60e51b8152600401610d2690615521565b60405180910390fd5b6009805460ff60a01b1916600160a01b179055604051600181527fb8527b93c36dabdfe078af41be789ba946a4adcfeafcf9d8de21d51629859e3c906020015b60405180910390a1565b6000546001600160a01b03163314610da35760405162461bcd60e51b8152600401610d2690615521565b6103e863ffffffff82161115610dcc5760405163eec915d760e01b815260040160405180910390fd5b6006805463ffffffff909216600160201b0267ffffffff0000000019909216919091179055565b630a85bd0160e11b5b949350505050565b6001600160801b0382166000908152600260208190526040822090810154829190600160881b900460ff16610e575760405163327c783360e01b81526001600160801b0386166004820152602401610d26565b6001600160801b0380861660009081526007602090815260408083206001600160a01b038916845290915281205490911690819003610ec35760405163775c73bf60e01b81526001600160a01b03861660048201526001600160801b0387166024820152604401610d26565b6001600160801b03861660009081526007602090815260408083206001600160a01b0389168452909152812080546001600160801b0319169055600283015481908190600160801b900460ff1615610f5857505050600182015482546001600160a01b03908116600090815260036020819052604090912001546001600160801b0380841693600160801b9004169116610f95565b505050600182015482546001600160a01b039081166000908152600360205260409020600201546001600160801b03600160801b84048116931691165b600083610fa2868561555d565b610fac9190615592565b9050610fc26001600160a01b0383168a836132e0565b600286015433906001600160801b03163410611014576002870154600090610ff3906001600160801b0316346155a6565b9050801561100e5761100e6001600160a01b0383168261335e565b50611073565b600287015461105a906001600160a01b037f00000000000000000000000043000000000000000000000000000000000000041690839030906001600160801b03166133b4565b3415611073576110736001600160a01b0382163461335e565b604080516001600160a01b038c1681526001600160801b038d1660208201529081018390527f7694d48c5e21d47a725e1e62a0159727e60d57f1e42d9f83e30199fffaefc8ac9060600160405180910390a1509096509450505050505b9250929050565b6000546001600160a01b031633146111015760405162461bcd60e51b8152600401610d2690615521565b620b71b063ffffffff8216111561112b576040516301eadab160e31b815260040160405180910390fd5b6006805463ffffffff191663ffffffff92909216919091179055565b6000546001600160a01b031633146111715760405162461bcd60e51b8152600401610d2690615521565b600a80546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b038481166000818152600360208181526040808420815160a0810183528154815260018201548185015260028201548816818401529301549586166060840152600160a01b90950462ffffff16608083015284516334324e9f60e21b8152945192948594929385939263d0c93a7c92600480820193918290030181865afa158015611229573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061124d91906155cf565b905061125981876155ec565b60020b15611288576040516327deee8960e21b8152600287810b600483015282900b6024820152604401610d26565b6112948288888861343e565b90999098509650505050505050565b600a546000906001600160a01b03161561138057600080600a60009054906101000a90046001600160a01b03166001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa15801561130d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113319190615628565b509350509250506000814261134691906155a6565b9050611c208111156113785760065461137090600160201b900463ffffffff16633b9aca0061555d565b935050505090565b509092915050565b60065461139e90600160201b900463ffffffff16633b9aca0061555d565b905090565b600080806113b384860186615678565b6001600160a01b038084166000908152600360205260409020600201549396509194509250166114015760405163d495675960e01b81526001600160a01b0384166004820152602401610d26565b6001600160a01b0383166000908152600360205260408120906114226112a3565b600654611435919063ffffffff1661555d565b90506000856001600160a01b0316633850c7bd6040518163ffffffff1660e01b815260040160e060405180830381865afa158015611477573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061149b91906156b9565b5050505050915050600080866114b55784600101546114b8565b84545b905060005b600654600160401b900461ffff168110156115ed5781156115ed576000828152600860205260408120805490919061150f908790600160201b8104600290810b91610100810490910b9060ff16613890565b905060008160028111156115255761152561575b565b036115d357611537848c848a8d61392d565b8961154657816003015461154c565b81600201545b6002808401805460038087018054600090815260086020908152604080832088018690558354958352808320909401949094559384905583905586546001600160801b03600160781b90910416835290839052902001805460ff60881b1916600160881b1790558254670100000000000000600160f81b03191683556001955093506115da565b50506115ed565b5050806115e690615771565b90506114bd565b508161160c57604051630f72fa0160e11b815260040160405180910390fd5b861561161a57808555611622565b600185018190555b50505050505050505050565b6000546001600160a01b031633146116585760405162461bcd60e51b8152600401610d2690615521565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000043000000000000000000000000000000000000046001600160a01b0316906370a0823190602401602060405180830381865afa1580156116bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116e3919061578a565b905047811580156116f2575080155b15611710576040516336f53c8f60e21b815260040160405180910390fd5b811561175057600054611750906001600160a01b037f000000000000000000000000430000000000000000000000000000000000000481169116846132e0565b801561176c5760005461176c906001600160a01b03168261335e565b5050565b600954600090600160a01b900460ff161561179e57604051637856112960e11b815260040160405180910390fd5b6001600160a01b03878116600090815260036020526040902060020154166117e45760405163d495675960e01b81526001600160a01b0388166004820152602401610d26565b33600085611810576001600160a01b03808a16600090815260036020819052604090912001541661182f565b6001600160a01b03808a16600090815260036020526040902060020154165b9050611844876001600160801b031682613aa6565b6118626001600160a01b03821683306001600160801b038b166133b4565b506040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810191909152886001600160a01b0316633850c7bd6040518163ffffffff1660e01b815260040160e060405180830381865afa1580156118da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118fe91906156b9565b5050505060029190910b83525050604080516334324e9f60e21b815290516000916001600160a01b038c169163d0c93a7c916004808201926020929091908290030181865afa158015611955573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061197991906155cf565b9050611985818a6155ec565b60020b156119b4576040516327deee8960e21b815260028a810b600483015282900b6024820152604401610d26565b86156119db57600289900b60208301526119ce818a6157a3565b60020b60408301526119f8565b6119e5818a6157c8565b600290810b602084015289900b60408301525b506000611a138260000151836040015184602001518a613890565b90506001816002811115611a2957611a2961575b565b14611a6057815160405163ea7469e760e01b8152600291820b6004820152908a900b60248201528715156044820152606401610d26565b506001600160a01b038916600090815260046020908152604080832089158015855290835281842085830151600290810b86529084528285208685015190910b8552909252909120546080830152611ac6576001600160801b03871660a0820152611ad6565b6001600160801b03871660c08201525b8060800151600003611c6d576001600160a01b03898116600090815260036020818152604092839020835160a0808201865282548252600183015482850152600283015487168287015291909301549485166060840152600160a01b90940462ffffff166080830152840151918401519284015160c08501519193611b619385939092908c8b613b25565b60808301819052611b7890829088908c908b613f4b565b604080830151608084018051600090815260086020908152848220805462ffffff958616600160201b0266ffffff0000000019909116179055860151825182529390208054939092166101000263ffffff001990931692909217905551611be0908890613fb7565b611bef8260800151848a614048565b6001600160801b031660608301526080820151825160208401516040850151611c1d938e93909290916141df565b5060808101516001600160a01b038a1660009081526004602090815260408083208a15158452825280832081860151600290810b85529083528184208387015190910b8452909152902055611ee5565b608080820151600090815260086020908152604091829020825161012081018452815460ff811615158252610100808204600290810b95840195909552600160201b8204850b958301959095526001600160401b03600160381b82041660608301526001600160801b03600160781b909104811695820195909552600182015480861660a08301819052600160801b90910490951660c08201529181015460e0830152600301549181019190915290151580611d36575060008160c001516001600160801b0316115b15611e05578051151587151514611d605760405163e86e44c160e01b815260040160405180910390fd5b6001600160a01b038a8116600090815260036020818152604092839020835160a08082018652825482526001830154938201939093526002820154861694810194909452909101549283166060830152600160a01b90920462ffffff166080808301919091528401519184015160c08501519192611de2928492908c8b61445f565b611df18360800151858b614048565b6001600160801b0316606084015250611ee3565b6001600160a01b038a8116600090815260036020818152604092839020835160a0810185528154815260018201549281019290925260028101548516938201939093529101549182166060820152600160a01b90910462ffffff16608080830191909152830151611e7c90829089908d908c613f4b565b611e8a888460800151613fb7565b611ea48184608001518560a001518660c001518c8b61445f565b611eb38360800151858b614048565b6001600160801b031660608401526080830151835160208501516040860151611ee1938f93909290916141df565b505b505b7f559322b66708f28c8fe1386f8cd96634d0c2fdb250d925b71a6c15e11e26069c828a8984606001516008600087608001518152602001908152602001600020604051611f36959493929190615873565b60405180910390a160800151600090815260086020526040902054600160781b90046001600160801b03169150505b9695505050505050565b6000546001600160a01b03163314611f995760405162461bcd60e51b8152600401610d2690615521565b600954600160a01b900460ff16611fc357604051632960b58960e11b815260040160405180910390fd5b6009805460ff60a01b19169055604051600081527fb8527b93c36dabdfe078af41be789ba946a4adcfeafcf9d8de21d51629859e3c90602001610d6f565b6000606081612012848601866151d1565b90506000816001600160a01b0316633850c7bd6040518163ffffffff1660e01b815260040160e060405180830381865afa158015612054573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061207891906156b9565b505050506001600160a01b03858116600090815260036020818152604092839020835160a0810185528154815260018201549281019290925260028101548516938201939093529101549182166060820152600160a01b90910462ffffff1660808201529193509091506120ec9050614f41565b600080806120fc426103846158b0565b85519091501561221b578451600090815260086020908152604091829020825161012081018452815460ff81161515808352610100808304600290810b968501879052600160201b8404810b978501889052600160381b84046001600160401b03166060860152600160781b9093046001600160801b039081166080860152600186015480821660a0870152600160801b90041660c08501529184015460e08401526003909301549082015296506121b79289929091613890565b925060008360028111156121cd576121cd61575b565b0361221b57604080516001600160a01b03891660208201526001918101829052606081018390529099508992506080015b6040516020818303038152906040529750505050505050506110d0565b60208501511561232257602085810151600090815260088252604090819020815161012081018352815460ff81161515808352610100808304600290810b978501889052600160201b8404810b968501879052600160381b84046001600160401b03166060860152600160781b9093046001600160801b039081166080860152600186015480821660a0870152600160801b90041660c08501529184015460e08401526003909301549082015296506122d692899291613890565b925060008360028111156122ec576122ec61575b565b0361232257604080516001600160a01b038916602082015260009181018290526060810183905260019a509092506080016121fe565b60408051600060208201819052910160405160208183030381529060405298509850505050505050509250929050565b6000806000806000886001600160a01b0316633850c7bd6040518163ffffffff1660e01b815260040160e060405180830381865afa158015612398573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123bc91906156b9565b505050505091505060008060008b6001600160a01b031663d0c93a7c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612407573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061242b91906155cf565b9050612437818c6155ec565b60020b15612466576040516327deee8960e21b815260028c810b600483015282900b6024820152604401610d26565b8915612480578a925061247981846157a3565b9150612490565b61248a818c6157c8565b92508a91505b50600061249f8483858d613890565b905060018160028111156124b5576124b561575b565b146124e95760405163ea7469e760e01b8152600285810b60048301528c900b60248201528a15156044820152606401610d26565b506001600160a01b038b1660009081526004602090815260408083208c151584528252808320600285810b85529083528184209086900b8452909152812054945084900361254a576040516327bd01f960e21b815260040160405180910390fd5b505050600081815260086020526040812080549091600160781b9091046001600160801b0316900361258f5760405163d17ecf4960e01b815260040160405180910390fd5b8054600160781b90046001600160801b03908116600081815260076020908152604080832033808552925282205492965090929091168083036125ff5760405163775c73bf60e01b81526001600160a01b03831660048201526001600160801b0387166024820152604401610d26565b8354600160381b90046001600160401b031684600761261d836158c3565b82546001600160401b039182166101009390930a9283029190920219909116179055506001600160801b03861660009081526007602090815260408083206001600160a01b0386168452909152812080546001600160801b0319169055845460ff1615612724575060018401546001600160801b0390811690821681036126c0576001850180546001600160801b0319169055670de0b6b3a764000093506127c3565b806001600160801b0316826001600160801b0316670de0b6b3a76400006126e7919061555d565b6126f19190615592565b93506126fd82826158e6565b6001860180546001600160801b0319166001600160801b03929092169190911790556127c3565b5060018401546001600160801b03600160801b90910481169082168103612766576001850180546001600160801b03169055670de0b6b3a764000093506127c3565b806001600160801b0316826001600160801b0316670de0b6b3a764000061278d919061555d565b6127979190615592565b93506127a382826158e6565b6001860180546001600160801b03928316600160801b0292169190911790555b6127cf868e868d614816565b604051919a5098507f61e6e7599d7fb0402072db6fa40efca86866f1c441dc2515a79575743ab59cf79061280a9085908c908c908a9061590d565b60405180910390a183670de0b6b3a76400000361284e5761282c868e87614db6565b6000600186015584546fffffffffffffffffffffffffffffffff60781b191685555b5050825460ff16156128e6576001600160801b038716156128a0576001600160a01b03808c1660009081526003602052604090206002015461289b9116826001600160801b038a166132e0565b6128b9565b604051634a68d63560e11b815260040160405180910390fd5b6001600160801b038616156128e1576040516395f95a0760e01b815260040160405180910390fd5b612950565b6001600160801b038616156128a0576001600160a01b03808c16600090815260036020819052604090912001546129289116826001600160801b0389166132e0565b6001600160801b03871615612950576040516395f95a0760e01b815260040160405180910390fd5b505050509450945094915050565b6000546001600160a01b031633146129885760405162461bcd60e51b8152600401610d2690615521565b6001600160a01b038116600090815260016020526040812054908190036129cd5760405163117373e160e01b81526001600160a01b0383166004820152602401610d26565b6001600160a01b0380831660008181526001602052604081208190555461176c9216836132e0565b6000546001600160a01b03163314612a1f5760405162461bcd60e51b8152600401610d2690615521565b61ffff81161580612a345750601461ffff8216115b15612a52576040516394aa3c9160e01b815260040160405180910390fd5b6006805461ffff909216600160401b0269ffff000000000000000019909216919091179055565b6000546001600160a01b03163314612aa35760405162461bcd60e51b8152600401610d2690615521565b6001600160a01b038281166000908152600360205260409020600201541615612aea57604051635edc3a1b60e11b81526001600160a01b0383166004820152602401610d26565b8015612f1c57600054612b2b906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116911630846133b4565b60408051808201825260018152603160f81b6020909101819052600954825163181f5a7760e01b8152925191926001600160a01b039091169163181f5a77916004808201926000929091908290030181865afa158015612b8f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612bb79190810190615961565b601081518110612bc957612bc961594b565b01602001516001600160f81b03191603612d55576000604051806080016040528060488152602001615f216048913980516020918201206040805160008185015281518082039094018452810190526006549091903090612c3c9063ffffffff811690600160401b900461ffff166159ce565b600054604080516001600160a01b038a81166020830152909216910160408051601f1981840301815290829052612c8095949392918990604d9030906024016159fa565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092526009549151630200057560e51b81529092506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811692634000aea092612d0b92919091169086908690600401615ab1565b6020604051808303816000875af1158015612d2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d4e9190615ad8565b5050612f1c565b600954612d8f906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116911683614e7a565b604080516101408101825260146101008201908152734c696d6974204f7264657220526567697374727960601b61012083015281528151600060208083018290529093908301910160408051808303601f19018152918152908252306020830152600654910190612e129063ffffffff811690600160401b900461ffff166159ce565b63ffffffff1681526000546001600160a01b031660208083019190915260408051920191612e51918791016001600160a01b0391909116815260200190565b60405160208183030381529060405281526020016000604051602001612e80919060ff91909116815260200190565b60408051808303601f190181529181529082526001600160601b038516602090920191909152600954905163022de76960e21b81529192506001600160a01b0316906308b79da490612ed6908490600401615af5565b6020604051808303816000875af1158015612ef5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f19919061578a565b50505b6040518060a001604052806000815260200160008152602001836001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015612f73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f979190615be3565b6001600160a01b03168152602001836001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa158015612fe3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130079190615be3565b6001600160a01b03168152602001836001600160a01b031663ddca3f436040518163ffffffff1660e01b8152600401602060405180830381865afa158015613053573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130779190615c13565b62ffffff9081169091526001600160a01b0384811660008181526003602081815260409283902087518155878201516001820155878401516002820180549188166001600160a01b0319909216919091179055606088015192018054608090980151909616600160a01b026001600160b81b031990971691909416179490941790925591519081527f250d91a5317f78e9f385385f5e6073f9a759b17cfa6f5d2374163436fbb44ae4910160405180910390a15050565b6000546001600160a01b031633146131585760405162461bcd60e51b8152600401610d2690615521565b6001600160a01b0316600090815260056020526040902055565b61317a614f41565b50600090815260086020908152604091829020825161012081018452815460ff811615158252610100808204600290810b95840195909552600160201b8204850b958301959095526001600160401b03600160381b82041660608301526001600160801b03600160781b90910481166080830152600183015480821660a0840152600160801b90041660c08201529181015460e0830152600301549181019190915290565b6000546001600160a01b031633146132495760405162461bcd60e51b8152600401610d2690615521565b600080546001600160a01b0319166001600160a01b0383169081178255604051909133917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a350565b6000546001600160a01b031633146132be5760405162461bcd60e51b8152600401610d2690615521565b600980546001600160a01b0319166001600160a01b0392909216919091179055565b600060405163a9059cbb60e01b8152836004820152826024820152602060006044836000895af13d15601f3d11600160005114161716915050806133585760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b6044820152606401610d26565b50505050565b600080600080600085875af19050806133af5760405162461bcd60e51b815260206004820152601360248201527211551217d514905394d1915497d19052531151606a1b6044820152606401610d26565b505050565b60006040516323b872dd60e01b81528460048201528360248201528260448201526020600060648360008a5af13d15601f3d11600160005114161716915050806134375760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b6044820152606401610d26565b5050505050565b600080613449614f41565b856000036135db5783801561345e5750865115155b1561350f57508551600081815260086020908152604091829020825161012081018452815460ff811615158252610100808204600290810b95840195909552600160201b8204850b958301959095526001600160401b03600160381b82041660608301526001600160801b03600160781b90910481166080830152600183015480821660a0840152600160801b90041660c08201529181015460e083015260030154918101919091529095506136b0565b831580156135205750602087015115155b156135ce5750602080870151600081815260088352604090819020815161012081018352815460ff811615158252610100808204600290810b97840197909752600160201b8204870b948301949094526001600160401b03600160381b82041660608301526001600160801b03600160781b90910481166080830152600183015480821660a0840152600160801b90041660c08201529381015460e0850152600301549083015295506136b0565b6000809250925050613887565b50600085815260086020908152604091829020825161012081018452815460ff81161515808352610100808304600290810b96850196909652600160201b8304860b96840196909652600160381b82046001600160401b03166060840152600160781b9091046001600160801b039081166080840152600184015480821660a0850152600160801b90041660c08301529282015460e082015260039091015492810192909252841515146136a557604051630eb5001960e41b815260048101879052602401610d26565b6136b0868289614ef1565b855b84156137a1578560020b826040015160020b126136da57610100909101519092509050613887565b8160e001516000036136f3576000935091506138879050565b5060e090810151600081815260086020908152604091829020825161012081018452815460ff811615158252610100808204600290810b95840195909552600160201b8204850b958301959095526001600160401b03600160381b82041660608301526001600160801b03600160781b90910481166080830152600183015480821660a0840152600160801b90041660c08201529181015494820194909452600390930154908301526136b2565b8560020b826020015160020b136137c15760e09091015192509050613887565b8161010001516000036137db579250600091506138879050565b5061010090810151600081815260086020908152604091829020825161012081018452815460ff811615158252868104600290810b94830194909452600160201b8104840b94820194909452600160381b84046001600160401b03166060820152600160781b9093046001600160801b039081166080850152600182015480821660a0860152600160801b90041660c08401529081015460e083015260030154928101929092526136b2565b94509492505050565b60008360020b8360020b036138c957604051600162993c7b60e01b03198152600284810b600483015285900b6024820152604401610d26565b8115613902578260020b8560020b13156138e557506000610dfc565b8360020b8560020b126138fa57506002610dfc565b506001610dfc565b8360020b8560020b121561391857506000610dfc565b8260020b8560020b136138fa57506002610dfc565b8254600160781b81046001600160801b03166000908152600260205260409020600160381b9091046001600160401b0316906139698285615592565b6002820180546001600160801b0319166001600160801b039290921691909117905580546001600160a01b0319166001600160a01b0387161781556000806139bb8989670de0b6b3a764000088614816565b8854919350915060ff16156139ed576001808801546001600160801b03838116600160801b0291161790840155613a1d565b6001878101546001600160801b0319600160801b918290046001600160801b039081169092021690841617908401555b865460028401805460ff9092161515600160801b0260ff60801b1990921691909117905560006001880155865460408051600160781b9092046001600160801b031682526001600160a01b038a1660208301527f74ebbab24ee8774729982ac100f931306b160f431f7f1483cc380186d56754bc910160405180910390a1505050505050505050565b6001600160a01b03811660009081526005602052604081205490819003613aeb57604051630b90e8fb60e21b81526001600160a01b0383166004820152602401610d26565b808310156133af576040516360d7e97160e01b81526001600160a01b03831660048201526024810182905260448101849052606401610d26565b60008215613b74576040880151613b6f906001600160a01b03167f000000000000000000000000b218e4f7cf0533d4696fdfc419a0023d33345f286001600160801b038816614e7a565b613bb6565b6060880151613bb6906001600160a01b03167f000000000000000000000000b218e4f7cf0533d4696fdfc419a0023d33345f286001600160801b038716614e7a565b60006001600160801b03861615613be557612710613bd68761270f615c2e565b613be09190615c54565b613be8565b60005b905060006001600160801b03861615613c1957612710613c0a8761270f615c2e565b613c149190615c54565b613c1c565b60005b905060006040518061016001604052808c604001516001600160a01b031681526020018c606001516001600160a01b031681526020018c6080015162ffffff1681526020018a60020b81526020018b60020b8152602001896001600160801b03168152602001886001600160801b03168152602001846001600160801b03168152602001836001600160801b03168152602001306001600160a01b0316815260200186815250905060007f000000000000000000000000b218e4f7cf0533d4696fdfc419a0023d33345f286001600160a01b03166388316456836040518263ffffffff1660e01b8152600401613d129190615c7a565b6080604051808303816000875af1158015613d31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d559190615d49565b505050905080600003613d7b576040516327bd01f960e21b815260040160405180910390fd5b868015613e1c575060408c8101519051636eb1769f60e11b81523060048201526001600160a01b037f000000000000000000000000b218e4f7cf0533d4696fdfc419a0023d33345f2881166024830152600092169063dd62ed3e90604401602060405180830381865afa158015613df6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e1a919061578a565b115b15613e5b5760408c0151613e5b906001600160a01b03167f000000000000000000000000b218e4f7cf0533d4696fdfc419a0023d33345f286000614e7a565b86158015613efd575060608c0151604051636eb1769f60e11b81523060048201526001600160a01b037f000000000000000000000000b218e4f7cf0533d4696fdfc419a0023d33345f2881166024830152600092169063dd62ed3e90604401602060405180830381865afa158015613ed7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613efb919061578a565b115b15613f3c5760608c0151613f3c906001600160a01b03167f000000000000000000000000b218e4f7cf0533d4696fdfc419a0023d33345f286000614e7a565b9b9a5050505050505050505050565b600080613f5a8787878661343e565b9150915080600014613f875760008181526008602052604080822060020186905585825290206003018190555b8115613fae5760008281526008602052604080822060030186905585825290206002018290555b50505050505050565b600081815260086020526040902060068054600160501b90046001600160801b031690600a613fe583615d87565b82546101009290920a6001600160801b0381810219909316918316021790915582547fff00000000000000000000000000000000ffffffffffffffffffffffffffff0016600160781b929091169190910260ff1916179215159290921790915550565b6000838152600860205260408120805460ff16156140a9576001810180548491906000906140809084906001600160801b0316615dad565b92506101000a8154816001600160801b0302191690836001600160801b031602179055506140f4565b828160010160108282829054906101000a90046001600160801b03166140cf9190615dad565b92506101000a8154816001600160801b0302191690836001600160801b031602179055505b80546001600160801b03600160781b909104811660008181526007602090815260408083206001600160a01b038a1684529091528120549192919091169081900361417d578254600160381b90046001600160401b031683600761415783615dcd565b91906101000a8154816001600160401b0302191690836001600160401b03160217905550505b6141878582615dad565b6001600160801b0383811660009081526007602090815260408083206001600160a01b038c168452909152902080546001600160801b031916929091169190911790556141d48582615dad565b979650505050505050565b6001600160a01b03858116600090815260036020818152604092839020835160a08101855281548152600182015492810192909252600280820154861694830194909452909101549283166060820152600160a01b90920462ffffff16608083015283810b9085900b131561435357806020015160000361427d576001600160a01b0386166000908152600360205260409020600101859055614457565b602081810151600090815260088252604090819020815161012081018352815460ff811615158252610100808204600290810b968401879052600160201b8304810b95840195909552600160381b82046001600160401b03166060840152600160781b9091046001600160801b039081166080840152600184015480821660a0850152600160801b90041660c08301528383015460e083015260039092015491810191909152919085900b131561434d576001600160a01b03871660009081526003602052604090206001018690555b50614457565b8160020b8460020b121561445757805160000361438a576001600160a01b0386166000908152600360205260409020859055614457565b8051600090815260086020908152604091829020825161012081018452815460ff811615158252610100808204600290810b95840195909552600160201b8204850b958301869052600160381b82046001600160401b03166060840152600160781b9091046001600160801b039081166080840152600184015480821660a0850152600160801b90041660c08301528383015460e083015260039092015491810191909152919084900b1215613fae576001600160a01b0387166000908152600360205260409020869055505b505050505050565b81156144ac5760408601516144a7906001600160a01b03167f000000000000000000000000b218e4f7cf0533d4696fdfc419a0023d33345f286001600160801b038716614e7a565b6144ee565b60608601516144ee906001600160a01b03167f000000000000000000000000b218e4f7cf0533d4696fdfc419a0023d33345f286001600160801b038616614e7a565b60006001600160801b0385161561451d5761271061450e8661270f615c2e565b6145189190615c54565b614520565b60005b905060006001600160801b03851615614551576127106145428661270f615c2e565b61454c9190615c54565b614554565b60005b6040805160c0810182528981526001600160801b0389811660208301908152898216838501908152878316606085019081529286166080850190815260a085018a8152955163219f5d1760e01b81528551600482015292516024840152905160448301529151606482015290516084820152915160a48301529192507f000000000000000000000000b218e4f7cf0533d4696fdfc419a0023d33345f286001600160a01b03169063219f5d179060c4016060604051808303816000875af1158015614623573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146479190615de9565b5050508480156146eb57506040898101519051636eb1769f60e11b81523060048201526001600160a01b037f000000000000000000000000b218e4f7cf0533d4696fdfc419a0023d33345f2881166024830152600092169063dd62ed3e90604401602060405180830381865afa1580156146c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146e9919061578a565b115b1561472a57604089015161472a906001600160a01b03167f000000000000000000000000b218e4f7cf0533d4696fdfc419a0023d33345f286000614e7a565b841580156147cc57506060890151604051636eb1769f60e11b81523060048201526001600160a01b037f000000000000000000000000b218e4f7cf0533d4696fdfc419a0023d33345f2881166024830152600092169063dd62ed3e90604401602060405180830381865afa1580156147a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147ca919061578a565b115b1561480b57606089015161480b906001600160a01b03167f000000000000000000000000b218e4f7cf0533d4696fdfc419a0023d33345f286000614e7a565b505050505050505050565b60008060007f000000000000000000000000b218e4f7cf0533d4696fdfc419a0023d33345f286001600160a01b03166399fbab88886040518263ffffffff1660e01b815260040161486991815260200190565b61018060405180830381865afa158015614887573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148ab9190615e20565b50505050975050505050505050670de0b6b3a764000085826001600160801b03166148d6919061555d565b6148e09190615592565b6040805160a0810182528981526001600160801b0380841660208301908152600083850181815260608501828152608086018c81529651630624e65f60e11b81528651600482015293519094166024840152516044830152915160648201529251608484015292935091908190819081906001600160a01b037f000000000000000000000000b218e4f7cf0533d4696fdfc419a0023d33345f281690630c49ccbe9060a40160408051808303816000875af11580156149a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149c79190615efc565b604080516080810182526000808252602082018190529181018290526060810191909152919550935091506149f99050565b6000808a670de0b6b3a764000003614a1c57506001600160801b03905080614a22565b50839050825b604080516080810182528e81523060208083018290526001600160801b03958616838501529390941660608201526001600160a01b038e81166000908152600394859052838120600281015495015493516370a0823160e01b815260048101969096529195509283169391909216919083906370a0823190602401602060405180830381865afa158015614aba573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614ade919061578a565b6040516370a0823160e01b81523060048201529091506000906001600160a01b038416906370a0823190602401602060405180830381865afa158015614b28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614b4c919061578a565b6040805163fc6f786560e01b81528751600482015260208801516001600160a01b039081166024830152918801516001600160801b03908116604483015260608901511660648201529192507f000000000000000000000000b218e4f7cf0533d4696fdfc419a0023d33345f28169063fc6f78659060840160408051808303816000875af1158015614be2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614c069190615efc565b50506040516370a0823160e01b8152306004820152600090889084906001600160a01b038816906370a0823190602401602060405180830381865afa158015614c53573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614c77919061578a565b614c8191906155a6565b614c8b91906158e6565b6040516370a0823160e01b8152306004820152909150600090889084906001600160a01b038816906370a0823190602401602060405180830381865afa158015614cd9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614cfd919061578a565b614d0791906155a6565b614d1191906158e6565b90506001600160801b03821615614d59576001600160a01b038616600090815260016020526040812080546001600160801b0385169290614d539084906158b0565b90915550505b6001600160801b03811615614d9f576001600160a01b038516600090815260016020526040812080546001600160801b0384169290614d999084906158b0565b90915550505b50969f959e50949c50505050505050505050505050565b6001600160a01b03821660009081526003602052604090208054600190910154818503614e0c576000828152600860209081526040808320600201546001600160a01b0388168452600390925290912055614e40565b808503614e405760008181526008602090815260408083206003908101546001600160a01b03891685529252909120600101555b5050600280820180546003938401805460009081526008602052604080822090950183905581549281529384209094015581905590555050565b600060405163095ea7b360e01b8152836004820152826024820152602060006044836000895af13d15601f3d11600160005114161716915050806133585760405162461bcd60e51b815260206004820152600e60248201526d1054141493d59157d1905253115160921b6044820152606401610d26565b60e0820151158015614f065750610100820151155b156133af5780518314801590614f20575082816020015114155b156133af57604051630eb5001960e41b815260048101849052602401610d26565b6040805161012081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081019190915290565b600060208284031215614f9f57600080fd5b813563ffffffff81168114614fb357600080fd5b9392505050565b6001600160a01b0381168114614fcf57600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171561501057615010614fd2565b604052919050565b60006001600160401b0382111561503157615031614fd2565b50601f01601f191660200190565b6000806000806080858703121561505557600080fd5b843561506081614fba565b9350602085013561507081614fba565b92506040850135915060608501356001600160401b0381111561509257600080fd5b8501601f810187136150a357600080fd5b80356150b66150b182615018565b614fe8565b8181528860208385010111156150cb57600080fd5b8160208401602083013760006020838301015280935050505092959194509250565b6001600160801b0381168114614fcf57600080fd5b6000806040838503121561511557600080fd5b8235615120816150ed565b9150602083013561513081614fba565b809150509250929050565b60006020828403121561514d57600080fd5b8135614fb3816150ed565b8015158114614fcf57600080fd5b8060020b8114614fcf57600080fd5b6000806000806080858703121561518b57600080fd5b843561519681614fba565b935060208501356151a681615158565b925060408501356151b681615166565b915060608501356151c681615166565b939692955090935050565b6000602082840312156151e357600080fd5b8135614fb381614fba565b6000806000806080858703121561520457600080fd5b843561520f81614fba565b935060208501359250604085013561522681615166565b915060608501356151c681615158565b6000806020838503121561524957600080fd5b82356001600160401b038082111561526057600080fd5b818501915085601f83011261527457600080fd5b81358181111561528357600080fd5b86602082850101111561529557600080fd5b60209290920196919550909350505050565b60008060008060008060c087890312156152c057600080fd5b86356152cb81614fba565b955060208701356152db81615166565b945060408701356152eb816150ed565b935060608701356152fb81615158565b9598949750929560808101359460a0909101359350915050565b60005b83811015615330578181015183820152602001615318565b50506000910152565b60008151808452615351816020860160208601615315565b601f01601f19169290920160200192915050565b8215158152604060208201526000610dfc6040830184615339565b6000806000806080858703121561539657600080fd5b84356153a181614fba565b935060208501356153b181615166565b925060408501356153c181615158565b9396929550929360600135925050565b6000602082840312156153e357600080fd5b5035919050565b61ffff81168114614fcf57600080fd5b60006020828403121561540c57600080fd5b8135614fb3816153ea565b6000806040838503121561542a57600080fd5b823561543581614fba565b946020939093013593505050565b6000806040838503121561545657600080fd5b82359150602083013561513081614fba565b600061012082019050825115158252602083015160020b60208301526040830151615498604084018260020b9052565b5060608301516154b360608401826001600160401b03169052565b5060808301516154ce60808401826001600160801b03169052565b5060a08301516154e960a08401826001600160801b03169052565b5060c083015161550460c08401826001600160801b03169052565b5060e083015160e083015261010080840151818401525092915050565b6020808252600c908201526b15539055551213d49256915160a21b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b600081600019048311821515161561557757615577615547565b500290565b634e487b7160e01b600052601260045260246000fd5b6000826155a1576155a161557c565b500490565b818103818111156155b9576155b9615547565b92915050565b80516155ca81615166565b919050565b6000602082840312156155e157600080fd5b8151614fb381615166565b60008260020b806155ff576155ff61557c565b808360020b0791505092915050565b805169ffffffffffffffffffff811681146155ca57600080fd5b600080600080600060a0868803121561564057600080fd5b6156498661560e565b945060208601519350604086015192506060860151915061566c6080870161560e565b90509295509295909350565b60008060006060848603121561568d57600080fd5b833561569881614fba565b925060208401356156a881615158565b929592945050506040919091013590565b600080600080600080600060e0888a0312156156d457600080fd5b87516156df81614fba565b60208901519097506156f081615166565b6040890151909650615701816153ea565b6060890151909550615712816153ea565b6080890151909450615723816153ea565b60a089015190935060ff8116811461573a57600080fd5b60c089015190925061574b81615158565b8091505092959891949750929550565b634e487b7160e01b600052602160045260246000fd5b60006001820161578357615783615547565b5060010190565b60006020828403121561579c57600080fd5b5051919050565b600282810b9082900b03627fffff198112627fffff821317156155b9576155b9615547565b600281810b9083900b01627fffff8113627fffff19821217156155b9576155b9615547565b805460ff811615158352600881901c60020b6020840152602081901c60020b6040840152603881901c6001600160401b031660608401526001600160801b03607882901c8116608085015260018301546001600160801b038282161660a0860152915050608081901c60c084015250600281015460e08301526003015461010090910152565b6001600160a01b038681168252851660208201526001600160801b038481166040830152831660608201526101a08101611f6560808301846157ed565b808201808211156155b9576155b9615547565b60006001600160401b038216806158dc576158dc615547565b6000190192915050565b6001600160801b0382811682821603908082111561590657615906615547565b5092915050565b6001600160a01b03851681526001600160801b03848116602083015283166040820152610180810161594260608301846157ed565b95945050505050565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561597357600080fd5b81516001600160401b0381111561598957600080fd5b8201601f8101841361599a57600080fd5b80516159a86150b182615018565b8181528560208385010111156159bd57600080fd5b615942826020830160208601615315565b600063ffffffff808316818516818304811182151516156159f1576159f1615547565b02949350505050565b600061012080835260148184015250734c696d6974204f7264657220526567697374727960601b610140830152610160806020840152615a3c8184018c615339565b6001600160a01b038b8116604086015263ffffffff8b1660608601528916608085015283810360a08501529050615a738188615339565b9150506001600160601b03851660c083015260ff841660e0830152615aa46101008301846001600160a01b03169052565b9998505050505050505050565b60018060a01b03841681528260208201526060604082015260006159426060830184615339565b600060208284031215615aea57600080fd5b8151614fb381615158565b6020815260008251610100806020850152615b14610120850183615339565b91506020850151601f1980868503016040870152615b328483615339565b935060408701519150615b5060608701836001600160a01b03169052565b606087015163ffffffff81166080880152915060808701516001600160a01b03811660a0880152915060a08701519150808685030160c0870152615b948483615339565b935060c08701519150808685030160e087015250615bb28382615339565b92505060e0850151615bce828601826001600160601b03169052565b5090949350505050565b80516155ca81614fba565b600060208284031215615bf557600080fd5b8151614fb381614fba565b805162ffffff811681146155ca57600080fd5b600060208284031215615c2557600080fd5b614fb382615c00565b60006001600160801b03808316818516818304811182151516156159f1576159f1615547565b60006001600160801b0380841680615c6e57615c6e61557c565b92169190910492915050565b81516001600160a01b0316815261016081016020830151615ca660208401826001600160a01b03169052565b506040830151615cbd604084018262ffffff169052565b506060830151615cd2606084018260020b9052565b506080830151615ce7608084018260020b9052565b5060a083015160a083015260c083015160c083015260e083015160e083015261010080840151818401525061012080840151615d2d828501826001600160a01b03169052565b505061014092830151919092015290565b80516155ca816150ed565b60008060008060808587031215615d5f57600080fd5b845193506020850151615d71816150ed565b6040860151606090960151949790965092505050565b60006001600160801b03808316818103615da357615da3615547565b6001019392505050565b6001600160801b0381811683821601908082111561590657615906615547565b60006001600160401b03808316818103615da357615da3615547565b600080600060608486031215615dfe57600080fd5b8351615e09816150ed565b602085015160409095015190969495509392505050565b6000806000806000806000806000806000806101808d8f031215615e4357600080fd5b8c516001600160601b0381168114615e5a57600080fd5b9b50615e6860208e01615bd8565b9a50615e7660408e01615bd8565b9950615e8460608e01615bd8565b9850615e9260808e01615c00565b9750615ea060a08e016155bf565b9650615eae60c08e016155bf565b9550615ebc60e08e01615d3e565b94506101008d015193506101208d01519250615edb6101408e01615d3e565b9150615eea6101608e01615d3e565b90509295989b509295989b509295989b565b60008060408385031215615f0f57600080fd5b50508051602090910151909290915056fe726567697374657228737472696e672c62797465732c616464726573732c75696e7433322c616464726573732c62797465732c75696e7439362c75696e74382c6164647265737329a2646970667358221220050050e9eeef002bff0490b18116493419b20249972b8e2abbd9ef060d3e423f64736f6c63430008100033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000e75358526Ef4441Db03cCaEB9a87F180fAe80eb9000000000000000000000000B218e4f7cF0533d4696fDfC419A0023D33345F280000000000000000000000004300000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : _owner (address): 0xe75358526Ef4441Db03cCaEB9a87F180fAe80eb9
Arg [1] : _positionManager (address): 0xB218e4f7cF0533d4696fDfC419A0023D33345F28
Arg [2] : wrappedNative (address): 0x4300000000000000000000000000000000000004
Arg [3] : link (address): 0x0000000000000000000000000000000000000000
Arg [4] : _registrar (address): 0x0000000000000000000000000000000000000000
Arg [5] : _fastGasFeed (address): 0x0000000000000000000000000000000000000000
-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 000000000000000000000000e75358526Ef4441Db03cCaEB9a87F180fAe80eb9
Arg [1] : 000000000000000000000000B218e4f7cF0533d4696fDfC419A0023D33345F28
Arg [2] : 0000000000000000000000004300000000000000000000000000000000000004
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$94.78
Net Worth in ETH
0.03137
Token Allocations
ETH
60.29%
USDB
21.05%
WETH
18.66%
Multichain Portfolio | 35 Chains
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.