Feature Tip: Add private address tag to any address under My Name Tag !
More Info
Private Name Tags
ContractCreator
Latest 8 from a total of 8 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Add Pool | 18521830 | 434 days ago | IN | 0 ETH | 0.00805647 | ||||
Add Pool | 18521830 | 434 days ago | IN | 0 ETH | 0.00872987 | ||||
Add Pool | 18521830 | 434 days ago | IN | 0 ETH | 0.00872987 | ||||
Add Pool | 18521830 | 434 days ago | IN | 0 ETH | 0.00805647 | ||||
Add Pool | 18521830 | 434 days ago | IN | 0 ETH | 0.00805647 | ||||
Add Pool | 18521830 | 434 days ago | IN | 0 ETH | 0.00908185 | ||||
Add Pool | 18521830 | 434 days ago | IN | 0 ETH | 0.00927474 | ||||
Add Pool | 18521830 | 434 days ago | IN | 0 ETH | 0.01830942 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
LinkedPool
Compiler Version
v0.8.17+commit.8df45f5f
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; import {IPausable} from "./interfaces/IPausable.sol"; import {IndexedToken, IPoolModule} from "./interfaces/IPoolModule.sol"; import {ILinkedPool} from "./interfaces/ILinkedPool.sol"; import {IDefaultPool} from "./interfaces/IDefaultPool.sol"; import {Action} from "./libs/Structs.sol"; import {UniversalTokenLib} from "./libs/UniversalToken.sol"; import {TokenTree} from "./tree/TokenTree.sol"; import {Address} from "@openzeppelin/contracts-4.5.0/utils/Address.sol"; import {Ownable} from "@openzeppelin/contracts-4.5.0/access/Ownable.sol"; import {IERC20, SafeERC20} from "@openzeppelin/contracts-4.5.0/token/ERC20/utils/SafeERC20.sol"; /// LinkedPool is using an internal Token Tree to aggregate a collection of pools with correlated /// tokens into a single wrapper, conforming to IDefaultPool interface. /// The internal Token Tree allows to store up to 256 tokens, which should be enough for most use cases. /// Note: unlike traditional Default pools, tokens in LinkedPool could be duplicated. /// This contract is supposed to be used in conjunction with Synapse:Bridge: /// - The bridged token has index == 0, and could not be duplicated in the tree. /// - Other tokens (correlated to bridge token) could be duplicated in the tree. Every node token in the tree /// is represented by a trade path from root token to node token. /// > This is the reason why token could be duplicated. `nUSD -> USDC` and `nUSD -> USDT -> USDC` both represent /// > USDC token, but via different paths from nUSD, the bridge token. /// In addition to the standard IDefaultPool interface, LinkedPool also implements getters to observe the internal /// tree, as well as the best path finder between any two tokens in the tree. /// Note: LinkedPool assumes that the added pool tokens have no transfer fees enabled. contract LinkedPool is TokenTree, Ownable, ILinkedPool { using SafeERC20 for IERC20; using Address for address; using UniversalTokenLib for address; error LinkedPool__DeadlineExceeded(uint256 timestamp, uint256 deadline); error LinkedPool__EqualSwapIndexes(uint8 index); error LinkedPool__MinDyNotMet(uint256 amountOut, uint256 minDy); error LinkedPool__EmptyPoolAddress(); /// @notice Replicates signature of `TokenSwap` event from Default Pools. event TokenSwap(address indexed buyer, uint256 tokensSold, uint256 tokensBought, uint128 soldId, uint128 boughtId); constructor(address bridgeToken, address owner_) TokenTree(bridgeToken) { transferOwnership(owner_); } // ═════════════════════════════════════════════════ EXTERNAL ══════════════════════════════════════════════════════ /// @notice Adds a pool having `N` pool tokens to the tree by adding `N-1` new nodes /// as the children of the given node. Given node needs to represent a token from the pool. /// @dev `poolModule` should be set to address(this) if the pool conforms to IDefaultPool interface. /// Otherwise, it should be set to the address of the contract that implements the logic for pool handling. /// @param nodeIndex The index of the node to which the pool will be added /// @param pool The address of the pool /// @param poolModule The address of the pool module function addPool( uint256 nodeIndex, address pool, address poolModule ) external onlyOwner checkIndex(nodeIndex) { if (pool == address(0)) revert LinkedPool__EmptyPoolAddress(); _addPool(nodeIndex, pool, poolModule); } /// @notice Updates the pool module logic address for the given pool. /// @dev Will revert if the pool is not present in the tree, or if the new pool module /// produces a different token list for the pool. function updatePoolModule(address pool, address newPoolModule) external onlyOwner { _updatePoolModule(pool, newPoolModule); } /// @inheritdoc ILinkedPool function swap( uint8 nodeIndexFrom, uint8 nodeIndexTo, uint256 dx, uint256 minDy, uint256 deadline ) external checkIndex(nodeIndexFrom) checkIndex(nodeIndexTo) returns (uint256 amountOut) { // solhint-disable-next-line not-rely-on-time if (block.timestamp > deadline) revert LinkedPool__DeadlineExceeded(block.timestamp, deadline); if (nodeIndexFrom == nodeIndexTo) revert LinkedPool__EqualSwapIndexes(nodeIndexFrom); // Pull initial token from the user. LinkedPool assumes that the tokens have no transfer fees enabled, // thus the balance checks are omitted. address tokenIn = _nodes[nodeIndexFrom].token; IERC20(tokenIn).safeTransferFrom(msg.sender, address(this), dx); amountOut = _multiSwap(nodeIndexFrom, nodeIndexTo, dx).amountOut; if (amountOut < minDy) revert LinkedPool__MinDyNotMet(amountOut, minDy); // Transfer the tokens to the user IERC20(_nodes[nodeIndexTo].token).safeTransfer(msg.sender, amountOut); // Emit the event emit TokenSwap(msg.sender, dx, amountOut, nodeIndexFrom, nodeIndexTo); } // ═══════════════════════════════════════════════════ VIEWS ═══════════════════════════════════════════════════════ /// Note: this calculates a quote for a predefined swap path between two tokens. If any of the tokens is /// presented more than once in the internal tree, there might be a better quote. Integration should use /// findBestPath() instead. This function is present for backwards compatibility. /// @inheritdoc ILinkedPool function calculateSwap( uint8 nodeIndexFrom, uint8 nodeIndexTo, uint256 dx ) external view returns (uint256 amountOut) { uint256 totalTokens = _nodes.length; // Check that the token indexes are within range if (nodeIndexFrom >= totalTokens || nodeIndexTo >= totalTokens) { return 0; } // Check that the token indexes are not the same if (nodeIndexFrom == nodeIndexTo) { return 0; } // Calculate the quote by following the path from "tokenFrom" node to "tokenTo" node in the stored tree // This function might be called by Synapse:Bridge before the swap, so we don't waste gas checking if pool is paused, // as the swap will fail anyway if it is. amountOut = _getMultiSwapQuote({ nodeIndexFrom: nodeIndexFrom, nodeIndexTo: nodeIndexTo, amountIn: dx, probePaused: false }).amountOut; } /// @inheritdoc ILinkedPool function areConnectedTokens(address tokenIn, address tokenOut) external view returns (bool areConnected) { // Tokens are considered connected, if they are both present in the tree return _tokenNodes[tokenIn].length > 0 && _tokenNodes[tokenOut].length > 0; } /// Note: this could be potentially a gas expensive operation. This is used by SwapQuoterV2 to get the best quote /// for tokenIn -> tokenOut swap request (the call to SwapQuoter is an off-chain call). /// This should NOT be used as a part of "find path + perform a swap" on-chain flow. /// Instead, do an off-chain call to findBestPath() and then perform a swap using the found node indexes. /// As pair of token nodes defines only a single trade path (tree has no cycles), it will be possible to go /// through the found path by simply supplying the found indexes (instead of searching for the best path again). /// @inheritdoc ILinkedPool function findBestPath( address tokenIn, address tokenOut, uint256 amountIn ) external view returns ( uint8 nodeIndexFromBest, uint8 nodeIndexToBest, uint256 amountOutBest ) { // Check that the tokens are not the same and that the amount is not zero if (tokenIn == tokenOut || amountIn == 0) { return (0, 0, 0); } uint256 nodesFrom = _tokenNodes[tokenIn].length; uint256 nodesTo = _tokenNodes[tokenOut].length; // Go through every node that represents `tokenIn` for (uint256 i = 0; i < nodesFrom; ++i) { uint256 nodeIndexFrom = _tokenNodes[tokenIn][i]; // Go through every node that represents `tokenOut` for (uint256 j = 0; j < nodesTo; ++j) { uint256 nodeIndexTo = _tokenNodes[tokenOut][j]; // Calculate the quote by following the path from "tokenFrom" node to "tokenTo" node in the stored tree // We discard any paths with paused pools, as it's not possible to swap via them anyway. uint256 amountOut = _getMultiSwapQuote({ nodeIndexFrom: nodeIndexFrom, nodeIndexTo: nodeIndexTo, amountIn: amountIn, probePaused: true }).amountOut; if (amountOut > amountOutBest) { amountOutBest = amountOut; nodeIndexFromBest = uint8(nodeIndexFrom); nodeIndexToBest = uint8(nodeIndexTo); } } } } /// @inheritdoc ILinkedPool function getToken(uint8 index) external view checkIndex(index) returns (address token) { return _nodes[index].token; } /// @inheritdoc ILinkedPool function tokenNodesAmount() external view returns (uint256) { return _nodes.length; } /// @inheritdoc ILinkedPool function getAttachedPools(uint8 index) external view checkIndex(index) returns (address[] memory pools) { pools = new address[](_pools.length); uint256 amountAttached = 0; uint256 poolsMask = _attachedPools[index]; for (uint256 i = 0; i < pools.length; ) { // Check if _pools[i] is attached to the node at `index` unchecked { if ((poolsMask >> i) & 1 == 1) { pools[amountAttached++] = _pools[i]; } ++i; } } // Use assembly to shrink the array to the actual size // solhint-disable-next-line no-inline-assembly assembly { mstore(pools, amountAttached) } } /// @inheritdoc ILinkedPool function getTokenIndexes(address token) external view returns (uint256[] memory nodes) { nodes = _tokenNodes[token]; } /// @inheritdoc ILinkedPool function getPoolModule(address pool) external view returns (address) { return _poolMap[pool].module; } /// @inheritdoc ILinkedPool function getNodeParent(uint256 nodeIndex) external view checkIndex(nodeIndex) returns (uint256 parentIndex, address parentPool) { uint8 depth = _nodes[nodeIndex].depth; // Check if node is root, in which case there is no parent if (depth > 0) { parentIndex = _extractNodeIndex(_rootPath[nodeIndex], depth - 1); parentPool = _pools[_nodes[nodeIndex].poolIndex]; } } // ══════════════════════════════════════════════ INTERNAL LOGIC ═══════════════════════════════════════════════════ /// @dev Performs a single swap between two nodes using the given pool. /// Assumes that the initial token is already in this contract. function _poolSwap( address poolModule, address pool, uint256 nodeIndexFrom, uint256 nodeIndexTo, uint256 amountIn ) internal override returns (uint256 amountOut) { address tokenFrom = _nodes[nodeIndexFrom].token; address tokenTo = _nodes[nodeIndexTo].token; // Approve pool to spend the token, if needed if (poolModule == address(this)) { tokenFrom.universalApproveInfinity(pool, amountIn); // Pool conforms to IDefaultPool interface. Note: we check minDy and deadline outside of this function. amountOut = IDefaultPool(pool).swap({ tokenIndexFrom: tokenIndexes[pool][tokenFrom], tokenIndexTo: tokenIndexes[pool][tokenTo], dx: amountIn, minDy: 0, deadline: type(uint256).max }); } else { // Here we pass both token address and its index to the pool module, so it doesn't need to store // index<>token mapping. This allows Pool Module to be implemented in a stateless way, as some // pools require token index for interactions, while others require token address. // poolSwap(pool, tokenFrom, tokenTo, amountIn) bytes memory payload = abi.encodeWithSelector( IPoolModule.poolSwap.selector, pool, IndexedToken({index: tokenIndexes[pool][tokenFrom], token: tokenFrom}), IndexedToken({index: tokenIndexes[pool][tokenTo], token: tokenTo}), amountIn ); // Delegate swap logic to Pool Module. It should approve the pool to spend the token, if needed. // Note that poolModule address is set by the contract owner, so it's safe to delegatecall it. // Using OZ library here to bubble up the revert reason if the call fails. bytes memory result = poolModule.functionDelegateCall(payload); // Pool Modules are whitelisted, so we can trust the returned amountOut value. amountOut = abi.decode(result, (uint256)); } } // ══════════════════════════════════════════════ INTERNAL VIEWS ═══════════════════════════════════════════════════ /// @dev Returns the amount of tokens that will be received from a single swap. function _getPoolQuote( address poolModule, address pool, uint256 nodeIndexFrom, uint256 nodeIndexTo, uint256 amountIn, bool probePaused ) internal view override returns (uint256 amountOut) { if (poolModule == address(this)) { // Check if pool is paused, if requested if (probePaused) { // We issue a static call in case the pool does not conform to IPausable interface. (bool success, bytes memory returnData) = pool.staticcall( abi.encodeWithSelector(IPausable.paused.selector) ); if (success && abi.decode(returnData, (bool))) { // Pool is paused, return zero return 0; } } // Pool conforms to IDefaultPool interface. try IDefaultPool(pool).calculateSwap({ tokenIndexFrom: tokenIndexes[pool][_nodes[nodeIndexFrom].token], tokenIndexTo: tokenIndexes[pool][_nodes[nodeIndexTo].token], dx: amountIn }) returns (uint256 amountOut_) { amountOut = amountOut_; } catch { // Return zero if the pool getter reverts for any reason amountOut = 0; } } else { // Ask Pool Module to calculate the quote address tokenFrom = _nodes[nodeIndexFrom].token; address tokenTo = _nodes[nodeIndexTo].token; // Here we pass both token address and its index to the pool module, so it doesn't need to store // index<>token mapping. This allows Pool Module to be implemented in a stateless way, as some // pools require token index for interactions, while others require token address. try IPoolModule(poolModule).getPoolQuote( pool, IndexedToken({index: tokenIndexes[pool][tokenFrom], token: tokenFrom}), IndexedToken({index: tokenIndexes[pool][tokenTo], token: tokenTo}), amountIn, probePaused ) returns (uint256 amountOut_) { amountOut = amountOut_; } catch { // Return zero if the pool module getter reverts for any reason amountOut = 0; } } } /// @dev Returns the tokens in the pool at the given address. function _getPoolTokens(address poolModule, address pool) internal view override returns (address[] memory tokens) { if (poolModule == address(this)) { // Pool conforms to IDefaultPool interface. // First, figure out how many tokens there are in the pool uint256 numTokens = 0; while (true) { try IDefaultPool(pool).getToken(uint8(numTokens)) returns (address) { unchecked { ++numTokens; } } catch { break; } } // Then allocate the memory, and get the tokens tokens = new address[](numTokens); for (uint256 i = 0; i < numTokens; ) { tokens[i] = IDefaultPool(pool).getToken(uint8(i)); unchecked { ++i; } } } else { // Ask Pool Module to return the tokens // Note: this will revert if pool is not supported by the module, enforcing the invariant // that the added pools are supported by their specified module. tokens = IPoolModule(poolModule).getPoolTokens(pool); } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; interface IPausable { function paused() external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; import {IndexedToken} from "../libs/Structs.sol"; interface IPoolModule { /// @notice Performs a swap via the given pool, assuming `tokenFrom` is already in the contract. /// After the call, the contract should have custody over the received `tokenTo` tokens. /// @dev This will be used via delegatecall from LinkedPool, which will have the custody over the initial tokens, /// and will only use the correct pool address for interacting with the Pool Module. /// Note: Pool Module is responsible for issuing the token approvals, if `pool` requires them. /// Note: execution needs to be reverted, if swap fails for any reason. /// @param pool Address of the pool /// @param tokenFrom Token to swap from /// @param tokenTo Token to swap to /// @param amountIn Amount of tokenFrom to swap /// @return amountOut Amount of tokenTo received after the swap function poolSwap( address pool, IndexedToken memory tokenFrom, IndexedToken memory tokenTo, uint256 amountIn ) external returns (uint256 amountOut); /// @notice Returns a quote for a swap via the given pool. /// @dev This will be used by LinkedPool, which is supposed to pass only the correct pool address. /// Note: Pool Module should bubble the revert, if pool quote fails for any reason. /// Note: Pool Module should only revert if the pool is paused, if `probePaused` is true. /// @param pool Address of the pool /// @param tokenFrom Token to swap from /// @param tokenTo Token to swap to /// @param amountIn Amount of tokenFrom to swap /// @param probePaused Whether to check if the pool is paused /// @return amountOut Amount of tokenTo received after the swap function getPoolQuote( address pool, IndexedToken memory tokenFrom, IndexedToken memory tokenTo, uint256 amountIn, bool probePaused ) external view returns (uint256 amountOut); /// @notice Returns the list of tokens in the pool. Tokens should be returned in the same order /// that is used by the pool for indexing. /// @dev Execution needs to be reverted, if pool tokens retrieval fails for any reason, e.g. /// if the given pool is not compatible with the Pool Module. /// @param pool Address of the pool /// @return tokens Array of tokens in the pool function getPoolTokens(address pool) external view returns (address[] memory tokens); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; interface ILinkedPool { /// @notice Wrapper for IDefaultPool.swap() /// @param tokenIndexFrom the token the user wants to swap from /// @param tokenIndexTo the token the user wants to swap to /// @param dx the amount of tokens the user wants to swap from /// @param minDy the min amount the user would like to receive, or revert. /// @param deadline latest timestamp to accept this transaction /// @return amountOut amount of tokens bought function swap( uint8 tokenIndexFrom, uint8 tokenIndexTo, uint256 dx, uint256 minDy, uint256 deadline ) external returns (uint256 amountOut); // ═══════════════════════════════════════════════════ VIEWS ═══════════════════════════════════════════════════════ /// @notice Wrapper for IDefaultPool.calculateSwap() /// @param tokenIndexFrom the token the user wants to sell /// @param tokenIndexTo the token the user wants to buy /// @param dx the amount of tokens the user wants to sell. If the token charges /// a fee on transfers, use the amount that gets transferred after the fee. /// @return amountOut amount of tokens the user will receive function calculateSwap( uint8 tokenIndexFrom, uint8 tokenIndexTo, uint256 dx ) external view returns (uint256 amountOut); /// @notice Wrapper for IDefaultPool.getToken() /// @param index the index of the token /// @return token address of the token at given index function getToken(uint8 index) external view returns (address token); /// @notice Checks if a path exists between the two tokens, using any of the supported pools. /// @dev This is used by SwapQuoterV2 to check if a path exists between two tokens using the LinkedPool. /// Note: this only checks if both tokens are present in the tree, but doesn't check if any of the pools /// connecting the two tokens are paused. This is done to enable caching of the result, the paused/duplicated /// pools will be discarded, when `findBestPath` is called to fetch the quote. /// @param tokenIn Token address to begin from /// @param tokenOut Token address to end up with /// @return areConnected True if a path exists between the two tokens, false otherwise function areConnectedTokens(address tokenIn, address tokenOut) external view returns (bool areConnected); /// @notice Returns the best path for swapping the given amount of tokens. All possible paths /// present in the internal tree are considered, if any of the tokens are present in the tree more than once. /// Note: paths that have the same pool more than once are not considered. /// @dev Will return zero values if no path is found. /// @param tokenIn the token the user wants to sell /// @param tokenOut the token the user wants to buy /// @param amountIn the amount of tokens the user wants to sell /// @return tokenIndexFrom the index of the token the user wants to sell /// @return tokenIndexTo the index of the token the user wants to buy /// @return amountOut amount of tokens the user will receive function findBestPath( address tokenIn, address tokenOut, uint256 amountIn ) external view returns ( uint8 tokenIndexFrom, uint8 tokenIndexTo, uint256 amountOut ); /// @notice Returns the full amount of the "token nodes" in the internal tree. /// Note that some of the tokens might be duplicated, as the node in the tree represents /// a given path frm the bridge token to the node token using a series of pools. function tokenNodesAmount() external view returns (uint256); /// @notice Returns the list of pools that are "attached" to a node. /// Pool is attached to a node, if it connects the node to one of its children. /// Note: pool that is connecting the node to its parent is not considered attached. function getAttachedPools(uint8 index) external view returns (address[] memory pools); /// @notice Returns the list of indexes that represent a given token in the tree. /// @dev Will return empty array for tokens that are not added to the tree. function getTokenIndexes(address token) external view returns (uint256[] memory indexes); /// @notice Returns the pool module logic address, that is used to get swap quotes, token indexes and perform swaps. /// @dev Will return address(0) for pools that are not added to the tree. /// Will return address(this) for pools that conform to IDefaultPool interface. function getPoolModule(address pool) external view returns (address poolModule); /// @notice Returns the index of a parent node for the given node, as well as the pool that connects the two nodes. /// @dev Will return zero values for the root node. Will revert if index is out of range. function getNodeParent(uint256 nodeIndex) external view returns (uint256 parentIndex, address parentPool); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; interface IDefaultPool { function swap( uint8 tokenIndexFrom, uint8 tokenIndexTo, uint256 dx, uint256 minDy, uint256 deadline ) external returns (uint256 amountOut); function calculateSwap( uint8 tokenIndexFrom, uint8 tokenIndexTo, uint256 dx ) external view returns (uint256 amountOut); function getToken(uint8 index) external view returns (address token); }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.13; // "using A for B global" requires 0.8.13 or higher // ══════════════════════════════════════════ TOKEN AND POOL DESCRIPTION ═══════════════════════════════════════════════ /// @notice Struct representing a bridge token. Used as the return value in view functions. /// @param symbol Bridge token symbol: unique token ID consistent among all chains /// @param token Bridge token address struct BridgeToken { string symbol; address token; } /// @notice Struct used by IPoolHandler to represent a token in a pool /// @param index Token index in the pool /// @param token Token address struct IndexedToken { uint8 index; address token; } /// @notice Struct representing a token, and the available Actions for performing a swap. /// @param actionMask Bitmask representing what actions (see ActionLib) are available for swapping a token /// @param token Token address struct LimitedToken { uint256 actionMask; address token; } /// @notice Struct representing how pool tokens are stored by `SwapQuoter`. /// @param isWeth Whether the token represents Wrapped ETH. /// @param token Token address. struct PoolToken { bool isWeth; address token; } /// @notice Struct representing a liquidity pool. Used as the return value in view functions. /// @param pool Pool address. /// @param lpToken Address of pool's LP token. /// @param tokens List of pool's tokens. struct Pool { address pool; address lpToken; PoolToken[] tokens; } // ════════════════════════════════════════════════ ROUTER STRUCTS ═════════════════════════════════════════════════════ /// @notice Struct representing a quote request for swapping a bridge token. /// Used in destination chain's SynapseRouter, hence the name "Destination Request". /// @dev tokenOut is passed externally. /// @param symbol Bridge token symbol: unique token ID consistent among all chains /// @param amountIn Amount of bridge token to start with, before the bridge fee is applied struct DestRequest { string symbol; uint256 amountIn; } /// @notice Struct representing a swap request for SynapseRouter. /// @dev tokenIn is supplied separately. /// @param routerAdapter Contract that will perform the swap for the Router. Address(0) specifies a "no swap" query. /// @param tokenOut Token address to swap to. /// @param minAmountOut Minimum amount of tokens to receive after the swap, or tx will be reverted. /// @param deadline Latest timestamp for when the transaction needs to be executed, or tx will be reverted. /// @param rawParams ABI-encoded params for the swap that will be passed to `routerAdapter`. /// Should be DefaultParams for swaps via DefaultAdapter. struct SwapQuery { address routerAdapter; address tokenOut; uint256 minAmountOut; uint256 deadline; bytes rawParams; } using SwapQueryLib for SwapQuery global; library SwapQueryLib { /// @notice Checks whether the router adapter was specified in the query. /// Query without a router adapter specifies that no action needs to be taken. function hasAdapter(SwapQuery memory query) internal pure returns (bool) { return query.routerAdapter != address(0); } /// @notice Fills `routerAdapter` and `deadline` fields in query, if it specifies one of the supported Actions, /// and if a path for this action was found. function fillAdapterAndDeadline(SwapQuery memory query, address routerAdapter) internal pure { // Fill the fields only if some path was found. if (query.minAmountOut == 0) return; // Empty params indicates no action needs to be done, thus no adapter is needed. query.routerAdapter = query.rawParams.length == 0 ? address(0) : routerAdapter; // Set default deadline to infinity. Not using the value of 0, // which would lead to every swap to revert by default. query.deadline = type(uint256).max; } } // ════════════════════════════════════════════════ ADAPTER STRUCTS ════════════════════════════════════════════════════ /// @notice Struct representing parameters for swapping via DefaultAdapter. /// @param action Action that DefaultAdapter needs to perform. /// @param pool Liquidity pool that will be used for Swap/AddLiquidity/RemoveLiquidity actions. /// @param tokenIndexFrom Token index to swap from. Used for swap/addLiquidity actions. /// @param tokenIndexTo Token index to swap to. Used for swap/removeLiquidity actions. struct DefaultParams { Action action; address pool; uint8 tokenIndexFrom; uint8 tokenIndexTo; } /// @notice All possible actions that DefaultAdapter could perform. enum Action { Swap, // swap between two pools tokens AddLiquidity, // add liquidity in a form of a single pool token RemoveLiquidity, // remove liquidity in a form of a single pool token HandleEth // ETH <> WETH interaction } using ActionLib for Action global; /// @notice Library for dealing with bit masks which describe what set of Actions is available. library ActionLib { /// @notice Returns a bitmask with all possible actions set to True. function allActions() internal pure returns (uint256 actionMask) { actionMask = type(uint256).max; } /// @notice Returns whether the given action is set to True in the bitmask. function isIncluded(Action action, uint256 actionMask) internal pure returns (bool) { return actionMask & mask(action) != 0; } /// @notice Returns a bitmask with only the given action set to True. function mask(Action action) internal pure returns (uint256) { return 1 << uint256(action); } /// @notice Returns a bitmask with only two given actions set to True. function mask(Action a, Action b) internal pure returns (uint256) { return mask(a) | mask(b); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; import {TokenNotContract} from "./Errors.sol"; import {SafeERC20, IERC20} from "@openzeppelin/contracts-4.5.0/token/ERC20/utils/SafeERC20.sol"; library UniversalTokenLib { using SafeERC20 for IERC20; address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; /// @notice Transfers tokens to the given account. Reverts if transfer is not successful. /// @dev This might trigger fallback, if ETH is transferred to the contract. /// Make sure this can not lead to reentrancy attacks. function universalTransfer( address token, address to, uint256 value ) internal { // Don't do anything, if need to send tokens to this address if (to == address(this)) return; if (token == ETH_ADDRESS) { /// @dev Note: this can potentially lead to executing code in `to`. // solhint-disable-next-line avoid-low-level-calls (bool success, ) = to.call{value: value}(""); require(success, "ETH transfer failed"); } else { IERC20(token).safeTransfer(to, value); } } /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient /// to spend the given amount. function universalApproveInfinity( address token, address spender, uint256 amountToSpend ) internal { // ETH Chad doesn't require your approval if (token == ETH_ADDRESS) return; // No-op if allowance is already sufficient uint256 allowance = IERC20(token).allowance(address(this), spender); if (allowance >= amountToSpend) return; // Otherwise, reset approval to 0 and set to max allowance if (allowance > 0) IERC20(token).safeApprove(spender, 0); IERC20(token).safeApprove(spender, type(uint256).max); } /// @notice Returns the balance of the given token (or native ETH) for the given account. function universalBalanceOf(address token, address account) internal view returns (uint256) { if (token == ETH_ADDRESS) { return account.balance; } else { return IERC20(token).balanceOf(account); } } /// @dev Checks that token is a contract and not ETH_ADDRESS. function assertIsContract(address token) internal view { // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains) if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract(); // Check that token is not an EOA if (token.code.length == 0) revert TokenNotContract(); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; /// TokenTree implements the internal logic for storing a set of tokens in a rooted tree. /// - Root node represents a Synapse-bridged token. /// - The root token could not appear more than once in the tree. /// - Other tree nodes represent tokens that are correlated with the root token. /// - These other tokens could appear more than once in the tree. /// - Every edge between a child and a parent node is associated with a single liquidity pool that contains both tokens. /// - The tree is rooted => the root of the tree has a zero depth. A child node depth is one greater than its parent. /// - Every node can have arbitrary amount of children. /// - New nodes are added to the tree by "attaching" a pool to an existing node. This adds all the other pool tokens /// as new children of the existing node (which represents one of the tokens from the pool). /// - Pool could be only attached once to any given node. Pool could not be attached to a node, if it connects the node /// with its parent. /// - Pool could be potentially attached to two different nodes in the tree. /// - By definition a tree has no cycles, so there exists only one path between any two nodes. Every edge on this path /// represents a liquidity pool, and the whole path represents a series of swaps that lead from one token to another. /// - Paths that contain a pool more than once are not allowed, and are not used for quotes/swaps. This is due to /// the fact that it's impossible to get an accurate quote for the second swap through the pool in the same tx. /// > This contract is only responsible for storing and traversing the tree. The swap/quote logic, as well as /// > transformation of the inner tree into IDefaultPool interface is implemented in the child contract. abstract contract TokenTree { error TokenTree__DifferentTokenLists(); error TokenTree__IndexOutOfRange(uint256 index); error TokenTree__NodeTokenNotInPool(); error TokenTree__PoolAlreadyAttached(); error TokenTree__PoolAlreadyOnRootPath(); error TokenTree__SwapPoolUsedTwice(address pool); error TokenTree__TooManyNodes(); error TokenTree__TooManyPools(); error TokenTree__UnknownPool(); event TokenNodeAdded(uint256 childIndex, address token, address parentPool); event PoolAdded(uint256 parentIndex, address pool, address poolModule); event PoolModuleUpdated(address pool, address oldPoolModule, address newPoolModule); /// @notice Struct so store the tree nodes /// @param token Address of the token represented by this node /// @param depth Depth of the node in the tree /// @param poolIndex Index of the pool that connects this node to its parent (0 if root) struct Node { address token; uint8 depth; uint8 poolIndex; } /// @notice Struct to store the liquidity pools /// @dev Module address is used for delegate calls to get swap quotes, token indexes, etc. /// Set to address(this) if pool conforms to IDefaultPool interface. Set to 0x0 if pool is not supported. /// @param module Address of the module contract for this pool /// @param index Index of the pool in the `_pools` array struct Pool { address module; uint8 index; } /// @notice Struct to get around stack too deep error /// @param from Node representing the token we are swapping from /// @param to Node representing the token we are swapping to struct Request { Node from; Node to; bool probePaused; } /// @notice Struct to get around stack too deep error /// @param visitedPoolsMask Bitmask of pools visited so far /// @param amountOut Amount of tokens received so far struct Route { uint256 visitedPoolsMask; uint256 amountOut; } // ══════════════════════════════════════════════════ STORAGE ══════════════════════════════════════════════════════ // The nodes of the tree are stored in an array. The root node is at index 0. Node[] internal _nodes; // The list of all supported liquidity pools. All values are unique. address[] internal _pools; // (pool address => pool description) mapping(address => Pool) internal _poolMap; // (pool => token => tokenIndex) for each pool, stores the index of each token in the pool. mapping(address => mapping(address => uint8)) public tokenIndexes; // (token => nodes) for each token, stores the indexes of all nodes that represent this token. mapping(address => uint256[]) internal _tokenNodes; // The full path from every node to the root is stored using bitmasks in the following way: // - For a node with index i at depth N, lowest N + 1 bytes of _rootPath[i] are used to store the path to the root. // - The lowest byte is always the root index. This is always 0, but we store this for consistency. // - The highest byte is always the node index. This is always i, but we store this for consistency. // - The remaining bytes are indexes of the nodes on the path from the node to the root (from highest to lowest). // This way the finding the lowest common ancestor of two nodes is reduced to finding the lowest differing byte // in node's encoded root paths. uint256[] internal _rootPath; // (node => bitmask with all attached pools to the node). // Note: This excludes the pool that connects the node to its parent. mapping(uint256 => uint256) internal _attachedPools; // ════════════════════════════════════════════════ CONSTRUCTOR ════════════════════════════════════════════════════ constructor(address bridgeToken) { // Push the empty pool so that `poolIndex` for non-root nodes is never 0 _pools.push(address(0)); // The root node is always the bridge token _addNode({token: bridgeToken, depth: 0, poolIndex: 0, rootPathParent: 0}); } modifier checkIndex(uint256 nodeIndex) { if (nodeIndex >= _nodes.length) revert TokenTree__IndexOutOfRange(nodeIndex); _; } // ══════════════════════════════════════════════ INTERNAL LOGIC ═══════════════════════════════════════════════════ /// @dev Adds a pool having `N` pool tokens to the tree by adding `N-1` new nodes /// as the children of the given node. Given node needs to represent a token from the pool. /// Note: assumes that nodeIndex is valid, and that pool is not a zero address. function _addPool( uint256 nodeIndex, address pool, address poolModule ) internal { Node memory node = _nodes[nodeIndex]; if (poolModule == address(0)) poolModule = address(this); (bool wasAdded, uint8 poolIndex) = (false, _poolMap[pool].index); // Save the pool and emit an event if it's not been added before if (poolIndex == 0) { if (_pools.length > type(uint8).max) revert TokenTree__TooManyPools(); // Can do the unsafe cast here, as we just checked that pool index fits into uint8 poolIndex = uint8(_pools.length); _pools.push(pool); _poolMap[pool] = Pool({module: poolModule, index: poolIndex}); wasAdded = true; emit PoolAdded(nodeIndex, pool, poolModule); } else { // Check if the existing pool could be added to the node. This enforces some sanity checks, // as well the invariant that any path from root to node doesn't contain the same pool twice. _checkPoolAddition(nodeIndex, node.depth, poolIndex); } // Remember that the pool is attached to the node _attachedPools[nodeIndex] |= 1 << poolIndex; address[] memory tokens = _getPoolTokens(poolModule, pool); uint256 numTokens = tokens.length; bool nodeFound = false; unchecked { uint8 childDepth = node.depth + 1; uint256 rootPathParent = _rootPath[nodeIndex]; for (uint256 i = 0; i < numTokens; ++i) { address token = tokens[i]; // Save token indexes if this is a new pool if (wasAdded) { tokenIndexes[pool][token] = uint8(i); } // Add new nodes to the tree if (token == node.token) { nodeFound = true; continue; } _addNode(token, childDepth, poolIndex, rootPathParent); } } if (!nodeFound) revert TokenTree__NodeTokenNotInPool(); } /// @dev Adds a new node to the tree and saves its path to the root. function _addNode( address token, uint8 depth, uint8 poolIndex, uint256 rootPathParent ) internal { // Index of the newly inserted child node uint256 nodeIndex = _nodes.length; if (nodeIndex > type(uint8).max) revert TokenTree__TooManyNodes(); // Don't add the bridge token (root) twice. This may happen if we add a new pool containing the bridge token // to a few existing nodes. E.g. we have old nUSD/USDC/USDT pool, and we add a new nUSD/USDC pool. In this case // we attach nUSD/USDC pool to root, and then attach old nUSD/USDC/USDT pool to the newly added USDC node // to enable nUSD -> USDC -> USDT swaps via new + old pools. if (_nodes.length > 0 && token == _nodes[0].token) { return; } _nodes.push(Node({token: token, depth: depth, poolIndex: poolIndex})); _tokenNodes[token].push(nodeIndex); // Push the root path for the new node. The root path is the inserted node index + the parent's root path. _rootPath.push((nodeIndex << (8 * depth)) | rootPathParent); emit TokenNodeAdded(nodeIndex, token, _pools[poolIndex]); } /// @dev Updates the Pool Module for the given pool. /// Will revert, if the pool was not previously added, or if the new pool module produces a different list of tokens. function _updatePoolModule(address pool, address newPoolModule) internal { // Check that pool was previously added address oldPoolModule = _poolMap[pool].module; if (oldPoolModule == address(0)) revert TokenTree__UnknownPool(); // Sanity check that pool modules produce the same list of tokens address[] memory oldTokens = _getPoolTokens(oldPoolModule, pool); address[] memory newTokens = _getPoolTokens(newPoolModule, pool); if (oldTokens.length != newTokens.length) revert TokenTree__DifferentTokenLists(); for (uint256 i = 0; i < oldTokens.length; ++i) { if (oldTokens[i] != newTokens[i]) revert TokenTree__DifferentTokenLists(); } // Update the pool module _poolMap[pool].module = newPoolModule; emit PoolModuleUpdated(pool, oldPoolModule, newPoolModule); } // ══════════════════════════════════════ INTERNAL LOGIC: MULTIPLE POOLS ═══════════════════════════════════════════ /// @dev Performs a multi-hop swap by following the path from "tokenFrom" node to "tokenTo" node /// in the stored tree. Token indexes are checked to be within range and not the same. /// Assumes that the initial token is already in this contract. function _multiSwap( uint256 nodeIndexFrom, uint256 nodeIndexTo, uint256 amountIn ) internal returns (Route memory route) { // Struct to get around stack too deep Request memory req = Request({from: _nodes[nodeIndexFrom], to: _nodes[nodeIndexTo], probePaused: false}); uint256 rootPathFrom = _rootPath[nodeIndexFrom]; uint256 rootPathTo = _rootPath[nodeIndexTo]; // Find the depth where the paths diverge uint256 depthDiff = _depthDiff(rootPathFrom, rootPathTo); // Check if `nodeIndexTo` is an ancestor of `nodeIndexFrom`. True if paths diverge below `nodeIndexTo`. if (depthDiff > req.to.depth) { // Path from "tokenFrom" to root includes "tokenTo", // so we simply go from "tokenFrom" to "tokenTo" in the "to root" direction. return _multiSwapToRoot(0, rootPathFrom, req.from.depth, req.to.depth, amountIn); } // Check if `nodeIndexFrom` is an ancestor of `nodeIndexTo`. True if paths diverge below `nodeIndexFrom`. if (depthDiff > req.from.depth) { // Path from "tokenTo" to root includes "tokenFrom", // so we simply go from "tokenTo" to "tokenFrom" in the "from root" direction. return _multiSwapFromRoot(0, rootPathTo, req.from.depth, req.to.depth, amountIn); } // First, we traverse up the tree from "tokenFrom" to one level deeper the lowest common ancestor. route = _multiSwapToRoot(0, rootPathFrom, req.from.depth, depthDiff, amountIn); // Check if we need to do a sibling swap. When the two nodes are connected to the same parent via the same pool, // we do a direct swap between the two nodes, instead of doing two swaps through the parent using the same pool. uint256 lastNodeIndex = _extractNodeIndex(rootPathFrom, depthDiff); uint256 siblingIndex = _extractNodeIndex(rootPathTo, depthDiff); uint256 firstPoolIndex = _nodes[lastNodeIndex].poolIndex; uint256 secondPoolIndex = _nodes[siblingIndex].poolIndex; if (firstPoolIndex == secondPoolIndex) { // Swap lastNode -> sibling (route.visitedPoolsMask, route.amountOut) = _singleSwap( route.visitedPoolsMask, firstPoolIndex, lastNodeIndex, siblingIndex, route.amountOut ); } else { // Swap lastNode -> parent uint256 parentIndex = _extractNodeIndex(rootPathFrom, depthDiff - 1); (route.visitedPoolsMask, route.amountOut) = _singleSwap( route.visitedPoolsMask, firstPoolIndex, lastNodeIndex, parentIndex, route.amountOut ); // Swap parent -> sibling (route.visitedPoolsMask, route.amountOut) = _singleSwap( route.visitedPoolsMask, secondPoolIndex, parentIndex, siblingIndex, route.amountOut ); } // Finally, we traverse down the tree from the lowest common ancestor to "tokenTo". return _multiSwapFromRoot(route.visitedPoolsMask, rootPathTo, depthDiff, req.to.depth, route.amountOut); } /// @dev Performs a multi-hop swap, going in "from root direction" (where depth increases) /// via the given `rootPath` from `depthFrom` to `depthTo`. /// Assumes that the initial token is already in this contract. function _multiSwapFromRoot( uint256 visitedPoolsMask, uint256 rootPath, uint256 depthFrom, uint256 depthTo, uint256 amountIn ) internal returns (Route memory route) { uint256 nodeIndex = _extractNodeIndex(rootPath, depthFrom); // Traverse down the tree following `rootPath` from `depthFrom` to `depthTo`. for (uint256 depth = depthFrom; depth < depthTo; ) { // Get the child node unchecked { ++depth; } uint256 childIndex = _extractNodeIndex(rootPath, depth); // Swap node -> child (visitedPoolsMask, amountIn) = _singleSwap( visitedPoolsMask, _nodes[childIndex].poolIndex, nodeIndex, childIndex, amountIn ); nodeIndex = childIndex; } route.visitedPoolsMask = visitedPoolsMask; route.amountOut = amountIn; } /// @dev Performs a multi-hop swap, going in "to root direction" (where depth decreases) /// via the given `rootPath` from `depthFrom` to `depthTo`. /// Assumes that the initial token is already in this contract. function _multiSwapToRoot( uint256 visitedPoolsMask, uint256 rootPath, uint256 depthFrom, uint256 depthTo, uint256 amountIn ) internal returns (Route memory route) { uint256 nodeIndex = _extractNodeIndex(rootPath, depthFrom); // Traverse up the tree following `rootPath` from `depthFrom` to `depthTo`. for (uint256 depth = depthFrom; depth > depthTo; ) { // Get the parent node unchecked { --depth; // depth > 0 so we can do unchecked math } uint256 parentIndex = _extractNodeIndex(rootPath, depth); // Swap node -> parent (visitedPoolsMask, amountIn) = _singleSwap( visitedPoolsMask, _nodes[nodeIndex].poolIndex, nodeIndex, parentIndex, amountIn ); nodeIndex = parentIndex; } route.visitedPoolsMask = visitedPoolsMask; route.amountOut = amountIn; } // ════════════════════════════════════════ INTERNAL LOGIC: SINGLE POOL ════════════════════════════════════════════ /// @dev Performs a single swap between two nodes using the given pool. /// Assumes that the initial token is already in this contract. function _poolSwap( address poolModule, address pool, uint256 nodeIndexFrom, uint256 nodeIndexTo, uint256 amountIn ) internal virtual returns (uint256 amountOut); /// @dev Performs a single swap between two nodes using the given pool given the set of pools /// we have already used on the path. Returns the updated set of pools and the amount of tokens received. /// Assumes that the initial token is already in this contract. function _singleSwap( uint256 visitedPoolsMask, uint256 poolIndex, uint256 nodeIndexFrom, uint256 nodeIndexTo, uint256 amountIn ) internal returns (uint256 visitedPoolsMask_, uint256 amountOut) { address pool = _pools[poolIndex]; // If we already used this pool on the path, we can't use it again. if (visitedPoolsMask & (1 << poolIndex) != 0) revert TokenTree__SwapPoolUsedTwice(pool); // Mark the pool as visited visitedPoolsMask_ = visitedPoolsMask | (1 << poolIndex); amountOut = _poolSwap(_poolMap[pool].module, pool, nodeIndexFrom, nodeIndexTo, amountIn); } // ══════════════════════════════════════ INTERNAL VIEWS: MULTIPLE POOLS ═══════════════════════════════════════════ /// @dev Calculates the multi-hop swap quote by following the path from "tokenFrom" node to "tokenTo" node /// in the stored tree. Token indexes are checked to be within range and not the same. function _getMultiSwapQuote( uint256 nodeIndexFrom, uint256 nodeIndexTo, uint256 amountIn, bool probePaused ) internal view returns (Route memory route) { // Struct to get around stack too deep Request memory req = Request({from: _nodes[nodeIndexFrom], to: _nodes[nodeIndexTo], probePaused: probePaused}); uint256 rootPathFrom = _rootPath[nodeIndexFrom]; uint256 rootPathTo = _rootPath[nodeIndexTo]; // Find the depth where the paths diverge uint256 depthDiff = _depthDiff(rootPathFrom, rootPathTo); // Check if `nodeIndexTo` is an ancestor of `nodeIndexFrom`. True if paths diverge below `nodeIndexTo`. if (depthDiff > req.to.depth) { // Path from "tokenFrom" to root includes "tokenTo", // so we simply go from "tokenFrom" to "tokenTo" in the "to root" direction. return _getMultiSwapToRootQuote(0, rootPathFrom, req.from.depth, req.to.depth, amountIn, probePaused); } // Check if `nodeIndexFrom` is an ancestor of `nodeIndexTo`. True if paths diverge below `nodeIndexFrom`. if (depthDiff > req.from.depth) { // Path from "tokenTo" to root includes "tokenFrom", // so we simply go from "tokenTo" to "tokenFrom" in the "from root" direction. return _getMultiSwapFromRootQuote(0, rootPathTo, req.from.depth, req.to.depth, amountIn, probePaused); } // First, we traverse up the tree from "tokenFrom" to one level deeper the lowest common ancestor. route = _getMultiSwapToRootQuote( route.visitedPoolsMask, rootPathFrom, req.from.depth, depthDiff, amountIn, req.probePaused ); // Check if we need to do a sibling swap. When the two nodes are connected to the same parent via the same pool, // we do a direct swap between the two nodes, instead of doing two swaps through the parent using the same pool. uint256 lastNodeIndex = _extractNodeIndex(rootPathFrom, depthDiff); uint256 siblingIndex = _extractNodeIndex(rootPathTo, depthDiff); uint256 firstPoolIndex = _nodes[lastNodeIndex].poolIndex; uint256 secondPoolIndex = _nodes[siblingIndex].poolIndex; if (firstPoolIndex == secondPoolIndex) { // Swap lastNode -> sibling (route.visitedPoolsMask, route.amountOut) = _getSingleSwapQuote( route.visitedPoolsMask, firstPoolIndex, lastNodeIndex, siblingIndex, route.amountOut, req.probePaused ); } else { // Swap lastNode -> parent uint256 parentIndex = _extractNodeIndex(rootPathFrom, depthDiff - 1); (route.visitedPoolsMask, route.amountOut) = _getSingleSwapQuote( route.visitedPoolsMask, firstPoolIndex, lastNodeIndex, parentIndex, route.amountOut, req.probePaused ); // Swap parent -> sibling (route.visitedPoolsMask, route.amountOut) = _getSingleSwapQuote( route.visitedPoolsMask, secondPoolIndex, parentIndex, siblingIndex, route.amountOut, req.probePaused ); } // Finally, we traverse down the tree from the lowest common ancestor to "tokenTo". return _getMultiSwapFromRootQuote( route.visitedPoolsMask, rootPathTo, depthDiff, req.to.depth, route.amountOut, req.probePaused ); } /// @dev Calculates the amount of tokens that will be received from a multi-hop swap, /// going in "from root direction" (where depth increases) via the given `rootPath` from `depthFrom` to `depthTo`. function _getMultiSwapFromRootQuote( uint256 visitedPoolsMask, uint256 rootPath, uint256 depthFrom, uint256 depthTo, uint256 amountIn, bool probePaused ) internal view returns (Route memory route) { uint256 nodeIndex = _extractNodeIndex(rootPath, depthFrom); // Traverse down the tree following `rootPath` from `depthFrom` to `depthTo`. for (uint256 depth = depthFrom; depth < depthTo; ) { // Get the child node unchecked { ++depth; } uint256 childIndex = _extractNodeIndex(rootPath, depth); // Swap node -> child (visitedPoolsMask, amountIn) = _getSingleSwapQuote( visitedPoolsMask, _nodes[childIndex].poolIndex, nodeIndex, childIndex, amountIn, probePaused ); nodeIndex = childIndex; } route.visitedPoolsMask = visitedPoolsMask; route.amountOut = amountIn; } /// @dev Calculates the amount of tokens that will be received from a multi-hop swap, /// going in "to root direction" (where depth decreases) via the given `rootPath` from `depthFrom` to `depthTo`. function _getMultiSwapToRootQuote( uint256 visitedPoolsMask, uint256 rootPath, uint256 depthFrom, uint256 depthTo, uint256 amountIn, bool probePaused ) internal view returns (Route memory route) { uint256 nodeIndex = _extractNodeIndex(rootPath, depthFrom); // Traverse up the tree following `rootPath` from `depthFrom` to `depthTo`. for (uint256 depth = depthFrom; depth > depthTo; ) { // Get the parent node unchecked { --depth; // depth > 0 so we can do unchecked math } uint256 parentIndex = _extractNodeIndex(rootPath, depth); // Swap node -> parent (visitedPoolsMask, amountIn) = _getSingleSwapQuote( visitedPoolsMask, _nodes[nodeIndex].poolIndex, nodeIndex, parentIndex, amountIn, probePaused ); nodeIndex = parentIndex; } route.visitedPoolsMask = visitedPoolsMask; route.amountOut = amountIn; } // ════════════════════════════════════════ INTERNAL VIEWS: SINGLE POOL ════════════════════════════════════════════ /// @dev Returns the tokens in the pool at the given address. function _getPoolTokens(address poolModule, address pool) internal view virtual returns (address[] memory tokens); /// @dev Returns the amount of tokens that will be received from a single swap. /// Will check if the pool is paused beforehand, if requested. function _getPoolQuote( address poolModule, address pool, uint256 nodeIndexFrom, uint256 nodeIndexTo, uint256 amountIn, bool probePaused ) internal view virtual returns (uint256 amountOut); /// @dev Calculates the amount of tokens that will be received from a single swap given the set of pools /// we have already used on the path. Returns the updated set of pools and the amount of tokens received. function _getSingleSwapQuote( uint256 visitedPoolsMask, uint256 poolIndex, uint256 nodeIndexFrom, uint256 nodeIndexTo, uint256 amountIn, bool probePaused ) internal view returns (uint256 visitedPoolsMask_, uint256 amountOut) { if (visitedPoolsMask & (1 << poolIndex) != 0) { // If we already used this pool on the path, we can't use it again. // Return the full mask and zero amount to indicate that the swap is not possible. return (type(uint256).max, 0); } // Otherwise, mark the pool as visited visitedPoolsMask_ = visitedPoolsMask | (1 << poolIndex); address pool = _pools[poolIndex]; // Pass the parameter for whether we want to check that the pool is paused or not. amountOut = _getPoolQuote(_poolMap[pool].module, pool, nodeIndexFrom, nodeIndexTo, amountIn, probePaused); } // ══════════════════════════════════════════════════ HELPERS ══════════════════════════════════════════════════════ /// @dev Checks if a pool could be added to the tree at the given node. Requirements: /// - Pool is not already attached to the node: no need to add twice. /// - Pool is not present on the path from the node to root: this would invalidate swaps from added nodes to root, /// as this path would contain this pool twice. function _checkPoolAddition( uint256 nodeIndex, uint256 nodeDepth, uint8 poolIndex ) internal view { // Check that the pool is not already attached to the node if (_attachedPools[nodeIndex] & (1 << poolIndex) != 0) revert TokenTree__PoolAlreadyAttached(); // Here we iterate over all nodes from the root to the node, and check that the pool connecting the current node // to its parent is not the pool we want to add. We skip the root node (depth 0), as it has no parent. uint256 rootPath = _rootPath[nodeIndex]; for (uint256 d = 1; d <= nodeDepth; ) { uint256 nodeIndex_ = _extractNodeIndex(rootPath, d); if (_nodes[nodeIndex_].poolIndex == poolIndex) revert TokenTree__PoolAlreadyOnRootPath(); unchecked { ++d; } } } /// @dev Finds the lowest common ancestor of two different nodes in the tree. /// Node is defined by the path from the root to the node, and the depth of the node. function _depthDiff(uint256 rootPath0, uint256 rootPath1) internal pure returns (uint256 depthDiff) { // Xor the paths to get the first differing byte. // Nodes are different => root paths are different => the result is never zero. rootPath0 ^= rootPath1; // Sanity check for invariant: rootPath0 != rootPath1 assert(rootPath0 != 0); // Traverse from root to node0 and node1 until the paths diverge. while ((rootPath0 & 0xFF) == 0) { // Shift off the lowest byte which are identical in both paths. rootPath0 >>= 8; unchecked { depthDiff++; } } } /// @dev Returns the index of the node at the given depth on the path from the root to the node. function _extractNodeIndex(uint256 rootPath, uint256 depth) internal pure returns (uint256 nodeIndex) { // Nodes on the path are stored from root to node (lowest to highest bytes). return (rootPath >> (8 * depth)) & 0xFF; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _transferOwnership(_msgSender()); } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(owner() == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; function safeTransfer( IERC20 token, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom( IERC20 token, address from, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove( IERC20 token, address spender, uint256 value ) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance( IERC20 token, address spender, uint256 value ) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; error DeadlineExceeded(); error InsufficientOutputAmount(); error MsgValueIncorrect(); error PoolNotFound(); error TokenAddressMismatch(); error TokenNotContract(); error TokenNotETH(); error TokensIdentical();
// 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 // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
{ "remappings": [ "ds-test/=lib/forge-std/lib/ds-test/src/", "forge-std/=lib/forge-std/src/", "solmate/=lib/solmate/src/", "@boringcrypto/=node_modules/@boringcrypto/", "@ensdomains/=node_modules/@ensdomains/", "@openzeppelin/=node_modules/@openzeppelin/", "eth-gas-reporter/=node_modules/eth-gas-reporter/", "forge-std/=lib/forge-std/src/", "hardhat-deploy/=node_modules/hardhat-deploy/", "hardhat/=node_modules/hardhat/", "sol-explore/=node_modules/sol-explore/", "solmate/=lib/solmate/src/", "synthetix/=node_modules/synthetix/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } }, "evmVersion": "london", "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"bridgeToken","type":"address"},{"internalType":"address","name":"owner_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"LinkedPool__DeadlineExceeded","type":"error"},{"inputs":[],"name":"LinkedPool__EmptyPoolAddress","type":"error"},{"inputs":[{"internalType":"uint8","name":"index","type":"uint8"}],"name":"LinkedPool__EqualSwapIndexes","type":"error"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"minDy","type":"uint256"}],"name":"LinkedPool__MinDyNotMet","type":"error"},{"inputs":[],"name":"TokenTree__DifferentTokenLists","type":"error"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"TokenTree__IndexOutOfRange","type":"error"},{"inputs":[],"name":"TokenTree__NodeTokenNotInPool","type":"error"},{"inputs":[],"name":"TokenTree__PoolAlreadyAttached","type":"error"},{"inputs":[],"name":"TokenTree__PoolAlreadyOnRootPath","type":"error"},{"inputs":[{"internalType":"address","name":"pool","type":"address"}],"name":"TokenTree__SwapPoolUsedTwice","type":"error"},{"inputs":[],"name":"TokenTree__TooManyNodes","type":"error"},{"inputs":[],"name":"TokenTree__TooManyPools","type":"error"},{"inputs":[],"name":"TokenTree__UnknownPool","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"parentIndex","type":"uint256"},{"indexed":false,"internalType":"address","name":"pool","type":"address"},{"indexed":false,"internalType":"address","name":"poolModule","type":"address"}],"name":"PoolAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"pool","type":"address"},{"indexed":false,"internalType":"address","name":"oldPoolModule","type":"address"},{"indexed":false,"internalType":"address","name":"newPoolModule","type":"address"}],"name":"PoolModuleUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"childIndex","type":"uint256"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"parentPool","type":"address"}],"name":"TokenNodeAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"buyer","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokensSold","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokensBought","type":"uint256"},{"indexed":false,"internalType":"uint128","name":"soldId","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"boughtId","type":"uint128"}],"name":"TokenSwap","type":"event"},{"inputs":[{"internalType":"uint256","name":"nodeIndex","type":"uint256"},{"internalType":"address","name":"pool","type":"address"},{"internalType":"address","name":"poolModule","type":"address"}],"name":"addPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"}],"name":"areConnectedTokens","outputs":[{"internalType":"bool","name":"areConnected","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"nodeIndexFrom","type":"uint8"},{"internalType":"uint8","name":"nodeIndexTo","type":"uint8"},{"internalType":"uint256","name":"dx","type":"uint256"}],"name":"calculateSwap","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"}],"name":"findBestPath","outputs":[{"internalType":"uint8","name":"nodeIndexFromBest","type":"uint8"},{"internalType":"uint8","name":"nodeIndexToBest","type":"uint8"},{"internalType":"uint256","name":"amountOutBest","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"index","type":"uint8"}],"name":"getAttachedPools","outputs":[{"internalType":"address[]","name":"pools","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"nodeIndex","type":"uint256"}],"name":"getNodeParent","outputs":[{"internalType":"uint256","name":"parentIndex","type":"uint256"},{"internalType":"address","name":"parentPool","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pool","type":"address"}],"name":"getPoolModule","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"index","type":"uint8"}],"name":"getToken","outputs":[{"internalType":"address","name":"token","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getTokenIndexes","outputs":[{"internalType":"uint256[]","name":"nodes","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"nodeIndexFrom","type":"uint8"},{"internalType":"uint8","name":"nodeIndexTo","type":"uint8"},{"internalType":"uint256","name":"dx","type":"uint256"},{"internalType":"uint256","name":"minDy","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swap","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"tokenIndexes","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenNodesAmount","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":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"address","name":"newPoolModule","type":"address"}],"name":"updatePoolModule","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60806040523480156200001157600080fd5b5060405162003292380380620032928339810160408190526200003491620003d0565b60018054808201825560009182527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf60180546001600160a01b03191690558290620000839082908080620000a2565b506200008f336200028c565b6200009a81620002de565b505062000450565b60005460ff811115620000c857604051630be56a6f60e21b815260040160405180910390fd5b6000541580159062000106575060008081548110620000eb57620000eb62000408565b6000918252602090912001546001600160a01b038681169116145b1562000113575062000286565b604080516060810182526001600160a01b0380881680835260ff8089166020808601918252898316868801908152600080546001818101835582805298517f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5639091018054955193518716600160a81b0260ff60a81b1994909716600160a01b026001600160a81b03199096169190981617939093171692909217909355908252600481529281208054928301815581529190912001819055600582620001db8660086200041e565b8254600181810185556000948552602090942060ff92831686901b9390931792019190915581547f3d015788e7bd0b08b47bbeb8eef47706ac9e0c6e79ed68f54e89df593bee087d92849289929088169081106200023d576200023d62000408565b6000918252602090912001546040516200027c9392916001600160a01b0316909283526001600160a01b03918216602084015216604082015260600190565b60405180910390a1505b50505050565b600780546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6007546001600160a01b031633146200033e5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b6001600160a01b038116620003a55760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840162000335565b620003b0816200028c565b50565b80516001600160a01b0381168114620003cb57600080fd5b919050565b60008060408385031215620003e457600080fd5b620003ef83620003b3565b9150620003ff60208401620003b3565b90509250929050565b634e487b7160e01b600052603260045260246000fd5b60ff81811683821602908116908181146200044957634e487b7160e01b600052601160045260246000fd5b5092915050565b612e3280620004606000396000f3fe608060405234801561001057600080fd5b50600436106101005760003560e01c806382b8660011610097578063a95b089f11610066578063a95b089f1461029f578063dd3a1755146102b2578063f2fde38b146102d5578063f624d2c5146102e857600080fd5b806382b86600146102525780638da5cb5b14610265578063916955861461027657806398f80a981461029757600080fd5b80635ff2e6ec116100d35780635ff2e6ec146101d15780636ee4f71b14610215578063715018a61461022a57806380507b571461023257600080fd5b80630f2839ba14610105578063175724f61461012e5780631b6486d61461015e5780633dfea7721461019e575b600080fd5b61011861011336600461283c565b6102fb565b6040516101259190612857565b60405180910390f35b61014161013c3660046128a4565b610417565b604080519283526001600160a01b03909116602083015201610125565b61018c61016c3660046128d2565b600360209081526000928352604080842090915290825290205460ff1681565b60405160ff9091168152602001610125565b6101b16101ac36600461290b565b610507565b6040805160ff948516815293909216602084015290820152606001610125565b6101fd6101df36600461294c565b6001600160a01b039081166000908152600260205260409020541690565b6040516001600160a01b039091168152602001610125565b6102286102233660046128d2565b61063d565b005b610228610675565b61024561024036600461294c565b6106ab565b6040516101259190612969565b6101fd61026036600461283c565b610717565b6007546001600160a01b03166101fd565b6102896102843660046129a1565b610774565b604051908152602001610125565b600054610289565b6102896102ad3660046129ee565b61092a565b6102c56102c03660046128d2565b61098b565b6040519015158152602001610125565b6102286102e336600461294c565b6109d2565b6102286102f6366004612a2a565b610a6d565b60005460609060ff831690811061032d5760405163535e975d60e01b8152600481018290526024015b60405180910390fd5b60015467ffffffffffffffff81111561034857610348612a6c565b604051908082528060200260200182016040528015610371578160200160208202803683370190505b5060ff841660009081526006602052604081205491935090815b845181101561040d578082901c60011660010361040557600181815481106103b5576103b5612a82565b600091825260209091200154855160018501946001600160a01b0390921691879181106103e4576103e4612a82565b60200260200101906001600160a01b031690816001600160a01b0316815250505b60010161038b565b5050825250919050565b600080548190839081106104415760405163535e975d60e01b815260048101829052602401610324565b600080858154811061045557610455612a82565b600091825260209091200154600160a01b900460ff1690508015610500576104a96005868154811061048957610489612a82565b90600052602060002001546001836104a19190612aae565b60ff16610af6565b93506001600086815481106104c0576104c0612a82565b6000918252602090912001548154600160a81b90910460ff169081106104e8576104e8612a82565b6000918252602090912001546001600160a01b031692505b5050915091565b6000806000846001600160a01b0316866001600160a01b0316148061052a575083155b1561053d57506000915081905080610634565b6001600160a01b03808716600090815260046020526040808220549288168252812054905b82811015610630576001600160a01b038916600090815260046020526040812080548390811061059457610594612a82565b9060005260206000200154905060005b8381101561061d576001600160a01b038a1660009081526004602052604081208054839081106105d6576105d6612a82565b9060005260206000200154905060006105f284838d6001610b11565b6020015190508781111561060a578097508399508198505b50508061061690612ac7565b90506105a4565b50508061062990612ac7565b9050610562565b5050505b93509350939050565b6007546001600160a01b031633146106675760405162461bcd60e51b815260040161032490612ae0565b6106718282610e0f565b5050565b6007546001600160a01b0316331461069f5760405162461bcd60e51b815260040161032490612ae0565b6106a96000610f80565b565b6001600160a01b03811660009081526004602090815260409182902080548351818402810184019094528084526060939283018282801561070b57602002820191906000526020600020905b8154815260200190600101908083116106f7575b50505050509050919050565b6000805460ff83169081106107425760405163535e975d60e01b815260048101829052602401610324565b60008360ff168154811061075857610758612a82565b6000918252602090912001546001600160a01b03169392505050565b6000805460ff871690811061079f5760405163535e975d60e01b815260048101829052602401610324565b60005460ff87169081106107c95760405163535e975d60e01b815260048101829052602401610324565b834211156107f35760405163fd1c99dd60e01b815242600482015260248101859052604401610324565b8660ff168860ff160361081e57604051631288800960e01b815260ff89166004820152602401610324565b6000808960ff168154811061083557610835612a82565b6000918252602090912001546001600160a01b031690506108588133308a610fd2565b6108698960ff168960ff168961103d565b6020015193508584101561089a5760405163a8345d2b60e01b81526004810185905260248101879052604401610324565b6108d1338560008b60ff16815481106108b5576108b5612a82565b6000918252602090912001546001600160a01b03169190611313565b604080518881526020810186905260ff8b8116828401528a166060820152905133917fc6c1e0630dbe9130cc068028486c0d118ddcea348550819defd5cb8c257f8a38919081900360800190a250505095945050505050565b6000805460ff8516811115806109435750808460ff1610155b15610952576000915050610984565b8360ff168560ff1603610969576000915050610984565b61097c8560ff168560ff16856000610b11565b602001519150505b9392505050565b6001600160a01b038216600090815260046020526040812054158015906109c957506001600160a01b03821660009081526004602052604090205415155b90505b92915050565b6007546001600160a01b031633146109fc5760405162461bcd60e51b815260040161032490612ae0565b6001600160a01b038116610a615760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610324565b610a6a81610f80565b50565b6007546001600160a01b03163314610a975760405162461bcd60e51b815260040161032490612ae0565b60005483908110610abe5760405163535e975d60e01b815260048101829052602401610324565b6001600160a01b038316610ae55760405163b7e5ea2160e01b815260040160405180910390fd5b610af0848484611348565b50505050565b6000610b03826008612b15565b83901c60ff16905092915050565b60408051808201909152600080825260208201526000604051806060016040528060008881548110610b4557610b45612a82565b600091825260208083206040805160608101825293909101546001600160a01b038116845260ff600160a01b8204811685850152600160a81b9091041690830152908352815492019188908110610b9e57610b9e612a82565b600091825260208083206040805160608101825293909101546001600160a01b038116845260ff600160a01b8204811685850152600160a81b909104169083015290835286151592019190915260058054929350909188908110610c0457610c04612a82565b90600052602060002001549050600060058781548110610c2657610c26612a82565b906000526020600020015490506000610c3f8383611612565b905083602001516020015160ff16811115610c8457610c7960008486600001516020015160ff1687602001516020015160ff168b8b611642565b945050505050610e07565b83516020015160ff16811115610cb957610c7960008386600001516020015160ff1687602001516020015160ff168b8b6116d5565b610cda85600001518486600001516020015160ff16848b8960400151611642565b94506000610ce88483610af6565b90506000610cf68484610af6565b90506000808381548110610d0c57610d0c612a82565b60009182526020822001548154600160a81b90910460ff169250819084908110610d3857610d38612a82565b600091825260209091200154600160a81b900460ff169050808203610d7d57610d7189600001518386868d602001518d60400151611735565b60208b01528952610dd7565b6000610d9388610d8e600189612b2c565b610af6565b9050610daf8a600001518487848e602001518e60400151611735565b60208c01819052818c5260408b0151610dce9291859185918991611735565b60208c01528a52505b610dfc896000015187878b602001516020015160ff168d602001518d604001516116d5565b985050505050505050505b949350505050565b6001600160a01b038083166000908152600260205260409020541680610e485760405163b2ab734360e01b815260040160405180910390fd5b6000610e5482856117b6565b90506000610e6284866117b6565b90508051825114610e8657604051635e33813f60e11b815260040160405180910390fd5b60005b8251811015610f0657818181518110610ea457610ea4612a82565b60200260200101516001600160a01b0316838281518110610ec757610ec7612a82565b60200260200101516001600160a01b031614610ef657604051635e33813f60e11b815260040160405180910390fd5b610eff81612ac7565b9050610e89565b506001600160a01b0385811660008181526002602090815260409182902080546001600160a01b0319168986169081179091558251938452938716908301528101919091527f86972319a3e144542b16dfbf38414db2c872ea5bfe13b6e97021cc47db5ceac7906060015b60405180910390a15050505050565b600780546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6040516001600160a01b0380851660248301528316604482015260648101829052610af09085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261199c565b6040805180820190915260008082526020820152600060405180606001604052806000878154811061107157611071612a82565b600091825260208083206040805160608101825293909101546001600160a01b038116845260ff600160a01b8204811685850152600160a81b90910416908301529083528154920191879081106110ca576110ca612a82565b600091825260208083206040805160608101825293909101546001600160a01b038116845260ff600160a01b8204811685850152600160a81b9091041690830152908352919091018190526005805492935090918790811061112e5761112e612a82565b9060005260206000200154905060006005868154811061115057611150612a82565b9060005260206000200154905060006111698383611612565b905083602001516020015160ff168111156111ad576111a260008486600001516020015160ff1687602001516020015160ff168a611a6e565b945050505050610984565b83516020015160ff168111156111e1576111a260008386600001516020015160ff1687602001516020015160ff168a611aff565b6111fa60008486600001516020015160ff16848a611a6e565b945060006112088483610af6565b905060006112168484610af6565b9050600080838154811061122c5761122c612a82565b60009182526020822001548154600160a81b90910460ff16925081908490811061125857611258612a82565b600091825260209091200154600160a81b900460ff1690508082036112985761128c89600001518386868d60200151611b5f565b60208b015289526112e3565b60006112a988610d8e600189612b2c565b90506112c08a600001518487848e60200151611b5f565b60208c01819052818c526112da9190849084908890611b5f565b60208c01528a52505b611303896000015187878b602001516020015160ff168d60200151611aff565b9c9b505050505050505050505050565b6040516001600160a01b03831660248201526044810182905261134390849063a9059cbb60e01b90606401611006565b505050565b600080848154811061135c5761135c612a82565b60009182526020918290206040805160608101825292909101546001600160a01b03808216845260ff600160a01b8304811695850195909552600160a81b90910490931690820152915082166113b0573091505b6001600160a01b038316600090815260026020526040812054600160a01b900460ff168082036114da5760015460ff10156113fe576040516369236b8f60e11b815260040160405180910390fd5b50506001805480820182557fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6810180546001600160a01b038781166001600160a01b0319909216821790925560408051808201825287841680825260ff8087166020808501918252600087815260028252869020945185549251909316600160a01b026001600160a81b031990921692909716919091171790915581518a8152938401929092528201527ff526af69faf759a24b780dee9d979f542b6a5e8bfa39c7b04fcce83cb9982b8a9060600160405180910390a16114ec565b6114ec86846020015160ff1683611bfa565b60008681526006602052604081208054600160ff85161b17905561151085876117b6565b905060008151905060008086602001516001019050600060058b8154811061153a5761153a612a82565b9060005260206000200154905060005b848110156115e657600086828151811061156657611566612a82565b6020026020010151905088156115a9576001600160a01b038c81166000908152600360209081526040808320938516835292905220805460ff191660ff84161790555b89600001516001600160a01b0316816001600160a01b0316036115d05760019450506115de565b6115dc81858a86611cc5565b505b60010161154a565b50505080611607576040516350518a2560e01b815260040160405180910390fd5b505050505050505050565b90811890600082810361162757611627612b3f565b5b8260ff166000036109cc5760089290921c91600101611628565b604080518082019091526000808252602082015260006116628787610af6565b9050855b858111156116c25760001901600061167e8983610af6565b90506116b68a6000858154811061169757611697612a82565b600091825260209091200154600160a81b900460ff1685848a8a611735565b909a5095509150611666565b5050958652506020850152509192915050565b604080518082019091526000808252602082015260006116f58787610af6565b9050855b858110156116c25760010160006117108983610af6565b90506117298a6000838154811061169757611697612a82565b909a50955091506116f9565b6000806001871b8816156117505750600019905060006117ab565b866001901b8817915060006001888154811061176e5761176e612a82565b60009182526020808320909101546001600160a01b0390811680845260029092526040909220549092506117a791168289898989611e92565b9150505b965096945050505050565b6060306001600160a01b0384160361192e5760005b60405162415c3360e91b815260ff821660048201526001600160a01b038416906382b8660090602401602060405180830381865afa92505050801561182d575060408051601f3d908101601f1916820190925261182a91810190612b60565b60015b1561183b57506001016117cb565b8067ffffffffffffffff81111561185457611854612a6c565b60405190808252806020026020018201604052801561187d578160200160208202803683370190505b50915060005b818110156119275760405162415c3360e91b815260ff821660048201526001600160a01b038516906382b8660090602401602060405180830381865afa1580156118d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118f59190612b60565b83828151811061190757611907612a82565b6001600160a01b0390921660209283029190910190910152600101611883565b50506109cc565b60405163ca4f280360e01b81526001600160a01b03838116600483015284169063ca4f280390602401600060405180830381865afa158015611974573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109c99190810190612b7d565b60006119f1826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166121b19092919063ffffffff16565b8051909150156113435780806020019051810190611a0f9190612c42565b6113435760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610324565b60408051808201909152600080825260208201526000611a8e8686610af6565b9050845b84811115611aed57600019016000611aaa8883610af6565b9050611ae18960008581548110611ac357611ac3612a82565b600091825260209091200154600160a81b900460ff16858489611b5f565b90995094509150611a92565b50509485526020850152509192915050565b60408051808201909152600080825260208201526000611b1f8686610af6565b9050845b84811015611aed576001016000611b3a8883610af6565b9050611b538960008381548110611ac357611ac3612a82565b90995094509150611b23565b600080600060018781548110611b7757611b77612a82565b6000918252602090912001546001600160a01b031690506001871b881615611bbd5760405163a87c309760e01b81526001600160a01b0382166004820152602401610324565b6001600160a01b038082166000908152600260205260409020546001891b8a179450611bed9116828888886121c0565b9150509550959350505050565b600083815260066020526040902054600160ff83161b1615611c2f57604051630180f60d60e61b815260040160405180910390fd5b600060058481548110611c4457611c44612a82565b600091825260209091200154905060015b838111611cbe576000611c688383610af6565b90508360ff1660008281548110611c8157611c81612a82565b600091825260209091200154600160a81b900460ff1603611cb55760405163aa53d00f60e01b815260040160405180910390fd5b50600101611c55565b5050505050565b60005460ff811115611cea57604051630be56a6f60e21b815260040160405180910390fd5b60005415801590611d24575060008081548110611d0957611d09612a82565b6000918252602090912001546001600160a01b038681169116145b15611d2f5750610af0565b604080516060810182526001600160a01b0380881680835260ff8089166020808601918252898316868801908152600080546001818101835582805298517f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5639091018054955193518716600160a81b0260ff60a81b1994909716600160a01b026001600160a81b03199096169190981617939093171692909217909355908252600481529281208054928301815581529190912001819055600582611df5866008612c64565b8254600181810185556000948552602090942060ff92831686901b9390931792019190915581547f3d015788e7bd0b08b47bbeb8eef47706ac9e0c6e79ed68f54e89df593bee087d9284928992908816908110611e5457611e54612a82565b600091825260209091200154604051610f719392916001600160a01b0316909283526001600160a01b03918216602084015216604082015260600190565b6000306001600160a01b0388160361208a578115611f615760408051600481526024810182526020810180516001600160e01b0316635c975abb60e01b179052905160009182916001600160a01b038a1691611eed91612cab565b600060405180830381855afa9150503d8060008114611f28576040519150601f19603f3d011682016040523d82523d6000602084013e611f2d565b606091505b5091509150818015611f4e575080806020019051810190611f4e9190612c42565b15611f5e576000925050506121a7565b50505b6001600160a01b0386166000818152600360205260408120815463a95b089f929081908a908110611f9457611f94612a82565b60009182526020808320909101546001600160a01b039081168452838201949094526040928301822054938c16825260039052908120815460ff9093169290919081908a908110611fe757611fe7612a82565b6000918252602080832091909101546001600160a01b03168352820192909252604090810190912054905160e084901b6001600160e01b031916815260ff92831660048201529116602482015260448101869052606401602060405180830381865afa925050508015612077575060408051601f3d908101601f1916820190925261207491810190612cc7565b60015b612083575060006121a7565b90506121a7565b600080868154811061209e5761209e612a82565b600091825260208220015481546001600160a01b0390911692508190879081106120ca576120ca612a82565b60009182526020808320909101546040805180820182526001600160a01b038d81168652600385528286208882168088528187528488205460ff90811685528488019190915284518086018652958316808952918752968490205490961684529383018590529051637de4c55160e01b8152939450918c1692637de4c5519261215b928d928b908b90600401612ce0565b602060405180830381865afa925050508015612194575060408051601f3d908101601f1916820190925261219191810190612cc7565b60015b6121a157600092506121a4565b92505b50505b9695505050505050565b6060610e0784846000856123d1565b600080600085815481106121d6576121d6612a82565b600091825260208220015481546001600160a01b03909116925081908690811061220257612202612a82565b6000918252602090912001546001600160a01b03908116915030908916036122ee576122386001600160a01b0383168886612502565b6001600160a01b03878116600081815260036020908152604080832087861684529091528082205493851682528082205490516348b4aac360e11b815260ff94851660048201529316602484015260448301879052606483015260001960848301529063916955869060a4016020604051808303816000875af11580156122c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122e79190612cc7565b92506123c6565b6040805180820182526001600160a01b03808a166000908152600360209081528482208784168084528183528684205460ff9081168752838701919091528651808801885294881680855291835286842054168452908301529251631a0e91a960e31b92612362928c928a90602401612d47565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152905060006123ab6001600160a01b038b16836125e0565b9050808060200190518101906123c19190612cc7565b945050505b505095945050505050565b6060824710156124325760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610324565b6001600160a01b0385163b6124895760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610324565b600080866001600160a01b031685876040516124a59190612cab565b60006040518083038185875af1925050503d80600081146124e2576040519150601f19603f3d011682016040523d82523d6000602084013e6124e7565b606091505b50915091506124f7828286612605565b979650505050505050565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b0384160161252c57505050565b604051636eb1769f60e11b81523060048201526001600160a01b0383811660248301526000919085169063dd62ed3e90604401602060405180830381865afa15801561257c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125a09190612cc7565b90508181106125af5750505050565b80156125ca576125ca6001600160a01b03851684600061263e565b610af06001600160a01b0385168460001961263e565b60606109c98383604051806060016040528060278152602001612dd660279139612753565b60608315612614575081610984565b8251156126245782518084602001fd5b8160405162461bcd60e51b81526004016103249190612da2565b8015806126b85750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015612692573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126b69190612cc7565b155b6127235760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610324565b6040516001600160a01b03831660248201526044810182905261134390849063095ea7b360e01b90606401611006565b60606001600160a01b0384163b6127bb5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401610324565b600080856001600160a01b0316856040516127d69190612cab565b600060405180830381855af49150503d8060008114612811576040519150601f19603f3d011682016040523d82523d6000602084013e612816565b606091505b50915091506121a7828286612605565b803560ff8116811461283757600080fd5b919050565b60006020828403121561284e57600080fd5b6109c982612826565b6020808252825182820181905260009190848201906040850190845b818110156128985783516001600160a01b031683529284019291840191600101612873565b50909695505050505050565b6000602082840312156128b657600080fd5b5035919050565b6001600160a01b0381168114610a6a57600080fd5b600080604083850312156128e557600080fd5b82356128f0816128bd565b91506020830135612900816128bd565b809150509250929050565b60008060006060848603121561292057600080fd5b833561292b816128bd565b9250602084013561293b816128bd565b929592945050506040919091013590565b60006020828403121561295e57600080fd5b8135610984816128bd565b6020808252825182820181905260009190848201906040850190845b8181101561289857835183529284019291840191600101612985565b600080600080600060a086880312156129b957600080fd5b6129c286612826565b94506129d060208701612826565b94979496505050506040830135926060810135926080909101359150565b600080600060608486031215612a0357600080fd5b612a0c84612826565b9250612a1a60208501612826565b9150604084013590509250925092565b600080600060608486031215612a3f57600080fd5b833592506020840135612a51816128bd565b91506040840135612a61816128bd565b809150509250925092565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60ff82811682821603908111156109cc576109cc612a98565b600060018201612ad957612ad9612a98565b5060010190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b80820281158282048414176109cc576109cc612a98565b818103818111156109cc576109cc612a98565b634e487b7160e01b600052600160045260246000fd5b8051612837816128bd565b600060208284031215612b7257600080fd5b8151610984816128bd565b60006020808385031215612b9057600080fd5b825167ffffffffffffffff80821115612ba857600080fd5b818501915085601f830112612bbc57600080fd5b815181811115612bce57612bce612a6c565b8060051b604051601f19603f83011681018181108582111715612bf357612bf3612a6c565b604052918252848201925083810185019188831115612c1157600080fd5b938501935b82851015612c3657612c2785612b55565b84529385019392850192612c16565b98975050505050505050565b600060208284031215612c5457600080fd5b8151801515811461098457600080fd5b60ff8181168382160290811690818114612c8057612c80612a98565b5092915050565b60005b83811015612ca2578181015183820152602001612c8a565b50506000910152565b60008251612cbd818460208701612c87565b9190910192915050565b600060208284031215612cd957600080fd5b5051919050565b6001600160a01b038616815260e08101612d136020830187805160ff1682526020908101516001600160a01b0316910152565b845160ff1660608301526020909401516001600160a01b0316608082015260a0810192909252151560c09091015292915050565b6001600160a01b038516815260c08101612d7a6020830186805160ff1682526020908101516001600160a01b0316910152565b835160ff1660608301526020909301516001600160a01b0316608082015260a0015292915050565b6020815260008251806020840152612dc1816040850160208701612c87565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220a20dd8a538f2931dec0e2eef157073d30e5f0ec670efe8c0a9eae6615811448564736f6c63430008110033000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000fea3e5840334fc758a3decf14546bfdfbef5cd3
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101005760003560e01c806382b8660011610097578063a95b089f11610066578063a95b089f1461029f578063dd3a1755146102b2578063f2fde38b146102d5578063f624d2c5146102e857600080fd5b806382b86600146102525780638da5cb5b14610265578063916955861461027657806398f80a981461029757600080fd5b80635ff2e6ec116100d35780635ff2e6ec146101d15780636ee4f71b14610215578063715018a61461022a57806380507b571461023257600080fd5b80630f2839ba14610105578063175724f61461012e5780631b6486d61461015e5780633dfea7721461019e575b600080fd5b61011861011336600461283c565b6102fb565b6040516101259190612857565b60405180910390f35b61014161013c3660046128a4565b610417565b604080519283526001600160a01b03909116602083015201610125565b61018c61016c3660046128d2565b600360209081526000928352604080842090915290825290205460ff1681565b60405160ff9091168152602001610125565b6101b16101ac36600461290b565b610507565b6040805160ff948516815293909216602084015290820152606001610125565b6101fd6101df36600461294c565b6001600160a01b039081166000908152600260205260409020541690565b6040516001600160a01b039091168152602001610125565b6102286102233660046128d2565b61063d565b005b610228610675565b61024561024036600461294c565b6106ab565b6040516101259190612969565b6101fd61026036600461283c565b610717565b6007546001600160a01b03166101fd565b6102896102843660046129a1565b610774565b604051908152602001610125565b600054610289565b6102896102ad3660046129ee565b61092a565b6102c56102c03660046128d2565b61098b565b6040519015158152602001610125565b6102286102e336600461294c565b6109d2565b6102286102f6366004612a2a565b610a6d565b60005460609060ff831690811061032d5760405163535e975d60e01b8152600481018290526024015b60405180910390fd5b60015467ffffffffffffffff81111561034857610348612a6c565b604051908082528060200260200182016040528015610371578160200160208202803683370190505b5060ff841660009081526006602052604081205491935090815b845181101561040d578082901c60011660010361040557600181815481106103b5576103b5612a82565b600091825260209091200154855160018501946001600160a01b0390921691879181106103e4576103e4612a82565b60200260200101906001600160a01b031690816001600160a01b0316815250505b60010161038b565b5050825250919050565b600080548190839081106104415760405163535e975d60e01b815260048101829052602401610324565b600080858154811061045557610455612a82565b600091825260209091200154600160a01b900460ff1690508015610500576104a96005868154811061048957610489612a82565b90600052602060002001546001836104a19190612aae565b60ff16610af6565b93506001600086815481106104c0576104c0612a82565b6000918252602090912001548154600160a81b90910460ff169081106104e8576104e8612a82565b6000918252602090912001546001600160a01b031692505b5050915091565b6000806000846001600160a01b0316866001600160a01b0316148061052a575083155b1561053d57506000915081905080610634565b6001600160a01b03808716600090815260046020526040808220549288168252812054905b82811015610630576001600160a01b038916600090815260046020526040812080548390811061059457610594612a82565b9060005260206000200154905060005b8381101561061d576001600160a01b038a1660009081526004602052604081208054839081106105d6576105d6612a82565b9060005260206000200154905060006105f284838d6001610b11565b6020015190508781111561060a578097508399508198505b50508061061690612ac7565b90506105a4565b50508061062990612ac7565b9050610562565b5050505b93509350939050565b6007546001600160a01b031633146106675760405162461bcd60e51b815260040161032490612ae0565b6106718282610e0f565b5050565b6007546001600160a01b0316331461069f5760405162461bcd60e51b815260040161032490612ae0565b6106a96000610f80565b565b6001600160a01b03811660009081526004602090815260409182902080548351818402810184019094528084526060939283018282801561070b57602002820191906000526020600020905b8154815260200190600101908083116106f7575b50505050509050919050565b6000805460ff83169081106107425760405163535e975d60e01b815260048101829052602401610324565b60008360ff168154811061075857610758612a82565b6000918252602090912001546001600160a01b03169392505050565b6000805460ff871690811061079f5760405163535e975d60e01b815260048101829052602401610324565b60005460ff87169081106107c95760405163535e975d60e01b815260048101829052602401610324565b834211156107f35760405163fd1c99dd60e01b815242600482015260248101859052604401610324565b8660ff168860ff160361081e57604051631288800960e01b815260ff89166004820152602401610324565b6000808960ff168154811061083557610835612a82565b6000918252602090912001546001600160a01b031690506108588133308a610fd2565b6108698960ff168960ff168961103d565b6020015193508584101561089a5760405163a8345d2b60e01b81526004810185905260248101879052604401610324565b6108d1338560008b60ff16815481106108b5576108b5612a82565b6000918252602090912001546001600160a01b03169190611313565b604080518881526020810186905260ff8b8116828401528a166060820152905133917fc6c1e0630dbe9130cc068028486c0d118ddcea348550819defd5cb8c257f8a38919081900360800190a250505095945050505050565b6000805460ff8516811115806109435750808460ff1610155b15610952576000915050610984565b8360ff168560ff1603610969576000915050610984565b61097c8560ff168560ff16856000610b11565b602001519150505b9392505050565b6001600160a01b038216600090815260046020526040812054158015906109c957506001600160a01b03821660009081526004602052604090205415155b90505b92915050565b6007546001600160a01b031633146109fc5760405162461bcd60e51b815260040161032490612ae0565b6001600160a01b038116610a615760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610324565b610a6a81610f80565b50565b6007546001600160a01b03163314610a975760405162461bcd60e51b815260040161032490612ae0565b60005483908110610abe5760405163535e975d60e01b815260048101829052602401610324565b6001600160a01b038316610ae55760405163b7e5ea2160e01b815260040160405180910390fd5b610af0848484611348565b50505050565b6000610b03826008612b15565b83901c60ff16905092915050565b60408051808201909152600080825260208201526000604051806060016040528060008881548110610b4557610b45612a82565b600091825260208083206040805160608101825293909101546001600160a01b038116845260ff600160a01b8204811685850152600160a81b9091041690830152908352815492019188908110610b9e57610b9e612a82565b600091825260208083206040805160608101825293909101546001600160a01b038116845260ff600160a01b8204811685850152600160a81b909104169083015290835286151592019190915260058054929350909188908110610c0457610c04612a82565b90600052602060002001549050600060058781548110610c2657610c26612a82565b906000526020600020015490506000610c3f8383611612565b905083602001516020015160ff16811115610c8457610c7960008486600001516020015160ff1687602001516020015160ff168b8b611642565b945050505050610e07565b83516020015160ff16811115610cb957610c7960008386600001516020015160ff1687602001516020015160ff168b8b6116d5565b610cda85600001518486600001516020015160ff16848b8960400151611642565b94506000610ce88483610af6565b90506000610cf68484610af6565b90506000808381548110610d0c57610d0c612a82565b60009182526020822001548154600160a81b90910460ff169250819084908110610d3857610d38612a82565b600091825260209091200154600160a81b900460ff169050808203610d7d57610d7189600001518386868d602001518d60400151611735565b60208b01528952610dd7565b6000610d9388610d8e600189612b2c565b610af6565b9050610daf8a600001518487848e602001518e60400151611735565b60208c01819052818c5260408b0151610dce9291859185918991611735565b60208c01528a52505b610dfc896000015187878b602001516020015160ff168d602001518d604001516116d5565b985050505050505050505b949350505050565b6001600160a01b038083166000908152600260205260409020541680610e485760405163b2ab734360e01b815260040160405180910390fd5b6000610e5482856117b6565b90506000610e6284866117b6565b90508051825114610e8657604051635e33813f60e11b815260040160405180910390fd5b60005b8251811015610f0657818181518110610ea457610ea4612a82565b60200260200101516001600160a01b0316838281518110610ec757610ec7612a82565b60200260200101516001600160a01b031614610ef657604051635e33813f60e11b815260040160405180910390fd5b610eff81612ac7565b9050610e89565b506001600160a01b0385811660008181526002602090815260409182902080546001600160a01b0319168986169081179091558251938452938716908301528101919091527f86972319a3e144542b16dfbf38414db2c872ea5bfe13b6e97021cc47db5ceac7906060015b60405180910390a15050505050565b600780546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6040516001600160a01b0380851660248301528316604482015260648101829052610af09085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261199c565b6040805180820190915260008082526020820152600060405180606001604052806000878154811061107157611071612a82565b600091825260208083206040805160608101825293909101546001600160a01b038116845260ff600160a01b8204811685850152600160a81b90910416908301529083528154920191879081106110ca576110ca612a82565b600091825260208083206040805160608101825293909101546001600160a01b038116845260ff600160a01b8204811685850152600160a81b9091041690830152908352919091018190526005805492935090918790811061112e5761112e612a82565b9060005260206000200154905060006005868154811061115057611150612a82565b9060005260206000200154905060006111698383611612565b905083602001516020015160ff168111156111ad576111a260008486600001516020015160ff1687602001516020015160ff168a611a6e565b945050505050610984565b83516020015160ff168111156111e1576111a260008386600001516020015160ff1687602001516020015160ff168a611aff565b6111fa60008486600001516020015160ff16848a611a6e565b945060006112088483610af6565b905060006112168484610af6565b9050600080838154811061122c5761122c612a82565b60009182526020822001548154600160a81b90910460ff16925081908490811061125857611258612a82565b600091825260209091200154600160a81b900460ff1690508082036112985761128c89600001518386868d60200151611b5f565b60208b015289526112e3565b60006112a988610d8e600189612b2c565b90506112c08a600001518487848e60200151611b5f565b60208c01819052818c526112da9190849084908890611b5f565b60208c01528a52505b611303896000015187878b602001516020015160ff168d60200151611aff565b9c9b505050505050505050505050565b6040516001600160a01b03831660248201526044810182905261134390849063a9059cbb60e01b90606401611006565b505050565b600080848154811061135c5761135c612a82565b60009182526020918290206040805160608101825292909101546001600160a01b03808216845260ff600160a01b8304811695850195909552600160a81b90910490931690820152915082166113b0573091505b6001600160a01b038316600090815260026020526040812054600160a01b900460ff168082036114da5760015460ff10156113fe576040516369236b8f60e11b815260040160405180910390fd5b50506001805480820182557fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6810180546001600160a01b038781166001600160a01b0319909216821790925560408051808201825287841680825260ff8087166020808501918252600087815260028252869020945185549251909316600160a01b026001600160a81b031990921692909716919091171790915581518a8152938401929092528201527ff526af69faf759a24b780dee9d979f542b6a5e8bfa39c7b04fcce83cb9982b8a9060600160405180910390a16114ec565b6114ec86846020015160ff1683611bfa565b60008681526006602052604081208054600160ff85161b17905561151085876117b6565b905060008151905060008086602001516001019050600060058b8154811061153a5761153a612a82565b9060005260206000200154905060005b848110156115e657600086828151811061156657611566612a82565b6020026020010151905088156115a9576001600160a01b038c81166000908152600360209081526040808320938516835292905220805460ff191660ff84161790555b89600001516001600160a01b0316816001600160a01b0316036115d05760019450506115de565b6115dc81858a86611cc5565b505b60010161154a565b50505080611607576040516350518a2560e01b815260040160405180910390fd5b505050505050505050565b90811890600082810361162757611627612b3f565b5b8260ff166000036109cc5760089290921c91600101611628565b604080518082019091526000808252602082015260006116628787610af6565b9050855b858111156116c25760001901600061167e8983610af6565b90506116b68a6000858154811061169757611697612a82565b600091825260209091200154600160a81b900460ff1685848a8a611735565b909a5095509150611666565b5050958652506020850152509192915050565b604080518082019091526000808252602082015260006116f58787610af6565b9050855b858110156116c25760010160006117108983610af6565b90506117298a6000838154811061169757611697612a82565b909a50955091506116f9565b6000806001871b8816156117505750600019905060006117ab565b866001901b8817915060006001888154811061176e5761176e612a82565b60009182526020808320909101546001600160a01b0390811680845260029092526040909220549092506117a791168289898989611e92565b9150505b965096945050505050565b6060306001600160a01b0384160361192e5760005b60405162415c3360e91b815260ff821660048201526001600160a01b038416906382b8660090602401602060405180830381865afa92505050801561182d575060408051601f3d908101601f1916820190925261182a91810190612b60565b60015b1561183b57506001016117cb565b8067ffffffffffffffff81111561185457611854612a6c565b60405190808252806020026020018201604052801561187d578160200160208202803683370190505b50915060005b818110156119275760405162415c3360e91b815260ff821660048201526001600160a01b038516906382b8660090602401602060405180830381865afa1580156118d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118f59190612b60565b83828151811061190757611907612a82565b6001600160a01b0390921660209283029190910190910152600101611883565b50506109cc565b60405163ca4f280360e01b81526001600160a01b03838116600483015284169063ca4f280390602401600060405180830381865afa158015611974573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109c99190810190612b7d565b60006119f1826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166121b19092919063ffffffff16565b8051909150156113435780806020019051810190611a0f9190612c42565b6113435760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610324565b60408051808201909152600080825260208201526000611a8e8686610af6565b9050845b84811115611aed57600019016000611aaa8883610af6565b9050611ae18960008581548110611ac357611ac3612a82565b600091825260209091200154600160a81b900460ff16858489611b5f565b90995094509150611a92565b50509485526020850152509192915050565b60408051808201909152600080825260208201526000611b1f8686610af6565b9050845b84811015611aed576001016000611b3a8883610af6565b9050611b538960008381548110611ac357611ac3612a82565b90995094509150611b23565b600080600060018781548110611b7757611b77612a82565b6000918252602090912001546001600160a01b031690506001871b881615611bbd5760405163a87c309760e01b81526001600160a01b0382166004820152602401610324565b6001600160a01b038082166000908152600260205260409020546001891b8a179450611bed9116828888886121c0565b9150509550959350505050565b600083815260066020526040902054600160ff83161b1615611c2f57604051630180f60d60e61b815260040160405180910390fd5b600060058481548110611c4457611c44612a82565b600091825260209091200154905060015b838111611cbe576000611c688383610af6565b90508360ff1660008281548110611c8157611c81612a82565b600091825260209091200154600160a81b900460ff1603611cb55760405163aa53d00f60e01b815260040160405180910390fd5b50600101611c55565b5050505050565b60005460ff811115611cea57604051630be56a6f60e21b815260040160405180910390fd5b60005415801590611d24575060008081548110611d0957611d09612a82565b6000918252602090912001546001600160a01b038681169116145b15611d2f5750610af0565b604080516060810182526001600160a01b0380881680835260ff8089166020808601918252898316868801908152600080546001818101835582805298517f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5639091018054955193518716600160a81b0260ff60a81b1994909716600160a01b026001600160a81b03199096169190981617939093171692909217909355908252600481529281208054928301815581529190912001819055600582611df5866008612c64565b8254600181810185556000948552602090942060ff92831686901b9390931792019190915581547f3d015788e7bd0b08b47bbeb8eef47706ac9e0c6e79ed68f54e89df593bee087d9284928992908816908110611e5457611e54612a82565b600091825260209091200154604051610f719392916001600160a01b0316909283526001600160a01b03918216602084015216604082015260600190565b6000306001600160a01b0388160361208a578115611f615760408051600481526024810182526020810180516001600160e01b0316635c975abb60e01b179052905160009182916001600160a01b038a1691611eed91612cab565b600060405180830381855afa9150503d8060008114611f28576040519150601f19603f3d011682016040523d82523d6000602084013e611f2d565b606091505b5091509150818015611f4e575080806020019051810190611f4e9190612c42565b15611f5e576000925050506121a7565b50505b6001600160a01b0386166000818152600360205260408120815463a95b089f929081908a908110611f9457611f94612a82565b60009182526020808320909101546001600160a01b039081168452838201949094526040928301822054938c16825260039052908120815460ff9093169290919081908a908110611fe757611fe7612a82565b6000918252602080832091909101546001600160a01b03168352820192909252604090810190912054905160e084901b6001600160e01b031916815260ff92831660048201529116602482015260448101869052606401602060405180830381865afa925050508015612077575060408051601f3d908101601f1916820190925261207491810190612cc7565b60015b612083575060006121a7565b90506121a7565b600080868154811061209e5761209e612a82565b600091825260208220015481546001600160a01b0390911692508190879081106120ca576120ca612a82565b60009182526020808320909101546040805180820182526001600160a01b038d81168652600385528286208882168088528187528488205460ff90811685528488019190915284518086018652958316808952918752968490205490961684529383018590529051637de4c55160e01b8152939450918c1692637de4c5519261215b928d928b908b90600401612ce0565b602060405180830381865afa925050508015612194575060408051601f3d908101601f1916820190925261219191810190612cc7565b60015b6121a157600092506121a4565b92505b50505b9695505050505050565b6060610e0784846000856123d1565b600080600085815481106121d6576121d6612a82565b600091825260208220015481546001600160a01b03909116925081908690811061220257612202612a82565b6000918252602090912001546001600160a01b03908116915030908916036122ee576122386001600160a01b0383168886612502565b6001600160a01b03878116600081815260036020908152604080832087861684529091528082205493851682528082205490516348b4aac360e11b815260ff94851660048201529316602484015260448301879052606483015260001960848301529063916955869060a4016020604051808303816000875af11580156122c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122e79190612cc7565b92506123c6565b6040805180820182526001600160a01b03808a166000908152600360209081528482208784168084528183528684205460ff9081168752838701919091528651808801885294881680855291835286842054168452908301529251631a0e91a960e31b92612362928c928a90602401612d47565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152905060006123ab6001600160a01b038b16836125e0565b9050808060200190518101906123c19190612cc7565b945050505b505095945050505050565b6060824710156124325760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610324565b6001600160a01b0385163b6124895760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610324565b600080866001600160a01b031685876040516124a59190612cab565b60006040518083038185875af1925050503d80600081146124e2576040519150601f19603f3d011682016040523d82523d6000602084013e6124e7565b606091505b50915091506124f7828286612605565b979650505050505050565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b0384160161252c57505050565b604051636eb1769f60e11b81523060048201526001600160a01b0383811660248301526000919085169063dd62ed3e90604401602060405180830381865afa15801561257c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125a09190612cc7565b90508181106125af5750505050565b80156125ca576125ca6001600160a01b03851684600061263e565b610af06001600160a01b0385168460001961263e565b60606109c98383604051806060016040528060278152602001612dd660279139612753565b60608315612614575081610984565b8251156126245782518084602001fd5b8160405162461bcd60e51b81526004016103249190612da2565b8015806126b85750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015612692573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126b69190612cc7565b155b6127235760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610324565b6040516001600160a01b03831660248201526044810182905261134390849063095ea7b360e01b90606401611006565b60606001600160a01b0384163b6127bb5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401610324565b600080856001600160a01b0316856040516127d69190612cab565b600060405180830381855af49150503d8060008114612811576040519150601f19603f3d011682016040523d82523d6000602084013e612816565b606091505b50915091506121a7828286612605565b803560ff8116811461283757600080fd5b919050565b60006020828403121561284e57600080fd5b6109c982612826565b6020808252825182820181905260009190848201906040850190845b818110156128985783516001600160a01b031683529284019291840191600101612873565b50909695505050505050565b6000602082840312156128b657600080fd5b5035919050565b6001600160a01b0381168114610a6a57600080fd5b600080604083850312156128e557600080fd5b82356128f0816128bd565b91506020830135612900816128bd565b809150509250929050565b60008060006060848603121561292057600080fd5b833561292b816128bd565b9250602084013561293b816128bd565b929592945050506040919091013590565b60006020828403121561295e57600080fd5b8135610984816128bd565b6020808252825182820181905260009190848201906040850190845b8181101561289857835183529284019291840191600101612985565b600080600080600060a086880312156129b957600080fd5b6129c286612826565b94506129d060208701612826565b94979496505050506040830135926060810135926080909101359150565b600080600060608486031215612a0357600080fd5b612a0c84612826565b9250612a1a60208501612826565b9150604084013590509250925092565b600080600060608486031215612a3f57600080fd5b833592506020840135612a51816128bd565b91506040840135612a61816128bd565b809150509250925092565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60ff82811682821603908111156109cc576109cc612a98565b600060018201612ad957612ad9612a98565b5060010190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b80820281158282048414176109cc576109cc612a98565b818103818111156109cc576109cc612a98565b634e487b7160e01b600052600160045260246000fd5b8051612837816128bd565b600060208284031215612b7257600080fd5b8151610984816128bd565b60006020808385031215612b9057600080fd5b825167ffffffffffffffff80821115612ba857600080fd5b818501915085601f830112612bbc57600080fd5b815181811115612bce57612bce612a6c565b8060051b604051601f19603f83011681018181108582111715612bf357612bf3612a6c565b604052918252848201925083810185019188831115612c1157600080fd5b938501935b82851015612c3657612c2785612b55565b84529385019392850192612c16565b98975050505050505050565b600060208284031215612c5457600080fd5b8151801515811461098457600080fd5b60ff8181168382160290811690818114612c8057612c80612a98565b5092915050565b60005b83811015612ca2578181015183820152602001612c8a565b50506000910152565b60008251612cbd818460208701612c87565b9190910192915050565b600060208284031215612cd957600080fd5b5051919050565b6001600160a01b038616815260e08101612d136020830187805160ff1682526020908101516001600160a01b0316910152565b845160ff1660608301526020909401516001600160a01b0316608082015260a0810192909252151560c09091015292915050565b6001600160a01b038516815260c08101612d7a6020830186805160ff1682526020908101516001600160a01b0316910152565b835160ff1660608301526020909301516001600160a01b0316608082015260a0015292915050565b6020815260008251806020840152612dc1816040850160208701612c87565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220a20dd8a538f2931dec0e2eef157073d30e5f0ec670efe8c0a9eae6615811448564736f6c63430008110033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000fea3e5840334fc758a3decf14546bfdfbef5cd3
-----Decoded View---------------
Arg [0] : bridgeToken (address): 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
Arg [1] : owner_ (address): 0x0fea3e5840334Fc758A3DECf14546bFdfBef5cd3
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
Arg [1] : 0000000000000000000000000fea3e5840334fc758a3decf14546bfdfbef5cd3
Deployed Bytecode Sourcemap
1858:16530:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9998:746;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;11102:460;;;;;;:::i;:::-;;:::i;:::-;;;;1384:25:14;;;-1:-1:-1;;;;;1445:32:14;;;1440:2;1425:18;;1418:60;1357:18;11102:460:0;1210:274:14;4641:65:8;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2190:4:14;2178:17;;;2160:36;;2148:2;2133:18;4641:65:8;2018:184:14;7996:1661:0;;;;;;:::i;:::-;;:::i;:::-;;;;2892:4:14;2880:17;;;2862:36;;2934:17;;;;2929:2;2914:18;;2907:45;2968:18;;;2961:34;2850:2;2835:18;7996:1661:0;2668:333:14;10950:114:0;;;;;;:::i;:::-;-1:-1:-1;;;;;11036:14:0;;;11010:7;11036:14;;;:8;:14;;;;;:21;;;10950:114;;;;-1:-1:-1;;;;;3422:32:14;;;3404:51;;3392:2;3377:18;10950:114:0;3258:203:14;4011:137:0;;;;;;:::i;:::-;;:::i;:::-;;1668:101:9;;;:::i;10782:130:0:-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;9695:::-;;;;;;:::i;:::-;;:::i;1036:85:9:-;1108:6;;-1:-1:-1;;;;;1108:6:9;1036:85;;4186:1160:0;;;;;;:::i;:::-;;:::i;:::-;;;4712:25:14;;;4700:2;4685:18;4186:1160:0;4566:177:14;9863:97:0;9914:7;9940:13;9863:97;;6022:983;;;;;;:::i;:::-;;:::i;7043:277::-;;;;;;:::i;:::-;;:::i;:::-;;;5238:14:14;;5231:22;5213:41;;5201:2;5186:18;7043:277:0;5073:187:14;1918:198:9;;;;;;:::i;:::-;;:::i;3520:266:0:-;;;;;;:::i;:::-;;:::i;9998:746::-;6477:6:8;:13;10078:22:0;;6411:143:8;;;;6464:26;;6460:76;;6499:37;;-1:-1:-1;;;6499:37:8;;;;;4712:25:14;;;4685:18;;6499:37:8;;;;;;;;6460:76;10134:6:0::1;:13:::0;10120:28:::1;::::0;::::1;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;-1:-1:-1;10120:28:0::1;-1:-1:-1::0;10214:21:0::1;::::0;::::1;10158:22;10214:21:::0;;;:14:::1;:21;::::0;;;;;10112:36;;-1:-1:-1;10158:22:0;;10245:303:::1;10269:5;:12;10265:1;:16;10245:303;;;10414:1;10401:9;:14;;10419:1;10400:20;10424:1;10400:25:::0;10396:107:::1;;10475:6;10482:1;10475:9;;;;;;;;:::i;:::-;;::::0;;;::::1;::::0;;;::::1;::::0;10449:23;;10475:9;10455:16;::::1;::::0;-1:-1:-1;;;;;10475:9:0;;::::1;::::0;10449:5;;:23;::::1;;;;;:::i;:::-;;;;;;:35;-1:-1:-1::0;;;;;10449:35:0::1;;;-1:-1:-1::0;;;;;10449:35:0::1;;;::::0;::::1;10396:107;10520:3;;10245:303;;;-1:-1:-1::0;;10699:29:0;;-1:-1:-1;10706:5:0;9998:746;-1:-1:-1;9998:746:0:o;11102:460::-;11221:19;6477:13:8;;11221:19:0;;11193:9;;6464:26:8;;6460:76;;6499:37;;-1:-1:-1;;;6499:37:8;;;;;4712:25:14;;;4685:18;;6499:37:8;4566:177:14;6460:76:8;11276:11:0::1;11290:6:::0;11297:9:::1;11290:17;;;;;;;;:::i;:::-;;::::0;;;::::1;::::0;;;::::1;:23:::0;-1:-1:-1;;;11290:23:0;::::1;;;::::0;-1:-1:-1;11394:9:0;;11390:166:::1;;11433:50;11451:9;11461;11451:20;;;;;;;;:::i;:::-;;;;;;;;;11481:1;11473:5;:9;;;;:::i;:::-;11433:50;;:17;:50::i;:::-;11419:64;;11510:6;11517;11524:9;11517:17;;;;;;;;:::i;:::-;;::::0;;;::::1;::::0;;;::::1;:27:::0;11510:35;;-1:-1:-1;;;11517:27:0;;::::1;;;::::0;11510:35;::::1;;;;;:::i;:::-;;::::0;;;::::1;::::0;;;::::1;::::0;-1:-1:-1;;;;;11510:35:0::1;::::0;-1:-1:-1;11390:166:0::1;11266:296;11102:460:::0;;;;:::o;7996:1661::-;8161:23;8198:21;8233;8376:8;-1:-1:-1;;;;;8365:19:0;:7;-1:-1:-1;;;;;8365:19:0;;:36;;;-1:-1:-1;8388:13:0;;8365:36;8361:83;;;-1:-1:-1;8425:1:0;;-1:-1:-1;8425:1:0;;-1:-1:-1;8425:1:0;8417:16;;8361:83;-1:-1:-1;;;;;8473:20:0;;;8453:17;8473:20;;;:11;:20;;;;;;:27;8528:21;;;;;;;:28;;8625:1026;8649:9;8645:1;:13;8625:1026;;;-1:-1:-1;;;;;8703:20:0;;8679:21;8703:20;;;:11;:20;;;;;:23;;8724:1;;8703:23;;;;;;:::i;:::-;;;;;;;;;8679:47;;8809:9;8804:837;8828:7;8824:1;:11;8804:837;;;-1:-1:-1;;;;;8882:21:0;;8860:19;8882:21;;;:11;:21;;;;;:24;;8904:1;;8882:24;;;;;;:::i;:::-;;;;;;;;;8860:46;;9149:17;9169:213;9225:13;9273:11;9316:8;9359:4;9169:18;:213::i;:::-;:223;;;9149:243;;9426:13;9414:9;:25;9410:217;;;9479:9;9463:25;;9536:13;9510:40;;9596:11;9572:36;;9410:217;8842:799;;8837:3;;;;:::i;:::-;;;8804:837;;;;8665:986;8660:3;;;;:::i;:::-;;;8625:1026;;;;8269:1388;;7996:1661;;;;;;;;:::o;4011:137::-;1108:6:9;;-1:-1:-1;;;;;1108:6:9;719:10:13;1248:23:9;1240:68;;;;-1:-1:-1;;;1240:68:9;;;;;;;:::i;:::-;4103:38:0::1;4121:4;4127:13;4103:17;:38::i;:::-;4011:137:::0;;:::o;1668:101:9:-;1108:6;;-1:-1:-1;;;;;1108:6:9;719:10:13;1248:23:9;1240:68;;;;-1:-1:-1;;;1240:68:9;;;;;;;:::i;:::-;1732:30:::1;1759:1;1732:18;:30::i;:::-;1668:101::o:0;10782:130:0:-;-1:-1:-1;;;;;10887:18:0;;;;;;:11;:18;;;;;;;;;10879:26;;;;;;;;;;;;;;;;;10845:22;;10879:26;;;10887:18;10879:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;10782:130;;;:::o;9695:::-;9767:13;6477::8;;6411:143;;;;6464:26;;6460:76;;6499:37;;-1:-1:-1;;;6499:37:8;;;;;4712:25:14;;;4685:18;;6499:37:8;4566:177:14;6460:76:8;9799:6:0::1;9806:5;9799:13;;;;;;;;;;:::i;:::-;;::::0;;;::::1;::::0;;;::::1;:19:::0;-1:-1:-1;;;;;9799:19:0::1;::::0;9695:130;-1:-1:-1;;;9695:130:0:o;4186:1160::-;4399:17;6477:13:8;;6411:143;;;;6464:26;;6460:76;;6499:37;;-1:-1:-1;;;6499:37:8;;;;;4712:25:14;;;4685:18;;6499:37:8;4566:177:14;6460:76:8;6477:6:::1;:13:::0;6411:143:::1;::::0;::::1;::::0;6464:26;::::1;6460:76;;6499:37;::::0;-1:-1:-1;;;6499:37:8;;::::1;::::0;::::1;4712:25:14::0;;;4685:18;;6499:37:8::1;4566:177:14::0;6460:76:8::1;4504:8:0::2;4486:15;:26;4482:94;;;4521:55;::::0;-1:-1:-1;;;4521:55:0;;4550:15:::2;4521:55;::::0;::::2;6953:25:14::0;6994:18;;;6987:34;;;6926:18;;4521:55:0::2;6779:248:14::0;4482:94:0::2;4607:11;4590:28;;:13;:28;;::::0;4586:84:::2;;4627:43;::::0;-1:-1:-1;;;4627:43:0;;2190:4:14;2178:17;;4627:43:0::2;::::0;::::2;2160:36:14::0;2133:18;;4627:43:0::2;2018:184:14::0;4586:84:0::2;4839:15;4857:6:::0;4864:13:::2;4857:21;;;;;;;;;;:::i;:::-;;::::0;;;::::2;::::0;;;::::2;:27:::0;-1:-1:-1;;;;;4857:27:0::2;::::0;-1:-1:-1;4894:63:0::2;4857:27:::0;4927:10:::2;4947:4;4954:2:::0;4894:32:::2;:63::i;:::-;4979:42;4990:13;4979:42;;5005:11;4979:42;;5018:2;4979:10;:42::i;:::-;:52;;;4967:64;;5057:5;5045:9;:17;5041:71;;;5071:41;::::0;-1:-1:-1;;;5071:41:0;;::::2;::::0;::::2;6953:25:14::0;;;6994:18;;;6987:34;;;6926:18;;5071:41:0::2;6779:248:14::0;5041:71:0::2;5165:69;5212:10;5224:9;5172:6;5179:11;5172:19;;;;;;;;;;:::i;:::-;;::::0;;;::::2;::::0;;;::::2;:25:::0;-1:-1:-1;;;;;5172:25:0::2;::::0;5165:69;:46:::2;:69::i;:::-;5275:64;::::0;;7259:25:14;;;7315:2;7300:18;;7293:34;;;7375:4;7363:17;;;7343:18;;;7336:45;7417:17;;7412:2;7397:18;;7390:45;5275:64:0;;5285:10:::2;::::0;5275:64:::2;::::0;;;;;7246:3:14;5275:64:0;;::::2;4418:928;6546:1:8::1;4186:1160:0::0;;;;;;;;:::o;6022:983::-;6150:17;6201:13;;6285:28;;;;-1:-1:-1;6285:28:0;;:58;;;6332:11;6317;:26;;;;6285:58;6281:97;;;6366:1;6359:8;;;;;6281:97;6465:11;6448:28;;:13;:28;;;6444:67;;6499:1;6492:8;;;;;6444:67;6820:168;6868:13;6820:168;;6908:11;6820:168;;6943:2;6972:5;6820:18;:168::i;:::-;:178;;;6808:190;;6169:836;6022:983;;;;;;:::o;7043:277::-;-1:-1:-1;;;;;7246:20:0;;7129:17;7246:20;;;:11;:20;;;;;:27;:31;;;;:67;;-1:-1:-1;;;;;;7281:21:0;;7312:1;7281:21;;;:11;:21;;;;;:28;:32;;7246:67;7239:74;;7043:277;;;;;:::o;1918:198:9:-;1108:6;;-1:-1:-1;;;;;1108:6:9;719:10:13;1248:23:9;1240:68;;;;-1:-1:-1;;;1240:68:9;;;;;;;:::i;:::-;-1:-1:-1;;;;;2006:22:9;::::1;1998:73;;;::::0;-1:-1:-1;;;1998:73:9;;7648:2:14;1998:73:9::1;::::0;::::1;7630:21:14::0;7687:2;7667:18;;;7660:30;7726:34;7706:18;;;7699:62;-1:-1:-1;;;7777:18:14;;;7770:36;7823:19;;1998:73:9::1;7446:402:14::0;1998:73:9::1;2081:28;2100:8;2081:18;:28::i;:::-;1918:198:::0;:::o;3520:266:0:-;1108:6:9;;-1:-1:-1;;;;;1108:6:9;719:10:13;1248:23:9;1240:68;;;;-1:-1:-1;;;1240:68:9;;;;;;;:::i;:::-;6477:6:8::1;:13:::0;3650:9:0;;6464:26:8;::::1;6460:76;;6499:37;::::0;-1:-1:-1;;;6499:37:8;;::::1;::::0;::::1;4712:25:14::0;;;4685:18;;6499:37:8::1;4566:177:14::0;6460:76:8::1;-1:-1:-1::0;;;;;3675:18:0;::::2;3671:61;;3702:30;;-1:-1:-1::0;;;3702:30:0::2;;;;;;;;;;;3671:61;3742:37;3751:9;3762:4;3768:10;3742:8;:37::i;:::-;1318:1:9::1;3520:266:0::0;;;:::o;30956:243:8:-;31039:17;31174:9;31178:5;31174:1;:9;:::i;:::-;31161:8;:23;;31188:4;31160:32;31153:39;;30956:243;;;;:::o;20015:3798::-;-1:-1:-1;;;;;;;;;;;;;;;;;20261:18:8;20282:89;;;;;;;;20297:6;20304:13;20297:21;;;;;;;;:::i;:::-;;;;;;;;;20282:89;;;;;;;;20297:21;;;;20282:89;-1:-1:-1;;;;;20282:89:8;;;;;-1:-1:-1;;;20282:89:8;;;;;;;;-1:-1:-1;;;20282:89:8;;;;;;;;;;;20324:19;;20282:89;;;20331:11;;20324:19;;;;;;:::i;:::-;;;;;;;;;20282:89;;;;;;;;20324:19;;;;20282:89;-1:-1:-1;;;;;20282:89:8;;;;;-1:-1:-1;;;20282:89:8;;;;;;;;-1:-1:-1;;;20282:89:8;;;;;;;;;;;;;;;;;;;;20404:9;:24;;20261:110;;-1:-1:-1;20324:19:8;;20414:13;;20404:24;;;;;;:::i;:::-;;;;;;;;;20381:47;;20438:18;20459:9;20469:11;20459:22;;;;;;;;:::i;:::-;;;;;;;;;20438:43;;20541:17;20561:36;20572:12;20586:10;20561;:36::i;:::-;20541:56;;20735:3;:6;;;:12;;;20723:24;;:9;:24;20719:310;;;20924:94;20949:1;20952:12;20966:3;:8;;;:14;;;20924:94;;20982:3;:6;;;:12;;;20924:94;;20996:8;21006:11;20924:24;:94::i;:::-;20917:101;;;;;;;;20719:310;21168:8;;:14;;;21156:26;;;;21152:314;;;21361:94;21388:1;21391:10;21403:3;:8;;;:14;;;21361:94;;21419:3;:6;;;:12;;;21361:94;;21433:8;21443:11;21361:26;:94::i;21152:314::-;21590:198;21628:5;:22;;;21664:12;21690:3;:8;;;:14;;;21590:198;;21718:9;21741:8;21763:3;:15;;;21590:24;:198::i;:::-;21582:206;;22040:21;22064:42;22082:12;22096:9;22064:17;:42::i;:::-;22040:66;;22116:20;22139:40;22157:10;22169:9;22139:17;:40::i;:::-;22116:63;;22189:22;22214:6;22221:13;22214:21;;;;;;;;:::i;:::-;;;;;;;;;:31;22281:20;;-1:-1:-1;;;22214:31:8;;;;;;-1:-1:-1;22214:21:8;;22288:12;;22281:20;;;;;;:::i;:::-;;;;;;;;;;:30;-1:-1:-1;;;22281:30:8;;;;;-1:-1:-1;22325:33:8;;;22321:1134;;22458:232;22495:5;:22;;;22535:14;22567:13;22598:12;22628:5;:15;;;22661:3;:15;;;22458:19;:232::i;:::-;22439:15;;;22414:276;;;22321:1134;;;22760:19;22782:46;22800:12;22814:13;22826:1;22814:9;:13;:::i;:::-;22782:17;:46::i;:::-;22760:68;;22886:231;22923:5;:22;;;22963:14;22995:13;23026:11;23055:5;:15;;;23088:3;:15;;;22886:19;:231::i;:::-;22867:15;;;22842:275;;;;;;23415:15;;;;23213:231;;22842:275;23290:15;;23323:11;;23352:12;;23213:19;:231::i;:::-;23194:15;;;23169:275;;;-1:-1:-1;22321:1134:8;23575:231;23619:5;:22;;;23659:10;23687:9;23714:3;:6;;;:12;;;23575:231;;23744:5;:15;;;23777:3;:15;;;23575:26;:231::i;:::-;23556:250;;;;;;;;;;20015:3798;;;;;;;:::o;10703:873::-;-1:-1:-1;;;;;10858:14:8;;;10834:21;10858:14;;;:8;:14;;;;;:21;;;10889:64;;10929:24;;-1:-1:-1;;;10929:24:8;;;;;;;;;;;10889:64;11037:26;11066:35;11081:13;11096:4;11066:14;:35::i;:::-;11037:64;;11111:26;11140:35;11155:13;11170:4;11140:14;:35::i;:::-;11111:64;;11209:9;:16;11189:9;:16;:36;11185:81;;11234:32;;-1:-1:-1;;;11234:32:8;;;;;;;;;;;11185:81;11281:9;11276:145;11300:9;:16;11296:1;:20;11276:145;;;11357:9;11367:1;11357:12;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;;;;11341:28:8;:9;11351:1;11341:12;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;;;;11341:28:8;;11337:73;;11378:32;;-1:-1:-1;;;11378:32:8;;;;;;;;;;;11337:73;11318:3;;;:::i;:::-;;;11276:145;;;-1:-1:-1;;;;;;11464:14:8;;;;;;;:8;:14;;;;;;;;;:37;;-1:-1:-1;;;;;;11464:37:8;;;;;;;;;;11516:53;;8399:34:14;;;8469:15;;;8449:18;;;8442:43;8501:18;;8494:43;;;;11516:53:8;;8349:2:14;8334:18;11516:53:8;;;;;;;;10776:800;;;10703:873;;:::o;2270:187:9:-;2362:6;;;-1:-1:-1;;;;;2378:17:9;;;-1:-1:-1;;;;;;2378:17:9;;;;;;;2410:40;;2362:6;;;2378:17;2362:6;;2410:40;;2343:16;;2410:40;2333:124;2270:187;:::o;912:241:11:-;1077:68;;-1:-1:-1;;;;;8806:15:14;;;1077:68:11;;;8788:34:14;8858:15;;8838:18;;;8831:43;8890:18;;;8883:34;;;1050:96:11;;1070:5;;-1:-1:-1;;;1100:27:11;8723:18:14;;1077:68:11;;;;-1:-1:-1;;1077:68:11;;;;;;;;;;;;;;-1:-1:-1;;;;;1077:68:11;-1:-1:-1;;;;;;1077:68:11;;;;;;;;;;1050:19;:96::i;12126:3313:8:-;-1:-1:-1;;;;;;;;;;;;;;;;;12333:18:8;12354:83;;;;;;;;12369:6;12376:13;12369:21;;;;;;;;:::i;:::-;;;;;;;;;12354:83;;;;;;;;12369:21;;;;12354:83;-1:-1:-1;;;;;12354:83:8;;;;;-1:-1:-1;;;12354:83:8;;;;;;;;-1:-1:-1;;;12354:83:8;;;;;;;;;;;12396:19;;12354:83;;;12403:11;;12396:19;;;;;;:::i;:::-;;;;;;;;;12354:83;;;;;;;;12396:19;;;;12354:83;-1:-1:-1;;;;;12354:83:8;;;;;-1:-1:-1;;;12354:83:8;;;;;;;;-1:-1:-1;;;12354:83:8;;;;;;;;;;;;;;;;;;12470:9;:24;;12333:104;;-1:-1:-1;12396:19:8;;12480:13;;12470:24;;;;;;:::i;:::-;;;;;;;;;12447:47;;12504:18;12525:9;12535:11;12525:22;;;;;;;;:::i;:::-;;;;;;;;;12504:43;;12607:17;12627:36;12638:12;12652:10;12627;:36::i;:::-;12607:56;;12801:3;:6;;;:12;;;12789:24;;:9;:24;12785:289;;;12990:73;13007:1;13010:12;13024:3;:8;;;:14;;;12990:73;;13040:3;:6;;;:12;;;12990:73;;13054:8;12990:16;:73::i;:::-;12983:80;;;;;;;;12785:289;13213:8;;:14;;;13201:26;;;;13197:293;;;13406:73;13425:1;13428:10;13440:3;:8;;;:14;;;13406:73;;13456:3;:6;;;:12;;;13406:73;;13470:8;13406:18;:73::i;13197:293::-;13614:70;13631:1;13634:12;13648:3;:8;;;:14;;;13614:70;;13664:9;13675:8;13614:16;:70::i;:::-;13606:78;;13936:21;13960:42;13978:12;13992:9;13960:17;:42::i;:::-;13936:66;;14012:20;14035:40;14053:10;14065:9;14035:17;:40::i;:::-;14012:63;;14085:22;14110:6;14117:13;14110:21;;;;;;;;:::i;:::-;;;;;;;;;:31;14177:20;;-1:-1:-1;;;14110:31:8;;;;;;-1:-1:-1;14110:21:8;;14184:12;;14177:20;;;;;;:::i;:::-;;;;;;;;;;:30;-1:-1:-1;;;14177:30:8;;;;;-1:-1:-1;14221:33:8;;;14217:1011;;14354:191;14383:5;:22;;;14423:14;14455:13;14486:12;14516:5;:15;;;14354:11;:191::i;:::-;14335:15;;;14310:235;;;14217:1011;;;14615:19;14637:46;14655:12;14669:13;14681:1;14669:9;:13;:::i;14637:46::-;14615:68;;14741:190;14770:5;:22;;;14810:14;14842:13;14873:11;14902:5;:15;;;14741:11;:190::i;:::-;14722:15;;;14697:234;;;;;;15027:190;;14697:234;15096:15;;15129:11;;15158:12;;15027:11;:190::i;:::-;15008:15;;;14983:234;;;-1:-1:-1;14217:1011:8;15336:96;15355:5;:22;;;15379:10;15391:9;15402:3;:6;;;:12;;;15336:96;;15416:5;:15;;;15336:18;:96::i;:::-;15329:103;12126:3313;-1:-1:-1;;;;;;;;;;;;12126:3313:8:o;701:205:11:-;840:58;;-1:-1:-1;;;;;9120:32:14;;840:58:11;;;9102:51:14;9169:18;;;9162:34;;;813:86:11;;833:5;;-1:-1:-1;;;863:23:11;9075:18:14;;840:58:11;8928:274:14;813:86:11;701:205;;;:::o;7142:2104:8:-;7262:16;7281:6;7288:9;7281:17;;;;;;;;:::i;:::-;;;;;;;;;;7262:36;;;;;;;;7281:17;;;;7262:36;-1:-1:-1;;;;;7262:36:8;;;;;;-1:-1:-1;;;7262:36:8;;;;;;;;;;;-1:-1:-1;;;7262:36:8;;;;;;;;;;;-1:-1:-1;7312:24:8;;7308:56;;7359:4;7338:26;;7308:56;-1:-1:-1;;;;;7417:14:8;;7375:13;7417:14;;;:8;:14;;;;;:20;-1:-1:-1;;;7417:20:8;;;;7525:14;;;7521:740;;7559:6;:13;7575:15;-1:-1:-1;7555:69:8;;;7599:25;;-1:-1:-1;;;7599:25:8;;;;;;;;;;;7555:69;-1:-1:-1;;7751:6:8;:13;;7779:17;;;;;;;;;;-1:-1:-1;;;;;7779:17:8;;;-1:-1:-1;;;;;;7779:17:8;;;;;;;;7827:44;;;;;;;;;;;;;;;;;;7779:17;7827:44;;;;;;-1:-1:-1;7810:14:8;;;:8;:14;;;;;:61;;;;;;;;;-1:-1:-1;;;7810:61:8;-1:-1:-1;;;;;;7810:61:8;;;;;;;;;;;;;;;7919:38;;9409:25:14;;;9488:18;;;9481:43;;;;9540:18;;9533:43;7919:38:8;;9397:2:14;9382:18;7919:38:8;;;;;;;7521:740;;;8198:52;8217:9;8228:4;:10;;;8198:52;;8240:9;8198:18;:52::i;:::-;8328:25;;;;:14;:25;;;;;:43;;8357:1;:14;;;;8328:43;;;8407:32;8422:10;8434:4;8407:14;:32::i;:::-;8381:58;;8449:17;8469:6;:13;8449:33;;8492:14;8548:16;8567:4;:10;;;8580:1;8567:14;8548:33;;8595:22;8620:9;8630;8620:20;;;;;;;;:::i;:::-;;;;;;;;;8595:45;;8659:9;8654:512;8678:9;8674:1;:13;8654:512;;;8712:13;8728:6;8735:1;8728:9;;;;;;;;:::i;:::-;;;;;;;8712:25;;8819:8;8815:91;;;-1:-1:-1;;;;;8851:18:8;;;;;;;:12;:18;;;;;;;;:25;;;;;;;;;:36;;-1:-1:-1;;8851:36:8;;;;;;;8815:91;8981:4;:10;;;-1:-1:-1;;;;;8972:19:8;:5;-1:-1:-1;;;;;8972:19:8;;8968:112;;9027:4;9015:16;;9053:8;;;8968:112;9097:54;9106:5;9113:10;9125:9;9136:14;9097:8;:54::i;:::-;8694:472;8654:512;8689:3;;8654:512;;;;8524:652;;9190:9;9185:54;;9208:31;;-1:-1:-1;;;9208:31:8;;;;;;;;;;;9185:54;7252:1994;;;;;;7142:2104;;;:::o;30172:677::-;30428:22;;;;30253:17;30529:14;;;30522:22;;;;:::i;:::-;30628:215;30636:9;30648:4;30636:16;30657:1;30635:23;30628:215;;30764:1;30750:15;;;;;30807:11;;30628:215;;25313:1113;-1:-1:-1;;;;;;;;;;;;;;;;;25570:17:8;25590:38;25608:8;25618:9;25590:17;:38::i;:::-;25570:58;-1:-1:-1;25743:9:8;25722:611;25762:7;25754:5;:15;25722:611;;;-1:-1:-1;;25850:7:8;25926:19;25948:34;25966:8;25850:7;25948:17;:34::i;:::-;25926:56;;26062:223;26099:16;26133:6;26140:9;26133:17;;;;;;;;:::i;:::-;;;;;;;;;;:27;-1:-1:-1;;;26133:27:8;;;;26178:9;26205:11;26234:8;26260:11;26062:19;:223::i;:::-;26031:254;;-1:-1:-1;26031:254:8;-1:-1:-1;26311:11:8;-1:-1:-1;25722:611:8;;;-1:-1:-1;;26342:41:8;;;-1:-1:-1;26393:15:8;;;:26;-1:-1:-1;26342:5:8;;25313:1113;-1:-1:-1;;25313:1113:8:o;24028:1072::-;-1:-1:-1;;;;;;;;;;;;;;;;;24287:17:8;24307:38;24325:8;24335:9;24307:17;:38::i;:::-;24287:58;-1:-1:-1;24462:9:8;24441:566;24481:7;24473:5;:15;24441:566;;;24568:7;;24603:18;24624:34;24642:8;24568:7;24624:17;:34::i;:::-;24603:55;;24737:223;24774:16;24808:6;24815:10;24808:18;;;;;;;;:::i;24737:223::-;24706:254;;-1:-1:-1;24706:254:8;-1:-1:-1;24986:10:8;-1:-1:-1;24441:566:8;;27525:928;27756:25;;27836:1;:14;;27816:35;;:40;27812:275;;-1:-1:-1;;;28055:17:8;-1:-1:-1;28074:1:8;28047:29;;27812:275;28188:9;28183:1;:14;;28163:16;:35;28143:55;;28208:12;28223:6;28230:9;28223:17;;;;;;;;:::i;:::-;;;;;;;;;;;;;-1:-1:-1;;;;;28223:17:8;;;28367:14;;;:8;:14;;;;;;;:21;28223:17;;-1:-1:-1;28353:93:8;;28367:21;28223:17;28396:13;28411:11;28424:8;28434:11;28353:13;:93::i;:::-;28341:105;;27802:651;27525:928;;;;;;;;;;:::o;17136:1250:0:-;17226:23;17287:4;-1:-1:-1;;;;;17265:27:0;;;17261:1119;;17435:17;17470:276;17505:45;;-1:-1:-1;;;17505:45:0;;2190:4:14;2178:17;;17505:45:0;;;2160:36:14;-1:-1:-1;;;;;17505:27:0;;;;;2133:18:14;;17505:45:0;;;;;;;;;;;;;;;;;;-1:-1:-1;17505:45:0;;;;;;;;-1:-1:-1;;17505:45:0;;;;;;;;;;;;:::i;:::-;;;17501:231;17708:5;17501:231;-1:-1:-1;17627:11:0;;17470:276;;;17842:9;17828:24;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;17828:24:0;;17819:33;;17871:9;17866:190;17890:9;17886:1;:13;17866:190;;;17933:37;;-1:-1:-1;;;17933:37:0;;2190:4:14;2178:17;;17933:37:0;;;2160:36:14;-1:-1:-1;;;;;17933:27:0;;;;;2133:18:14;;17933:37:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;17921:6;17928:1;17921:9;;;;;;;;:::i;:::-;-1:-1:-1;;;;;17921:49:0;;;:9;;;;;;;;;;;:49;18020:3;;17866:190;;;;17294:772;17261:1119;;;18326:43;;-1:-1:-1;;;18326:43:0;;-1:-1:-1;;;;;3422:32:14;;;18326:43:0;;;3404:51:14;18326:37:0;;;;;3377:18:14;;18326:43:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;18326:43:0;;;;;;;;;;;;:::i;3207:706:11:-;3626:23;3652:69;3680:4;3652:69;;;;;;;;;;;;;;;;;3660:5;-1:-1:-1;;;;;3652:27:11;;;:69;;;;;:::i;:::-;3735:17;;3626:95;;-1:-1:-1;3735:21:11;3731:176;;3830:10;3819:30;;;;;;;;;;;;:::i;:::-;3811:85;;;;-1:-1:-1;;;3811:85:11;;11736:2:14;3811:85:11;;;11718:21:14;11775:2;11755:18;;;11748:30;11814:34;11794:18;;;11787:62;-1:-1:-1;;;11865:18:14;;;11858:40;11915:19;;3811:85:11;11534:406:14;16899:1037:8;-1:-1:-1;;;;;;;;;;;;;;;;;17117:17:8;17137:38;17155:8;17165:9;17137:17;:38::i;:::-;17117:58;-1:-1:-1;17290:9:8;17269:574;17309:7;17301:5;:15;17269:574;;;-1:-1:-1;;17397:7:8;17473:19;17495:34;17513:8;17397:7;17495:17;:34::i;:::-;17473:56;;17609:186;17638:16;17672:6;17679:9;17672:17;;;;;;;;:::i;:::-;;;;;;;;;;:27;-1:-1:-1;;;17672:27:8;;;;17717:9;17744:11;17773:8;17609:11;:186::i;:::-;17578:217;;-1:-1:-1;17578:217:8;-1:-1:-1;17821:11:8;-1:-1:-1;17269:574:8;;;-1:-1:-1;;17852:41:8;;;17903:15;;;:26;-1:-1:-1;17852:5:8;;16899:1037;-1:-1:-1;;16899:1037:8:o;15672:996::-;-1:-1:-1;;;;;;;;;;;;;;;;;15892:17:8;15912:38;15930:8;15940:9;15912:17;:38::i;:::-;15892:58;-1:-1:-1;16067:9:8;16046:529;16086:7;16078:5;:15;16046:529;;;16173:7;;16208:18;16229:34;16247:8;16173:7;16229:17;:34::i;:::-;16208:55;;16342:186;16371:16;16405:6;16412:10;16405:18;;;;;;;;:::i;16342:186::-;16311:217;;-1:-1:-1;16311:217:8;-1:-1:-1;16554:10:8;-1:-1:-1;16046:529:8;;18864:659;19056:25;19083:17;19112:12;19127:6;19134:9;19127:17;;;;;;;;:::i;:::-;;;;;;;;;;;-1:-1:-1;;;;;19127:17:8;;-1:-1:-1;19127:17:8;19254:14;;19234:35;;:40;19230:87;;19283:34;;-1:-1:-1;;;19283:34:8;;-1:-1:-1;;;;;3422:32:14;;19283:34:8;;;3404:51:14;3377:18;;19283:34:8;3258:203:14;19230:87:8;-1:-1:-1;;;;;19450:14:8;;;;;;;:8;:14;;;;;:21;19403:1;:14;;19383:35;;;-1:-1:-1;19440:76:8;;19450:21;19459:4;19479:13;19494:11;19507:8;19440:9;:76::i;:::-;19428:88;;19102:421;18864:659;;;;;;;;:::o;29124:870::-;29332:25;;;;:14;:25;;;;;;29361:1;:14;;;;29332:44;:49;29328:94;;29390:32;;-1:-1:-1;;;29390:32:8;;;;;;;;;;;29328:94;29664:16;29683:9;29693;29683:20;;;;;;;;:::i;:::-;;;;;;;;;;;;-1:-1:-1;29730:1:8;29713:275;29738:9;29733:1;:14;29713:275;;29765:18;29786:30;29804:8;29814:1;29786:17;:30::i;:::-;29765:51;;29866:9;29834:41;;:6;29841:10;29834:18;;;;;;;;:::i;:::-;;;;;;;;;;:28;-1:-1:-1;;;29834:28:8;;;;:41;29830:88;;29884:34;;-1:-1:-1;;;29884:34:8;;;;;;;;;;;29830:88;-1:-1:-1;29960:3:8;;29713:275;;;;29251:743;29124:870;;;:::o;9325:1193::-;9519:17;9539:13;9578:15;9566:27;;9562:65;;;9602:25;;-1:-1:-1;;;9602:25:8;;;;;;;;;;;9562:65;10077:1;10061:13;:17;;;;:45;;;10091:6;10098:1;10091:9;;;;;;;;:::i;:::-;;;;;;;;;;:15;-1:-1:-1;;;;;10082:24:8;;;10091:15;;10082:24;10061:45;10057:82;;;10122:7;;;10057:82;10160:56;;;;;;;;-1:-1:-1;;;;;10160:56:8;;;;;;;;;;;;;;;;;;;;;;;;;;10148:6;:69;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;10148:69:8;-1:-1:-1;;;;10148:69:8;;;;-1:-1:-1;;;10148:69:8;-1:-1:-1;;;;;;10148:69:8;;;;;;;;;;;;;;;;;;;;10227:18;;;:11;:18;;;;;:34;;;;;;;;;;;;;;;;;10386:9;10430:14;10416:9;10187:5;10416:1;:9;:::i;:::-;10386:59;;;;;;;;-1:-1:-1;10386:59:8;;;;;;;10402:24;;;;;;;10401:43;;;;10386:59;;;;;;10493:17;;10460:51;;10402:9;;10486:5;;10493:17;;;;;;;;;;:::i;:::-;;;;;;;;;;;10460:51;;;;;;-1:-1:-1;;;;;10493:17:8;;9409:25:14;;;-1:-1:-1;;;;;9508:15:14;;;9503:2;9488:18;;9481:43;9560:15;9555:2;9540:18;;9533:43;9397:2;9382:18;;9207:375;14586:2478:0;14809:17;14864:4;-1:-1:-1;;;;;14842:27:0;;;14838:2220;;14942:11;14938:460;;;15152:49;;;;;;;;;;;;;;;;-1:-1:-1;;;;;15152:49:0;-1:-1:-1;;;15152:49:0;;;15115:104;;15074:12;;;;-1:-1:-1;;;;;15115:15:0;;;:104;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;15073:146;;;;15241:7;:41;;;;;15263:10;15252:30;;;;;;;;;;;;:::i;:::-;15237:147;;;15364:1;15357:8;;;;;;15237:147;14955:443;;14938:460;-1:-1:-1;;;;;15487:32:0;;15558:18;;;;:12;:18;;;;;15577:21;;15487:32;;15558:18;;;15584:13;;15577:21;;;;;;:::i;:::-;;;;;;;;;;;;:27;-1:-1:-1;;;;;15577:27:0;;;15558:47;;;;;;;;;;;;;;;;15641:18;;;;;:12;:18;;;;;15660:19;;15558:47;;;;;15641:18;;15577:21;;;15667:11;;15660:19;;;;;;:::i;:::-;;;;;;;;;;;;;:25;-1:-1:-1;;;;;15660:25:0;15641:45;;;;;;;;;;;;;;;;15487:252;;;;;;-1:-1:-1;;;;;;15487:252:0;;;15641:45;2880:17:14;;;15487:252:0;;;2862:36:14;15641:45:0;;2914:18:14;;;2907:45;2968:18;;;2961:34;;;2835:18;;15487:252:0;;;;;;;;;;;;;;;;;;-1:-1:-1;15487:252:0;;;;;;;;-1:-1:-1;;15487:252:0;;;;;;;;;;;;:::i;:::-;;;15467:495;;-1:-1:-1;15946:1:0;14838:2220;;15467:495;15811:10;-1:-1:-1;14838:2220:0;;;16046:17;16066:6;16073:13;16066:21;;;;;;;;:::i;:::-;;;;;;;;;:27;16125:19;;-1:-1:-1;;;;;16066:27:0;;;;-1:-1:-1;16066:21:0;;16132:11;;16125:19;;;;;;:::i;:::-;;;;;;;;;;;;:25;16579:70;;;;;;;;-1:-1:-1;;;;;16600:18:0;;;;;:12;:18;;;;;:29;;;;;;;;;;;;;;;;;16579:70;;;;;;;;;16671:66;;;;;;;16125:25;;;16692:27;;;;;;;;;;;;;;16671:66;;;;;;;;16495:323;;-1:-1:-1;;;16495:323:0;;16125:25;;-1:-1:-1;16495:36:0;;;;;;:323;;16553:4;;16759:8;;16789:11;;16495:323;;;:::i;:::-;;;;;;;;;;;;;;;;;;;-1:-1:-1;16495:323:0;;;;;;;;-1:-1:-1;;16495:323:0;;;;;;;;;;;;:::i;:::-;;;16475:573;;17032:1;17020:13;;16475:573;;;16890:10;-1:-1:-1;16475:573:0;15978:1080;;14838:2220;14586:2478;;;;;;;;:::o;3861:223:12:-;3994:12;4025:52;4047:6;4055:4;4061:1;4064:12;4025:21;:52::i;12028:2152:0:-;12216:17;12245;12265:6;12272:13;12265:21;;;;;;;;:::i;:::-;;;;;;;;;:27;12320:19;;-1:-1:-1;;;;;12265:27:0;;;;-1:-1:-1;12265:21:0;;12327:11;;12320:19;;;;;;:::i;:::-;;;;;;;;;;:25;-1:-1:-1;;;;;12320:25:0;;;;-1:-1:-1;12435:4:0;12413:27;;;;12409:1765;;12456:50;-1:-1:-1;;;;;12456:34:0;;12491:4;12497:8;12456:34;:50::i;:::-;-1:-1:-1;;;;;12648:23:0;;;12706:18;;;;:12;:18;;;;;;;;:29;;;;;;;;;;;;12767:27;;;;;;;;;12648:262;;-1:-1:-1;;;12648:262:0;;12706:29;;;;12648:262;;;14038:36:14;12767:27:0;;14090:18:14;;;14083:45;14144:18;;;14137:34;;;14187:18;;;14180:34;-1:-1:-1;;14230:19:14;;;14223:35;12648:23:0;;;14010:19:14;;12648:262:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;12636:274;;12409:1765;;;13444:70;;;;;;;;-1:-1:-1;;;;;13465:18:0;;;13312:20;13465:18;;;:12;:18;;;;;;;:29;;;;;;;;;;;;;;;;;13444:70;;;;;;;;;13532:66;;;;;;;13553:27;;;;;;;;;;;;;;13532:66;;;;;;13335:303;;-1:-1:-1;;;13375:29:0;13335:303;;13422:4;;13616:8;;13335:303;;;:::i;:::-;;;;-1:-1:-1;;13335:303:0;;;;;;;;;;;;;;-1:-1:-1;;;;;13335:303:0;-1:-1:-1;;;;;;13335:303:0;;;;;;;;;;;-1:-1:-1;;13977:40:0;-1:-1:-1;;;;;13977:31:0;;13335:303;13977:31;:40::i;:::-;13955:62;;14145:6;14134:29;;;;;;;;;;;;:::i;:::-;14122:41;;12927:1247;;12409:1765;12235:1945;;12028:2152;;;;;;;:::o;4948:499:12:-;5113:12;5170:5;5145:21;:30;;5137:81;;;;-1:-1:-1;;;5137:81:12;;15062:2:14;5137:81:12;;;15044:21:14;15101:2;15081:18;;;15074:30;15140:34;15120:18;;;15113:62;-1:-1:-1;;;15191:18:14;;;15184:36;15237:19;;5137:81:12;14860:402:14;5137:81:12;-1:-1:-1;;;;;1465:19:12;;;5228:60;;;;-1:-1:-1;;;5228:60:12;;15469:2:14;5228:60:12;;;15451:21:14;15508:2;15488:18;;;15481:30;15547:31;15527:18;;;15520:59;15596:18;;5228:60:12;15267:353:14;5228:60:12;5300:12;5314:23;5341:6;-1:-1:-1;;;;;5341:11:12;5360:5;5367:4;5341:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5299:73;;;;5389:51;5406:7;5415:10;5427:12;5389:16;:51::i;:::-;5382:58;4948:499;-1:-1:-1;;;;;;;4948:499:12:o;1326:600:7:-;-1:-1:-1;;;;;;;1518:20:7;;;1514:33;;1326:600;;;:::o;1514:33::-;1628:47;;-1:-1:-1;;;1628:47:7;;1660:4;1628:47;;;15837:34:14;-1:-1:-1;;;;;15907:15:14;;;15887:18;;;15880:43;1608:17:7;;1628:23;;;;;;15772:18:14;;1628:47:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;1608:67;;1702:13;1689:9;:26;1685:39;;1717:7;1326:600;;;:::o;1685:39::-;1804:13;;1800:56;;1819:37;-1:-1:-1;;;;;1819:25:7;;1845:7;1854:1;1819:25;:37::i;:::-;1866:53;-1:-1:-1;;;;;1866:25:7;;1892:7;-1:-1:-1;;1866:25:7;:53::i;6570:198:12:-;6653:12;6684:77;6705:6;6713:4;6684:77;;;;;;;;;;;;;;;;;:20;:77::i;7561:692::-;7707:12;7735:7;7731:516;;;-1:-1:-1;7765:10:12;7758:17;;7731:516;7876:17;;:21;7872:365;;8070:10;8064:17;8130:15;8117:10;8113:2;8109:19;8102:44;7872:365;8209:12;8202:20;;-1:-1:-1;;;8202:20:12;;;;;;;;:::i;1413:603:11:-;1768:10;;;1767:62;;-1:-1:-1;1784:39:11;;-1:-1:-1;;;1784:39:11;;1808:4;1784:39;;;15837:34:14;-1:-1:-1;;;;;15907:15:14;;;15887:18;;;15880:43;1784:15:11;;;;;15772:18:14;;1784:39:11;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:44;1767:62;1746:163;;;;-1:-1:-1;;;1746:163:11;;16537:2:14;1746:163:11;;;16519:21:14;16576:2;16556:18;;;16549:30;16615:34;16595:18;;;16588:62;-1:-1:-1;;;16666:18:14;;;16659:52;16728:19;;1746:163:11;16335:418:14;1746:163:11;1946:62;;-1:-1:-1;;;;;9120:32:14;;1946:62:11;;;9102:51:14;9169:18;;;9162:34;;;1919:90:11;;1939:5;;-1:-1:-1;;;1969:22:11;9075:18:14;;1946:62:11;8928:274:14;6954:387:12;7095:12;-1:-1:-1;;;;;1465:19:12;;;7119:69;;;;-1:-1:-1;;;7119:69:12;;16960:2:14;7119:69:12;;;16942:21:14;16999:2;16979:18;;;16972:30;17038:34;17018:18;;;17011:62;-1:-1:-1;;;17089:18:14;;;17082:36;17135:19;;7119:69:12;16758:402:14;7119:69:12;7200:12;7214:23;7241:6;-1:-1:-1;;;;;7241:19:12;7261:4;7241:25;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7199:67;;;;7283:51;7300:7;7309:10;7321:12;7283:16;:51::i;14:156:14:-;80:20;;140:4;129:16;;119:27;;109:55;;160:1;157;150:12;109:55;14:156;;;:::o;175:182::-;232:6;285:2;273:9;264:7;260:23;256:32;253:52;;;301:1;298;291:12;253:52;324:27;341:9;324:27;:::i;362:658::-;533:2;585:21;;;655:13;;558:18;;;677:22;;;504:4;;533:2;756:15;;;;730:2;715:18;;;504:4;799:195;813:6;810:1;807:13;799:195;;;878:13;;-1:-1:-1;;;;;874:39:14;862:52;;969:15;;;;934:12;;;;910:1;828:9;799:195;;;-1:-1:-1;1011:3:14;;362:658;-1:-1:-1;;;;;;362:658:14:o;1025:180::-;1084:6;1137:2;1125:9;1116:7;1112:23;1108:32;1105:52;;;1153:1;1150;1143:12;1105:52;-1:-1:-1;1176:23:14;;1025:180;-1:-1:-1;1025:180:14:o;1489:131::-;-1:-1:-1;;;;;1564:31:14;;1554:42;;1544:70;;1610:1;1607;1600:12;1625:388;1693:6;1701;1754:2;1742:9;1733:7;1729:23;1725:32;1722:52;;;1770:1;1767;1760:12;1722:52;1809:9;1796:23;1828:31;1853:5;1828:31;:::i;:::-;1878:5;-1:-1:-1;1935:2:14;1920:18;;1907:32;1948:33;1907:32;1948:33;:::i;:::-;2000:7;1990:17;;;1625:388;;;;;:::o;2207:456::-;2284:6;2292;2300;2353:2;2341:9;2332:7;2328:23;2324:32;2321:52;;;2369:1;2366;2359:12;2321:52;2408:9;2395:23;2427:31;2452:5;2427:31;:::i;:::-;2477:5;-1:-1:-1;2534:2:14;2519:18;;2506:32;2547:33;2506:32;2547:33;:::i;:::-;2207:456;;2599:7;;-1:-1:-1;;;2653:2:14;2638:18;;;;2625:32;;2207:456::o;3006:247::-;3065:6;3118:2;3106:9;3097:7;3093:23;3089:32;3086:52;;;3134:1;3131;3124:12;3086:52;3173:9;3160:23;3192:31;3217:5;3192:31;:::i;3466:632::-;3637:2;3689:21;;;3759:13;;3662:18;;;3781:22;;;3608:4;;3637:2;3860:15;;;;3834:2;3819:18;;;3608:4;3903:169;3917:6;3914:1;3911:13;3903:169;;;3978:13;;3966:26;;4047:15;;;;4012:12;;;;3939:1;3932:9;3903:169;;4103:458;4194:6;4202;4210;4218;4226;4279:3;4267:9;4258:7;4254:23;4250:33;4247:53;;;4296:1;4293;4286:12;4247:53;4319:27;4336:9;4319:27;:::i;:::-;4309:37;;4365:36;4397:2;4386:9;4382:18;4365:36;:::i;:::-;4103:458;;4355:46;;-1:-1:-1;;;;4448:2:14;4433:18;;4420:32;;4499:2;4484:18;;4471:32;;4550:3;4535:19;;;4522:33;;-1:-1:-1;4103:458:14:o;4748:320::-;4821:6;4829;4837;4890:2;4878:9;4869:7;4865:23;4861:32;4858:52;;;4906:1;4903;4896:12;4858:52;4929:27;4946:9;4929:27;:::i;:::-;4919:37;;4975:36;5007:2;4996:9;4992:18;4975:36;:::i;:::-;4965:46;;5058:2;5047:9;5043:18;5030:32;5020:42;;4748:320;;;;;:::o;5265:456::-;5342:6;5350;5358;5411:2;5399:9;5390:7;5386:23;5382:32;5379:52;;;5427:1;5424;5417:12;5379:52;5463:9;5450:23;5440:33;;5523:2;5512:9;5508:18;5495:32;5536:31;5561:5;5536:31;:::i;:::-;5586:5;-1:-1:-1;5643:2:14;5628:18;;5615:32;5656:33;5615:32;5656:33;:::i;:::-;5708:7;5698:17;;;5265:456;;;;;:::o;5726:127::-;5787:10;5782:3;5778:20;5775:1;5768:31;5818:4;5815:1;5808:15;5842:4;5839:1;5832:15;5858:127;5919:10;5914:3;5910:20;5907:1;5900:31;5950:4;5947:1;5940:15;5974:4;5971:1;5964:15;5990:127;6051:10;6046:3;6042:20;6039:1;6032:31;6082:4;6079:1;6072:15;6106:4;6103:1;6096:15;6122:151;6212:4;6205:12;;;6191;;;6187:31;;6230:14;;6227:40;;;6247:18;;:::i;6278:135::-;6317:3;6338:17;;;6335:43;;6358:18;;:::i;:::-;-1:-1:-1;6405:1:14;6394:13;;6278:135::o;6418:356::-;6620:2;6602:21;;;6639:18;;;6632:30;6698:34;6693:2;6678:18;;6671:62;6765:2;6750:18;;6418:356::o;7853:168::-;7926:9;;;7957;;7974:15;;;7968:22;;7954:37;7944:71;;7995:18;;:::i;8026:128::-;8093:9;;;8114:11;;;8111:37;;;8128:18;;:::i;9587:127::-;9648:10;9643:3;9639:20;9636:1;9629:31;9679:4;9676:1;9669:15;9703:4;9700:1;9693:15;9719:138;9798:13;;9820:31;9798:13;9820:31;:::i;9862:251::-;9932:6;9985:2;9973:9;9964:7;9960:23;9956:32;9953:52;;;10001:1;9998;9991:12;9953:52;10033:9;10027:16;10052:31;10077:5;10052:31;:::i;10118:1129::-;10213:6;10244:2;10287;10275:9;10266:7;10262:23;10258:32;10255:52;;;10303:1;10300;10293:12;10255:52;10336:9;10330:16;10365:18;10406:2;10398:6;10395:14;10392:34;;;10422:1;10419;10412:12;10392:34;10460:6;10449:9;10445:22;10435:32;;10505:7;10498:4;10494:2;10490:13;10486:27;10476:55;;10527:1;10524;10517:12;10476:55;10556:2;10550:9;10578:2;10574;10571:10;10568:36;;;10584:18;;:::i;:::-;10630:2;10627:1;10623:10;10662:2;10656:9;10725:2;10721:7;10716:2;10712;10708:11;10704:25;10696:6;10692:38;10780:6;10768:10;10765:22;10760:2;10748:10;10745:18;10742:46;10739:72;;;10791:18;;:::i;:::-;10827:2;10820:22;10877:18;;;10911:15;;;;-1:-1:-1;10953:11:14;;;10949:20;;;10981:19;;;10978:39;;;11013:1;11010;11003:12;10978:39;11037:11;;;;11057:159;11073:6;11068:3;11065:15;11057:159;;;11139:34;11169:3;11139:34;:::i;:::-;11127:47;;11090:12;;;;11194;;;;11057:159;;;11235:6;10118:1129;-1:-1:-1;;;;;;;;10118:1129:14:o;11252:277::-;11319:6;11372:2;11360:9;11351:7;11347:23;11343:32;11340:52;;;11388:1;11385;11378:12;11340:52;11420:9;11414:16;11473:5;11466:13;11459:21;11452:5;11449:32;11439:60;;11495:1;11492;11485:12;11945:225;12049:4;12028:12;;;12042;;;12024:31;12075:22;;;;12116:24;;;12106:58;;12144:18;;:::i;:::-;12106:58;11945:225;;;;:::o;12175:250::-;12260:1;12270:113;12284:6;12281:1;12278:13;12270:113;;;12360:11;;;12354:18;12341:11;;;12334:39;12306:2;12299:10;12270:113;;;-1:-1:-1;;12417:1:14;12399:16;;12392:27;12175:250::o;12430:287::-;12559:3;12597:6;12591:13;12613:66;12672:6;12667:3;12660:4;12652:6;12648:17;12613:66;:::i;:::-;12695:16;;;;;12430:287;-1:-1:-1;;12430:287:14:o;12722:184::-;12792:6;12845:2;12833:9;12824:7;12820:23;12816:32;12813:52;;;12861:1;12858;12851:12;12813:52;-1:-1:-1;12884:16:14;;12722:184;-1:-1:-1;12722:184:14:o;13106:668::-;-1:-1:-1;;;;;13497:32:14;;13479:51;;13466:3;13451:19;;13539:58;13593:2;13578:18;;13570:6;12993:12;;13007:4;12989:23;12977:36;;13066:4;13055:16;;;13049:23;-1:-1:-1;;;;;13045:49:14;13029:14;;13022:73;12911:190;13539:58;12993:12;;13007:4;12989:23;13660:2;13645:18;;12977:36;13066:4;13055:16;;;13049:23;-1:-1:-1;;;;;13045:49:14;13029:14;;;13022:73;13695:3;13680:19;;13673:35;;;;13752:14;13745:22;13739:3;13724:19;;;13717:51;13106:668;;-1:-1:-1;;13106:668:14:o;14269:586::-;-1:-1:-1;;;;;14638:32:14;;14620:51;;14607:3;14592:19;;14680:58;14734:2;14719:18;;14711:6;12993:12;;13007:4;12989:23;12977:36;;13066:4;13055:16;;;13049:23;-1:-1:-1;;;;;13045:49:14;13029:14;;13022:73;12911:190;14680:58;12993:12;;13007:4;12989:23;14801:2;14786:18;;12977:36;13066:4;13055:16;;;13049:23;-1:-1:-1;;;;;13045:49:14;13029:14;;;13022:73;14836:3;14821:19;14814:35;14269:586;;-1:-1:-1;;14269:586:14:o;15934:396::-;16083:2;16072:9;16065:21;16046:4;16115:6;16109:13;16158:6;16153:2;16142:9;16138:18;16131:34;16174:79;16246:6;16241:2;16230:9;16226:18;16221:2;16213:6;16209:15;16174:79;:::i;:::-;16314:2;16293:15;-1:-1:-1;;16289:29:14;16274:45;;;;16321:2;16270:54;;15934:396;-1:-1:-1;;15934:396:14:o
Swarm Source
ipfs://a20dd8a538f2931dec0e2eef157073d30e5f0ec670efe8c0a9eae66158114485
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.