Source Code
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 25 internal transactions (View All)
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 424782937 | 7 mins ago | 0.2 ETH | ||||
| 424775230 | 39 mins ago | 0.26681158 ETH | ||||
| 424775230 | 39 mins ago | 0.26681158 ETH | ||||
| 424775145 | 39 mins ago | 0.34179946 ETH | ||||
| 424775145 | 39 mins ago | 0.34179946 ETH | ||||
| 424772385 | 51 mins ago | 0.0696257 ETH | ||||
| 424772385 | 51 mins ago | 0.0696257 ETH | ||||
| 424764932 | 1 hr ago | 0.00106452 ETH | ||||
| 424764932 | 1 hr ago | 0.00106452 ETH | ||||
| 424735821 | 3 hrs ago | 0.00069063 ETH | ||||
| 424735821 | 3 hrs ago | 0.00069063 ETH | ||||
| 424722191 | 4 hrs ago | 0.7 ETH | ||||
| 424712571 | 5 hrs ago | 0.00024646 ETH | ||||
| 424712571 | 5 hrs ago | 0.00024646 ETH | ||||
| 424709618 | 5 hrs ago | 0.00742257 ETH | ||||
| 424709618 | 5 hrs ago | 0.00742257 ETH | ||||
| 424701551 | 5 hrs ago | 0.0001285 ETH | ||||
| 424701551 | 5 hrs ago | 0.0001285 ETH | ||||
| 424689048 | 6 hrs ago | 0.01245319 ETH | ||||
| 424689048 | 6 hrs ago | 0.01245319 ETH | ||||
| 424666415 | 8 hrs ago | 0.01296114 ETH | ||||
| 424666415 | 8 hrs ago | 0.01296114 ETH | ||||
| 424657555 | 8 hrs ago | 0.00188026 ETH | ||||
| 424657555 | 8 hrs ago | 0.00188026 ETH | ||||
| 424650634 | 9 hrs ago | 0.0018 ETH |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
CamelotYakRouter
Compiler Version
v0.8.30+commit.73712a01
Optimization Enabled:
Yes with 1000000 runs
Other Settings:
prague EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// ╟╗ ╔╬
// ╞╬╬ ╬╠╬
// ╔╣╬╬╬ ╠╠╠╠╦
// ╬╬╬╬╬╩ ╘╠╠╠╠╬
// ║╬╬╬╬╬ ╘╠╠╠╠╬
// ╣╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬ ╒╬╬╬╬╬╬╬╜ ╠╠╬╬╬╬╬╬╬ ╠╬╬╬╬╬╬╬ ╬╬╬╬╬╬╬╬╠╠╠╠╠╠╠╠
// ╙╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╕ ╬╬╬╬╬╬╬╜ ╣╠╠╬╬╬╬╬╬╬╬ ╠╬╬╬╬╬╬╬ ╬╬╬╬╬╬╬╬╬╠╠╠╠╠╠╠╩
// ╙╣╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬ ╔╬╬╬╬╬╬╬ ╔╠╠╠╬╬╬╬╬╬╬╬ ╠╬╬╬╬╬╬╬ ╣╬╬╬╬╬╬╬╬╬╬╬╠╠╠╠╝╙
// ╘╣╬╬╬╬╬╬╬╬╬╬╬╬╬╬ ╒╠╠╠╬╠╬╩╬╬╬╬╬╬ ╠╬╬╬╬╬╬╬╣╬╬╬╬╬╬╬╙
// ╣╬╬╬╬╬╬╬╬╬╬╠╣ ╣╬╠╠╠╬╩ ╚╬╬╬╬╬╬ ╠╬╬╬╬╬╬╬╬╬╬╬╬╬╬
// ╣╬╬╬╬╬╬╬╬╬╣ ╣╬╠╠╠╬╬ ╣╬╬╬╬╬╬ ╠╬╬╬╬╬╬╬╬╬╬╬╬╬╬
// ╟╬╬╬╬╬╬╬╩ ╬╬╠╠╠╠╬╬╬╬╬╬╬╬╬╬╬ ╠╬╬╬╬╬╬╬╠╬╬╬╬╬╬╬
// ╬╬╬╬╬╬╬ ╒╬╬╠╠╬╠╠╬╬╬╬╬╬╬╬╬╬╬╬ ╠╬╬╬╬╬╬╬ ╣╬╬╬╬╬╬╬
// ╬╬╬╬╬╬╬ ╬╬╬╠╠╠╠╝╝╝╝╝╝╝╠╬╬╬╬╬╬ ╠╬╬╬╬╬╬╬ ╚╬╬╬╬╬╬╬╬
// ╬╬╬╬╬╬╬ ╣╬╬╬╬╠╠╩ ╘╬╬╬╬╬╬╬ ╠╬╬╬╬╬╬╬ ╙╬╬╬╬╬╬╬╬
//
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity 0.8.30;
pragma experimental ABIEncoderV2;
import {IYakRouter, Offer, Query, FormattedOffer, Trade} from "contracts/interface/IYakRouter.sol";
import {IAdapter} from "contracts/interface/IAdapter.sol";
import {IAlgebraV2Adapter} from "contracts/interface/IAlgebraV2Adapter.sol";
import {IERC20} from "contracts/interface/IERC20.sol";
import {IWETH} from "contracts/interface/IWETH.sol";
import {SafeERC20} from "contracts/lib/SafeERC20.sol";
import {OfferUtils} from "contracts/lib/YakViewUtils.sol";
import {Recoverable} from "contracts/lib/Recoverable.sol";
import {SafeERC20} from "contracts/lib/SafeERC20.sol";
/**
* @title CamelotYakRouter
* @notice Main router contract for finding optimal swap paths and executing trades
* @dev Inherits from Maintainable for access control and Recoverable for token recovery
*/
contract CamelotYakRouter is Recoverable, IYakRouter {
using SafeERC20 for IERC20;
using OfferUtils for Offer;
/// @notice Fee denominator for basis point calculations (10000 = 100%)
uint256 public constant FEE_DENOMINATOR = 1e4;
/// @notice Storage slot length in bytes
uint256 public constant SLOT_LENGTH = 32;
/// @notice Address representing native currency (ETH)
address public constant NATIVE = address(0);
/// @notice Name of this router implementation
string public constant NAME = "CamelotYakRouter";
/// @notice Wrapped native token address (WETH)
address public immutable WNATIVE;
/// @notice Minimum fee in basis points
uint256 public MIN_FEE = 0;
/// @notice Address that receives protocol fees
address public FEE_CLAIMER;
/// @notice Array of trusted intermediate tokens for multi-hop swaps
address[] public TRUSTED_TOKENS;
/// @notice Array of DEX adapter contracts
address[] public ADAPTERS;
/**
* @notice Ensures transaction is executed before deadline
* @param _deadline Unix timestamp deadline
*/
modifier withDeadline(uint256 _deadline) {
if (_deadline < block.timestamp) revert DeadlinePassed(_deadline, block.timestamp);
_;
}
/**
* @notice Initializes the router with adapters and configuration
* @param _adapters Initial array of adapter addresses
* @param _trustedTokens Initial array of trusted token addresses
* @param _feeClaimer Address to receive fees
* @param _wrapped_native Address of wrapped native token (WETH)
*/
constructor(
address[] memory _adapters,
address[] memory _trustedTokens,
address _feeClaimer,
address _wrapped_native
) {
if (_feeClaimer == address(0) || _wrapped_native == address(0)) revert AddressZero();
setTrustedTokens(_trustedTokens);
setFeeClaimer(_feeClaimer);
setAdapters(_adapters);
WNATIVE = _wrapped_native;
}
// -- SETTERS --
/// @inheritdoc IYakRouter
function setTrustedTokens(address[] memory _trustedTokens) public override onlyMaintainer {
TRUSTED_TOKENS = _trustedTokens;
emit UpdatedTrustedTokens(_trustedTokens);
}
/// @inheritdoc IYakRouter
function setAdapters(address[] memory _adapters) public override onlyMaintainer {
ADAPTERS = _adapters;
emit UpdatedAdapters(_adapters);
}
/// @inheritdoc IYakRouter
function setMinFee(uint256 _fee) external override onlyMaintainer {
if (_fee > FEE_DENOMINATOR / 10) revert FeeAboveMaximum(_fee, FEE_DENOMINATOR / 10);
uint256 oldMinFee = MIN_FEE;
MIN_FEE = _fee;
emit UpdatedMinFee(oldMinFee, _fee);
}
/// @inheritdoc IYakRouter
function setFeeClaimer(address _claimer) public override onlyMaintainer {
if (_claimer == address(0)) revert AddressZero();
address oldClaimer = FEE_CLAIMER;
FEE_CLAIMER = _claimer;
emit UpdatedFeeClaimer(oldClaimer, FEE_CLAIMER);
}
// -- GENERAL --
/// @inheritdoc IYakRouter
function trustedTokensCount() external view override returns (uint256) {
return TRUSTED_TOKENS.length;
}
/// @inheritdoc IYakRouter
function adaptersCount() external view override returns (uint256) {
return ADAPTERS.length;
}
/**
* @notice Fallback function to receive ETH
*/
receive() external payable {}
// -- HELPERS --
/**
* @notice Applies fee deduction to input amount
* @param _amountIn Input amount before fees
* @param _fee Fee in basis points
* @return Amount after fee deduction
*/
function _applyFee(uint256 _amountIn, uint256 _fee) internal view returns (uint256) {
if (_fee < MIN_FEE) revert InsufficientFee(_fee, MIN_FEE);
return (_amountIn * (FEE_DENOMINATOR - _fee)) / FEE_DENOMINATOR;
}
/**
* @notice Wraps native currency to WETH
* @param _amount Amount of native currency to wrap
*/
function _wrap(uint256 _amount) internal {
IWETH(WNATIVE).deposit{value: _amount}();
}
/**
* @notice Unwraps WETH to native currency
* @param _amount Amount of WETH to unwrap
*/
function _unwrap(uint256 _amount) internal {
IWETH(WNATIVE).withdraw(_amount);
}
/**
* @notice Returns tokens to specified address
* @param _token Token address (use address(0) for ETH)
* @param _amount Amount to transfer
* @param _to Recipient address
* @dev Handles both ERC20 tokens and native ETH transfers
*/
function _returnTokensTo(address _token, uint256 _amount, address _to) internal {
if (address(this) != _to) {
if (_token == NATIVE) {
(bool success,) = payable(_to).call{value: _amount}("");
if (!success) revert ETHTransferFailed();
} else {
IERC20(_token).safeTransfer(_to, _amount);
}
}
}
/**
* @notice Transfers tokens from source to destination
* @param token Token address to transfer
* @param _from Source address
* @param _to Destination address
* @param _amount Amount to transfer
* @dev Uses transferFrom if source is not this contract
*/
function _transferFrom(address token, address _from, address _to, uint256 _amount) internal {
if (_from != address(this)) IERC20(token).safeTransferFrom(_from, _to, _amount);
else IERC20(token).safeTransfer(_to, _amount);
}
// -- QUERIES --
/// @inheritdoc IYakRouter
function queryAdapter(
uint256 _amount,
address _tokenIn,
address _tokenOut,
uint8 _index,
bool _exactIn
) external view override returns (uint256, address) {
IAdapter _adapter = IAdapter(ADAPTERS[_index]);
try IAdapter(_adapter).query(_amount, _tokenIn, _tokenOut, _exactIn) returns (
uint256 quoteAmount, address _recipient
) {
return (quoteAmount, _recipient);
} catch {
return (0, address(0));
}
}
/// @inheritdoc IYakRouter
function queryNoSplit(
uint256 _amount,
address _tokenIn,
address _tokenOut,
uint8[] calldata _options,
bool _exactIn
) public view override returns (Query memory) {
Query memory bestQuery;
for (uint8 i; i < _options.length; ++i) {
address _adapter = ADAPTERS[_options[i]];
try IAdapter(_adapter).query(_amount, _tokenIn, _tokenOut, _exactIn) returns (
uint256 quoteAmount, address _recipient
) {
if (
i == 0 || _exactIn
? quoteAmount > bestQuery.amount
: (
quoteAmount != 0
&& (bestQuery.amount == 0 || quoteAmount < bestQuery.amount)
)
) bestQuery = Query(_adapter, _recipient, _tokenIn, _tokenOut, quoteAmount);
} catch {
continue;
}
}
return bestQuery;
}
/// @inheritdoc IYakRouter
function queryNoSplit(uint256 _amount, address _tokenIn, address _tokenOut, bool _exactIn)
public
view
override
returns (Query memory)
{
(Query memory bestQuery,) =
_queryNoSplitWithDeployer(_amount, _tokenIn, _tokenOut, _exactIn);
return bestQuery;
}
/**
* @notice Internal function to query adapters and return deployer info
* @param _amount Amount to swap
* @param _tokenIn Input token address
* @param _tokenOut Output token address
* @param _exactIn True for exact input, false for exact output
* @return bestQuery Best query result
* @return bestDeployer Deployer address for AlgebraV2 custom pools
*/
function _queryNoSplitWithDeployer(
uint256 _amount,
address _tokenIn,
address _tokenOut,
bool _exactIn
) internal view returns (Query memory bestQuery, address bestDeployer) {
uint256 length = ADAPTERS.length;
for (uint8 i; i < length; ++i) {
address _adapter = ADAPTERS[i];
// Try to get quote with deployer info from AlgebraV2Adapter
try IAlgebraV2Adapter(_adapter).queryWithDeployer(
_amount, _tokenIn, _tokenOut, _exactIn
) returns (uint256 quoteAmount, address _recipient, address deployer) {
if (
i == 0 || _exactIn
? quoteAmount > bestQuery.amount
: (
quoteAmount != 0
&& (bestQuery.amount == 0 || quoteAmount < bestQuery.amount)
)
) {
bestQuery = Query(_adapter, _recipient, _tokenIn, _tokenOut, quoteAmount);
bestDeployer = deployer;
}
continue;
} catch {}
// Fallback to regular query for other adapters
try IAdapter(_adapter).query(_amount, _tokenIn, _tokenOut, _exactIn) returns (
uint256 quoteAmount, address _recipient
) {
if (
i == 0 || _exactIn
? quoteAmount > bestQuery.amount
: (
quoteAmount != 0
&& (bestQuery.amount == 0 || quoteAmount < bestQuery.amount)
)
) {
bestQuery = Query(_adapter, _recipient, _tokenIn, _tokenOut, quoteAmount);
bestDeployer = address(0);
}
} catch {
continue;
}
}
return (bestQuery, bestDeployer);
}
/// @inheritdoc IYakRouter
function findBestPath(
uint256 _amount,
address _tokenIn,
address _tokenOut,
address[] memory _trustedTokens,
uint256 _maxSteps,
bool _exactIn
) external view override returns (FormattedOffer memory) {
if (_maxSteps == 0 || _maxSteps >= 5) revert InvalidMaxSteps(_maxSteps);
Offer memory queries = OfferUtils.newOffer(_amount, _exactIn ? _tokenIn : _tokenOut);
uint256 ttLength = TRUSTED_TOKENS.length;
// Concatenate default and additional trusted tokens
address[] memory _allTrustedTokens = new address[](ttLength + _trustedTokens.length);
for (uint256 i; i < ttLength; ++i) {
_allTrustedTokens[i] = TRUSTED_TOKENS[i];
}
for (uint256 i; i < _trustedTokens.length; ++i) {
_allTrustedTokens[ttLength + i] = _trustedTokens[i];
}
// Initialize empty array to track used pools
bytes32[] memory usedPools = new bytes32[](0);
queries = _findBestPath(
_amount, _tokenIn, _tokenOut, _allTrustedTokens, _maxSteps, queries, _exactIn, usedPools
);
// If no paths are found return empty struct
if (queries.adapters.length == 0) {
queries.amounts = "";
queries.path = "";
}
return queries.format();
}
/**
* @notice Internal recursive function to find optimal swap path
* @param _amount Amount to swap
* @param _tokenIn Input token address
* @param _tokenOut Output token address
* @param _trustedTokens Array of intermediate tokens to consider
* @param _maxSteps Maximum hops allowed
* @param _queries Current path being built
* @param _exactIn True for exact input, false for exact output
* @param _usedPools Array of pool hashes already used in the path
* @return Optimal swap path offer
* @dev Recursively explores paths through trusted tokens, avoiding duplicate pools
*/
function _findBestPath(
uint256 _amount,
address _tokenIn,
address _tokenOut,
address[] memory _trustedTokens,
uint256 _maxSteps,
Offer memory _queries,
bool _exactIn,
bytes32[] memory _usedPools
) internal view returns (Offer memory) {
Offer memory bestOption = _queries.clone();
uint256 bestAmount;
// First check if there is a path directly from tokenIn to tokenOut
(Query memory queryDirect, address deployer) =
_queryNoSplitWithDeployer(_amount, _tokenIn, _tokenOut, _exactIn);
if (queryDirect.amount > 0) {
// Check if this pool has already been used
bytes32 poolHash = _getPoolHash(queryDirect.adapter, _tokenIn, _tokenOut, deployer);
if (!_isPoolUsed(poolHash, _usedPools)) {
if (_exactIn) {
bestOption.addToTail(
queryDirect.amount,
queryDirect.adapter,
queryDirect.recipient,
queryDirect.tokenOut,
deployer
);
} else {
// For exactOut: when adding to head, we add the input token since path goes
// tokenIn
// -> tokenOut
bestOption.addToHead(
queryDirect.amount,
queryDirect.adapter,
queryDirect.recipient,
queryDirect.tokenIn,
deployer
);
}
bestAmount = queryDirect.amount;
}
}
// Only check the rest if they would go beyond step limit (Need at least 2 more steps)
if (_maxSteps > 1 && _queries.adapters.length / SLOT_LENGTH <= _maxSteps - 2) {
// Check for paths that pass through trusted tokens
for (uint256 i; i < _trustedTokens.length; ++i) {
if (_exactIn ? (_tokenIn == _trustedTokens[i]) : (_tokenOut == _trustedTokens[i])) {
continue;
}
Query memory bestSwap;
uint256 swapAmount;
address swapDeployer;
if (_exactIn) {
// For exactIn: find swap from tokenIn to trusted token
(bestSwap, swapDeployer) =
_queryNoSplitWithDeployer(_amount, _tokenIn, _trustedTokens[i], _exactIn);
swapAmount = bestSwap.amount;
} else {
// For exactOut: find swap from trusted token to tokenOut
(bestSwap, swapDeployer) =
_queryNoSplitWithDeployer(_amount, _trustedTokens[i], _tokenOut, _exactIn);
swapAmount = bestSwap.amount;
}
if (swapAmount == 0) continue;
// Check if this pool has already been used
bytes32 poolHash;
if (_exactIn) {
poolHash =
_getPoolHash(bestSwap.adapter, _tokenIn, _trustedTokens[i], swapDeployer);
} else {
poolHash =
_getPoolHash(bestSwap.adapter, _trustedTokens[i], _tokenOut, swapDeployer);
}
if (_isPoolUsed(poolHash, _usedPools)) continue;
// Explore options that connect the current path
Offer memory newOffer = _queries.clone();
// Add this pool to the used pools for the recursive call
bytes32[] memory newUsedPools = _addUsedPool(poolHash, _usedPools);
if (_exactIn) {
// For exactIn: add first hop to tail, then recurse forward
newOffer.addToTail(
swapAmount,
bestSwap.adapter,
bestSwap.recipient,
bestSwap.tokenOut,
swapDeployer
);
newOffer = _findBestPath(
swapAmount,
_trustedTokens[i],
_tokenOut,
_trustedTokens,
_maxSteps,
newOffer,
_exactIn,
newUsedPools
);
} else {
// For exactOut: add last hop to head, then recurse backward
// When building exactOut path, we need to add the tokenIn from the perspective
// of the swap direction (trustedToken -> tokenOut means trustedToken is
// tokenIn)
newOffer.addToHead(
swapAmount,
bestSwap.adapter,
bestSwap.recipient,
bestSwap.tokenIn,
swapDeployer
);
newOffer = _findBestPath(
swapAmount,
_tokenIn,
_trustedTokens[i],
_trustedTokens,
_maxSteps,
newOffer,
_exactIn,
newUsedPools
);
}
bool validPath = _exactIn
? (_tokenOut == newOffer.getTokenOut())
: (_tokenIn == newOffer.getTokenIn());
if (validPath) {
uint256 pathAmount = _exactIn
? newOffer.getAmountOut() // Final output amount
: newOffer.getAmountIn(); // First input amount
bool isBetter = (bestAmount == 0)
|| (_exactIn ? pathAmount > bestAmount : pathAmount < bestAmount);
if (isBetter) {
bestAmount = pathAmount;
bestOption = newOffer;
}
}
}
}
return bestOption;
}
/**
* @notice Generates a unique hash for a pool based on adapter, tokens, and deployer
* @param _adapter Address of the adapter
* @param _tokenA First token in the pair
* @param _tokenB Second token in the pair
* @param _deployer Deployer address (address(0) for default pools)
* @return Hash identifying the pool uniquely
*/
function _getPoolHash(address _adapter, address _tokenA, address _tokenB, address _deployer)
internal
pure
returns (bytes32)
{
// Sort tokens to ensure consistent hashing regardless of order
(address token0, address token1) =
_tokenA < _tokenB ? (_tokenA, _tokenB) : (_tokenB, _tokenA);
return keccak256(abi.encodePacked(_adapter, token0, token1, _deployer));
}
/**
* @notice Checks if a pool hash exists in the used pools array
* @param _poolHash Hash of the pool to check
* @param _usedPools Array of already used pool hashes
* @return True if the pool has been used, false otherwise
*/
function _isPoolUsed(bytes32 _poolHash, bytes32[] memory _usedPools)
internal
pure
returns (bool)
{
for (uint256 i = 0; i < _usedPools.length; i++) {
if (_usedPools[i] == _poolHash) return true;
}
return false;
}
/**
* @notice Adds a pool hash to the used pools array
* @param _poolHash Hash of the pool to add
* @param _usedPools Current array of used pools
* @return New array with the pool hash added
*/
function _addUsedPool(bytes32 _poolHash, bytes32[] memory _usedPools)
internal
pure
returns (bytes32[] memory)
{
bytes32[] memory newUsedPools = new bytes32[](_usedPools.length + 1);
for (uint256 i = 0; i < _usedPools.length; i++) {
newUsedPools[i] = _usedPools[i];
}
newUsedPools[_usedPools.length] = _poolHash;
return newUsedPools;
}
// -- SWAPPERS --
/**
* @notice Internal function that executes the swap
* @param _trade Trade parameters
* @param _from Address tokens are swapped from
* @param _fee Fee amount in basis points
* @param _to Address to receive output tokens
* @return amountOut Final output amount
* @dev Handles fee collection and multi-hop execution
*/
function _swapNoSplit(Trade calldata _trade, address _from, uint256 _fee, address _to)
internal
returns (uint256)
{
if (
(_trade.path.length - 1 != _trade.adapters.length)
|| (_trade.recipients.length != _trade.adapters.length)
|| (_trade.deployers.length > 0 && _trade.deployers.length != _trade.adapters.length)
) revert TradeLengthDoesNotMatch();
uint256 amountIn = _trade.amountIn;
if (_fee > 0 || MIN_FEE > 0) {
// Transfer fees to the claimer account and decrease initial amount
amountIn = _applyFee(_trade.amountIn, _fee);
_transferFrom(_trade.path[0], _from, FEE_CLAIMER, _trade.amountIn - amountIn);
}
uint256 recipientBalanceBefore = IERC20(_trade.path[0]).balanceOf(_trade.recipients[0]);
_transferFrom(_trade.path[0], _from, _trade.recipients[0], amountIn);
amountIn = IERC20(_trade.path[0]).balanceOf(_trade.recipients[0]) - recipientBalanceBefore;
address tokenOut = _trade.path[_trade.path.length - 1];
uint256 length = _trade.adapters.length;
for (uint256 i; i < length; ++i) {
// All adapters should transfer output token to the following target
// All targets are the adapters, expect for the last swap where tokens are sent out
address targetAddress = i < length - 1 ? _trade.recipients[i + 1] : _to;
recipientBalanceBefore = IERC20(_trade.path[i + 1]).balanceOf(targetAddress);
// Check if we have a deployer for this step (for AlgebraV2Adapter custom pools)
if (_trade.deployers.length > 0 && _trade.deployers[i] != address(0)) {
// Try to call the overloaded swap function with deployer parameter
// (AlgebraV2Adapter)
try IAlgebraV2Adapter(_trade.adapters[i]).swap(
amountIn,
0,
_trade.path[i],
_trade.path[i + 1],
targetAddress,
_trade.deployers[i]
) {} catch {
// If the adapter doesn't support the deployer parameter, fall back to regular
// swap
IAdapter(_trade.adapters[i]).swap(
amountIn, 0, _trade.path[i], _trade.path[i + 1], targetAddress
);
}
} else {
// Regular swap without deployer
IAdapter(_trade.adapters[i]).swap(
amountIn, 0, _trade.path[i], _trade.path[i + 1], targetAddress
);
}
amountIn = IERC20(_trade.path[i + 1]).balanceOf(targetAddress) - recipientBalanceBefore;
}
uint256 amountOut = amountIn;
if (amountOut < _trade.amountOut) {
revert InsufficientOutputAmount(amountOut, _trade.amountOut);
}
emit YakSwap(_trade.path[0], tokenOut, _trade.amountIn, amountOut);
return amountOut;
}
/// @inheritdoc IYakRouter
function swapNoSplit(Trade calldata _trade, uint256 _fee, uint256 _deadline, address _to)
public
override
withDeadline(_deadline)
{
_swapNoSplit(_trade, msg.sender, _fee, _to);
}
/// @inheritdoc IYakRouter
function swapNoSplitFromETH(Trade calldata _trade, uint256 _fee, uint256 _deadline, address _to)
external
payable
override
withDeadline(_deadline)
{
if (msg.value != _trade.amountIn) revert IncorrectETHAmount(msg.value, _trade.amountIn);
if (_trade.path[0] != WNATIVE) revert PathDoesNotBeginWithWETH(_trade.path[0]);
_wrap(_trade.amountIn);
_swapNoSplit(_trade, address(this), _fee, _to);
}
/// @inheritdoc IYakRouter
function swapNoSplitToETH(Trade calldata _trade, uint256 _fee, uint256 _deadline, address _to)
public
override
withDeadline(_deadline)
{
if (_trade.path[_trade.path.length - 1] != WNATIVE) {
revert PathDoesNotEndWithWETH(_trade.path[_trade.path.length - 1]);
}
uint256 returnAmount = _swapNoSplit(_trade, msg.sender, _fee, address(this));
_unwrap(returnAmount);
_returnTokensTo(NATIVE, returnAmount, _to);
}
/// @inheritdoc IYakRouter
function swapNoSplitWithPermit(
Trade calldata _trade,
uint256 _fee,
uint256 _deadline,
address _to,
uint8 _v,
bytes32 _r,
bytes32 _s
) external override {
try IERC20(_trade.path[0]).permit(
msg.sender, address(this), _trade.amountIn, _deadline, _v, _r, _s
) {
swapNoSplit(_trade, _fee, _deadline, _to);
} catch {
swapNoSplit(_trade, _fee, _deadline, _to);
}
}
/// @inheritdoc IYakRouter
function swapNoSplitToETHWithPermit(
Trade calldata _trade,
uint256 _fee,
uint256 _deadline,
address _to,
uint8 _v,
bytes32 _r,
bytes32 _s
) external override {
try IERC20(_trade.path[0]).permit(
msg.sender, address(this), _trade.amountIn, _deadline, _v, _r, _s
) {
swapNoSplitToETH(_trade, _fee, _deadline, _to);
} catch {
swapNoSplitToETH(_trade, _fee, _deadline, _to);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/AccessControl.sol)
pragma solidity ^0.8.0;
import "./IAccessControl.sol";
import "../utils/Context.sol";
import "../utils/Strings.sol";
import "../utils/introspection/ERC165.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```solidity
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```solidity
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
* to enforce additional security measures for this role.
*/
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address => bool) members;
bytes32 adminRole;
}
mapping(bytes32 => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with a standardized message including the required role.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*
* _Available since v4.1._
*/
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view virtual override returns (bool) {
return _roles[role].members[account];
}
/**
* @dev Revert with a standard message if `_msgSender()` is missing `role`.
* Overriding this function changes the behavior of the {onlyRole} modifier.
*
* Format of the revert message is described in {_checkRole}.
*
* _Available since v4.6._
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Revert with a standard message if `account` is missing `role`.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert(
string(
abi.encodePacked(
"AccessControl: account ",
Strings.toHexString(account),
" is missing role ",
Strings.toHexString(uint256(role), 32)
)
)
);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {
return _roles[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleGranted} event.
*/
function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleRevoked} event.
*/
function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*
* May emit a {RoleRevoked} event.
*/
function renounceRole(bytes32 role, address account) public virtual override {
require(account == _msgSender(), "AccessControl: can only renounce roles for self");
_revokeRole(role, account);
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event. Note that unlike {grantRole}, this function doesn't perform any
* checks on the calling account.
*
* May emit a {RoleGranted} event.
*
* [WARNING]
* ====
* This function should only be called from the constructor when setting
* up the initial roles for the system.
*
* Using this function in any other way is effectively circumventing the admin
* system imposed by {AccessControl}.
* ====
*
* NOTE: This function is deprecated in favor of {_grantRole}.
*/
function _setupRole(bytes32 role, address account) internal virtual {
_grantRole(role, account);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Grants `role` to `account`.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/
function _grantRole(bytes32 role, address account) internal virtual {
if (!hasRole(role, account)) {
_roles[role].members[account] = true;
emit RoleGranted(role, account, _msgSender());
}
}
/**
* @dev Revokes `role` from `account`.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/
function _revokeRole(bytes32 role, address account) internal virtual {
if (hasRole(role, account)) {
_roles[role].members[account] = false;
emit RoleRevoked(role, account, _msgSender());
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)
pragma solidity ^0.8.0;
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControl {
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*
* _Available since v3.1._
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*/
function renounceRole(bytes32 role, address account) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (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;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1, "Math: mulDiv overflow");
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMath {
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// must be unchecked in order to support `n = type(int256).min`
return uint256(n >= 0 ? n : -n);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)
pragma solidity ^0.8.0;
import "./math/Math.sol";
import "./math/SignedMath.sol";
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toString(int256 value) internal pure returns (string memory) {
return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value))));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return keccak256(bytes(a)) == keccak256(bytes(b));
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title IAdapter
* @author Yak Exchange
* @notice Interface for DEX adapter contracts that integrate various AMMs
* @dev Each adapter implements swap functionality for a specific DEX protocol
*/
interface IAdapter {
/**
* @notice Returns the name of the adapter
* @return name The adapter's descriptive name (e.g., "UniswapV2Adapter")
*/
function name() external view returns (string memory);
/**
* @notice Executes a token swap through the adapter's underlying DEX
* @param _amountIn Amount of input tokens to swap
* @param _amountOut Minimum amount of output tokens expected
* @param _fromToken Address of the input token
* @param _toToken Address of the output token
* @param _to Address that will receive the output tokens
* @dev Adapter must ensure _to receives at least _amountOut tokens
*/
function swap(uint256 _amountIn, uint256 _amountOut, address _fromToken, address _toToken, address _to) external;
/**
* @notice Queries the adapter for expected swap output/input amount
* @param _amount Input amount (if exactIn) or output amount (if !exactIn)
* @param _tokenIn Address of the input token
* @param _tokenOut Address of the output token
* @param _exactIn True for exact input quote, false for exact output quote
* @return amountOut The output amount (if exactIn) or required input amount (if !exactIn)
* @return recipient The address that should receive tokens for this adapter
* @dev Should return (0, address(0)) if swap is not available
*/
function query(uint256 _amount, address _tokenIn, address _tokenOut, bool _exactIn)
external
view
returns (uint256 amountOut, address recipient);
}// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
interface IAlgebraV2Adapter {
/// @dev Output amount is lower than expected amount out
error InsufficientAmount();
/// @dev Thrown when the caller is not the pool address
error NotPoolAddress();
/// @dev Event emitted when the quoter is set
event QuoterSet(address quoter);
/// @dev Event emitted when an invalid quoter gas limit is set
error InvalidGasLimit();
/// @dev Event emitted when the quoter gas limit is updated
event QuoterGasLimitSet(uint256 newGasLimit);
/// @dev Parameters struct for a quote
struct QParams {
address tokenIn;
address tokenOut;
int256 amount;
bool exactIn;
}
/// @notice Returns an address for a given key and index combination
/// @param key The keccak256 key generated by encoding tokenA and tokenB
/// @param index The index of the array to retrieve the address from
function deployers(bytes32 key, uint256 index) external view returns (address);
/// @notice Returns list of whitelisted deployers for a given tokenA/tokenB combination
/// @param key Keccack256 hash of tokenA and tokenB encoded addresses
function getDeployers(bytes32 key) external view returns (address[] memory);
/// @notice Whitelists a custom deployer for a given tokenA and tokenB combination
/// @param deployer Address of deployer of pool
/// @param tokenA The address of tokenA
/// @param tokenB The address of tokenB
function addCustomDeployer(address deployer, address tokenA, address tokenB) external;
/// @notice Removes a whitelisted custom deployer for a given tokenA and tokenB combination
/// @param tokenA The address of tokenA
/// @param tokenB The address of tokenB
/// @param index Index in the list of whitelisted deployers for the given pool
function removeCustomDeployer(address tokenA, address tokenB, uint256 index) external;
/// @notice Swaps tokens using a specific deployer's pool
/// @param amountIn Amount of input tokens
/// @param amountOut Minimum amount of output tokens expected
/// @param tokenIn Address of input token
/// @param tokenOut Address of output token
/// @param to Address to receive output tokens
/// @param deployer Address of the deployer for custom pool (address(0) for factory pool)
function swap(
uint256 amountIn,
uint256 amountOut,
address tokenIn,
address tokenOut,
address to,
address deployer
) external;
/// @notice Queries the adapter for swap quote and returns the deployer info
/// @param amount Input amount (if exactIn) or output amount (if !exactIn)
/// @param tokenIn Address of the input token
/// @param tokenOut Address of the output token
/// @param exactIn True for exact input quote, false for exact output quote
/// @return quoteAmount The output amount (if exactIn) or required input amount (if !exactIn)
/// @return recipient The address that should receive tokens for this adapter
/// @return deployer The deployer address for custom pool (address(0) for factory pool)
function queryWithDeployer(uint256 amount, address tokenIn, address tokenOut, bool exactIn)
external
view
returns (uint256 quoteAmount, address recipient, address deployer);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IERC20 {
event Approval(address, address, uint256);
event Transfer(address, address, uint256);
function name() external view returns (string memory);
function decimals() external view returns (uint8);
function transferFrom(
address,
address,
uint256
) external returns (bool);
function allowance(address, address) external view returns (uint256);
function approve(address, uint256) external returns (bool);
function transfer(address, uint256) external returns (bool);
function balanceOf(address) external view returns (uint256);
function nonces(address) external view returns (uint256); // Only tokens that support permit
function permit(
address,
address,
uint256,
uint256,
uint8,
bytes32,
bytes32
) external; // Only tokens that support permit
function swap(address, uint256) external; // Only Avalanche bridge tokens
function swapSupply(address) external view returns (uint256); // Only Avalanche bridge tokens
function totalSupply() external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IERC20} from "contracts/interface/IERC20.sol";
interface IWETH is IERC20 {
function withdraw(uint256 amount) external;
function deposit() external payable;
}// ╟╗ ╔╬
// ╞╬╬ ╬╠╬
// ╔╣╬╬╬ ╠╠╠╠╦
// ╬╬╬╬╬╩ ╘╠╠╠╠╬
// ║╬╬╬╬╬ ╘╠╠╠╠╬
// ╣╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬ ╒╬╬╬╬╬╬╬╜ ╠╠╬╬╬╬╬╬╬ ╠╬╬╬╬╬╬╬ ╬╬╬╬╬╬╬╬╠╠╠╠╠╠╠╠
// ╙╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╕ ╬╬╬╬╬╬╬╜ ╣╠╠╬╬╬╬╬╬╬╬ ╠╬╬╬╬╬╬╬ ╬╬╬╬╬╬╬╬╬╠╠╠╠╠╠╠╩
// ╙╣╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬ ╔╬╬╬╬╬╬╬ ╔╠╠╠╬╬╬╬╬╬╬╬ ╠╬╬╬╬╬╬╬ ╣╬╬╬╬╬╬╬╬╬╬╬╠╠╠╠╝╙
// ╘╣╬╬╬╬╬╬╬╬╬╬╬╬╬╬ ╒╠╠╠╬╠╬╩╬╬╬╬╬╬ ╠╬╬╬╬╬╬╬╣╬╬╬╬╬╬╬╙
// ╣╬╬╬╬╬╬╬╬╬╬╠╣ ╣╬╠╠╠╬╩ ╚╬╬╬╬╬╬ ╠╬╬╬╬╬╬╬╬╬╬╬╬╬╬
// ╣╬╬╬╬╬╬╬╬╬╣ ╣╬╠╠╠╬╬ ╣╬╬╬╬╬╬ ╠╬╬╬╬╬╬╬╬╬╬╬╬╬╬
// ╟╬╬╬╬╬╬╬╩ ╬╬╠╠╠╠╬╬╬╬╬╬╬╬╬╬╬ ╠╬╬╬╬╬╬╬╠╬╬╬╬╬╬╬
// ╬╬╬╬╬╬╬ ╒╬╬╠╠╬╠╠╬╬╬╬╬╬╬╬╬╬╬╬ ╠╬╬╬╬╬╬╬ ╣╬╬╬╬╬╬╬
// ╬╬╬╬╬╬╬ ╬╬╬╠╠╠╠╝╝╝╝╝╝╝╠╬╬╬╬╬╬ ╠╬╬╬╬╬╬╬ ╚╬╬╬╬╬╬╬╬
// ╬╬╬╬╬╬╬ ╣╬╬╬╬╠╠╩ ╘╬╬╬╬╬╬╬ ╠╬╬╬╬╬╬╬ ╙╬╬╬╬╬╬╬╬
//
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @notice Query struct containing adapter and swap amount information for a single hop
* @param adapter Address of the adapter contract to use for the swap
* @param recipient Address that will receive tokens from the swap
* @param tokenIn Address of the input token
* @param tokenOut Address of the output token
* @param amount Amount of tokens (input or output depending on swap type)
*/
struct Query {
address adapter;
address recipient;
address tokenIn;
address tokenOut;
uint256 amount;
}
/**
* @notice Compressed offer data using bytes encoding for gas efficiency
* @param amounts Encoded swap amounts for each hop
* @param adapters Encoded adapter addresses for each hop
* @param path Encoded token path for the swap route
* @param recipients Encoded recipient addresses for each hop
* @param deployers Encoded deployer addresses for AlgebraV2 custom pools (address(0) for other
* adapters)
*/
struct Offer {
bytes amounts;
bytes adapters;
bytes path;
bytes recipients;
bytes deployers;
}
/**
* @notice Formatted offer with decoded arrays for easier consumption
* @param amounts Array of swap amounts for each hop
* @param adapters Array of adapter addresses for each hop
* @param path Array of token addresses defining the swap route
* @param recipients Array of recipient addresses for each hop
* @param deployers Array of deployer addresses for AlgebraV2 custom pools (address(0) for other
* adapters)
*/
struct FormattedOffer {
uint256[] amounts;
address[] adapters;
address[] path;
address[] recipients;
address[] deployers;
}
/**
* @notice Trade parameters for executing a swap
* @param amountIn Amount of input tokens to swap
* @param amountOut Minimum amount of output tokens expected
* @param path Array of token addresses defining the swap route
* @param adapters Array of adapter addresses for each hop
* @param recipients Array of recipient addresses for each hop
* @param deployers Array of deployer addresses for AlgebraV2 custom pools (address(0) for other
* adapters)
*/
struct Trade {
uint256 amountIn;
uint256 amountOut;
address[] path;
address[] adapters;
address[] recipients;
address[] deployers;
}
/**
* @title IYakRouter
* @author Yak Exchange
* @notice Interface for the YakRouter contract that finds optimal swap paths and executes trades
* @dev Supports multi-hop swaps across different DEX adapters with minimal slippage
*/
interface IYakRouter {
/**
* @notice Thrown when a zero address is provided where it's not allowed
*/
error AddressZero();
/**
* @notice Thrown when the transaction deadline has passed
* @param _deadline The deadline timestamp that was set
* @param _currentTime The current block timestamp
*/
error DeadlinePassed(uint256 _deadline, uint256 _currentTime);
/**
* @notice Thrown when the ETH amount sent does not match the expected amount
* @param _sentAmount The amount of ETH sent with the transaction
* @param _expectedAmount The expected amount of ETH for the swap
*/
error IncorrectETHAmount(uint256 _sentAmount, uint256 _expectedAmount);
/**
* @notice Thrown when the provided fee is above the maximum allowed fee
* @param _fee The fee amount provided
* @param _maxFee The maximum fee amount allowed
*/
error FeeAboveMaximum(uint256 _fee, uint256 _maxFee);
/**
* @notice Thrown when the provided fee is less than the minimum required fee
* @param _fee The fee amount provided
* @param _minFee The minimum fee amount required
*/
error InsufficientFee(uint256 _fee, uint256 _minFee);
/**
* @notice Thrown when max steps is invalid (must be between 1 and 4)
* @param _maxSteps The invalid max steps value provided
*/
error InvalidMaxSteps(uint256 _maxSteps);
/**
* @notice Thrown when the actual output amount is less than the minimum expected
* @param _amountOut The actual output amount received
* @param _minAmountOut The minimum output amount expected
*/
error InsufficientOutputAmount(uint256 _amountOut, uint256 _minAmountOut);
/**
* @notice Thrown when swapping from ETH but the path doesn't start with WETH
* @param _tokenIn The first token in the path that should be WETH
*/
error PathDoesNotBeginWithWETH(address _tokenIn);
/**
* @notice Thrown when swapping to ETH but the path doesn't end with WETH
* @param _tokenOut The last token in the path that should be WETH
*/
error PathDoesNotEndWithWETH(address _tokenOut);
/**
* @notice Thrown when trade parameters length does not match
*/
error TradeLengthDoesNotMatch();
/**
* @notice Emitted when trusted tokens list is updated
* @param _newTrustedTokens The new array of trusted token addresses
*/
event UpdatedTrustedTokens(address[] _newTrustedTokens);
/**
* @notice Emitted when adapters list is updated
* @param _newAdapters The new array of adapter addresses
*/
event UpdatedAdapters(address[] _newAdapters);
/**
* @notice Emitted when minimum fee is updated
* @param _oldMinFee The previous minimum fee value
* @param _newMinFee The new minimum fee value
*/
event UpdatedMinFee(uint256 _oldMinFee, uint256 _newMinFee);
/**
* @notice Emitted when fee claimer address is updated
* @param _oldFeeClaimer The previous fee claimer address
* @param _newFeeClaimer The new fee claimer address
*/
event UpdatedFeeClaimer(address _oldFeeClaimer, address _newFeeClaimer);
/**
* @notice Emitted when a swap is executed
* @param _tokenIn The input token address
* @param _tokenOut The output token address
* @param _amountIn The input amount swapped
* @param _amountOut The output amount received
*/
event YakSwap(
address indexed _tokenIn, address indexed _tokenOut, uint256 _amountIn, uint256 _amountOut
);
// ========== Admin Functions ==========
/**
* @notice Updates the list of trusted tokens used for finding swap paths
* @param _trustedTokens Array of token addresses to use as intermediate tokens
* @dev Only callable by maintainer
*/
function setTrustedTokens(address[] memory _trustedTokens) external;
/**
* @notice Updates the list of DEX adapters
* @param _adapters Array of adapter contract addresses
* @dev Only callable by maintainer
*/
function setAdapters(address[] memory _adapters) external;
/**
* @notice Sets the address that receives swap fees
* @param _claimer Address to receive fees
* @dev Only callable by maintainer, cannot be zero address
*/
function setFeeClaimer(address _claimer) external;
/**
* @notice Sets the minimum fee in basis points (1/10000)
* @param _fee Minimum fee amount (e.g., 30 = 0.3%)
* @dev Only callable by maintainer
*/
function setMinFee(uint256 _fee) external;
// ========== View Functions ==========
/**
* @notice Returns the number of trusted tokens
* @return count The total number of trusted tokens configured
*/
function trustedTokensCount() external view returns (uint256);
/**
* @notice Returns the number of adapters
* @return count The total number of adapter contracts configured
*/
function adaptersCount() external view returns (uint256);
// ========== Query Functions ==========
/**
* @notice Queries a specific adapter for swap quote
* @param _amount Input amount (if exactIn) or output amount (if !exactIn)
* @param _tokenIn Address of the input token
* @param _tokenOut Address of the output token
* @param _index Index of the adapter in the adapters array
* @param _exactIn True for exact input, false for exact output
* @return quoteAmount The output amount (if exactIn) or input amount (if !exactIn)
* @return recipient The recipient address for this adapter
*/
function queryAdapter(
uint256 _amount,
address _tokenIn,
address _tokenOut,
uint8 _index,
bool _exactIn
) external returns (uint256, address);
/**
* @notice Finds the best adapter from specified options for a direct swap
* @param _amount Input amount (if exactIn) or output amount (if !exactIn)
* @param _tokenIn Address of the input token
* @param _tokenOut Address of the output token
* @param _options Array of adapter indices to check
* @param _exactIn True for exact input, false for exact output
* @return query The best query result with adapter and amount information
*/
function queryNoSplit(
uint256 _amount,
address _tokenIn,
address _tokenOut,
uint8[] calldata _options,
bool _exactIn
) external view returns (Query memory);
/**
* @notice Finds the best adapter from all available adapters for a direct swap
* @param _amount Input amount (if exactIn) or output amount (if !exactIn)
* @param _tokenIn Address of the input token
* @param _tokenOut Address of the output token
* @param _exactIn True for exact input, false for exact output
* @return query The best query result with adapter and amount information
*/
function queryNoSplit(uint256 _amount, address _tokenIn, address _tokenOut, bool _exactIn)
external
view
returns (Query memory);
/**
* @notice Finds the optimal swap path between two tokens
* @param _amount Input amount (if exactIn) or output amount (if !exactIn)
* @param _tokenIn Address of the input token
* @param _tokenOut Address of the output token
* @param _trustedTokens Additional trusted tokens to consider for routing
* @param _maxSteps Maximum number of hops allowed (1-4)
* @param _exactIn True for exact input, false for exact output
* @return offer The optimal swap path with amounts and adapters for each hop
* @dev Combines default trusted tokens with provided ones for path finding
*/
function findBestPath(
uint256 _amount,
address _tokenIn,
address _tokenOut,
address[] memory _trustedTokens,
uint256 _maxSteps,
bool _exactIn
) external view returns (FormattedOffer memory);
// ========== Swap Functions ==========
/**
* @notice Executes a token-to-token swap
* @param _trade Trade parameters including path and amounts
* @param _fee Fee amount in basis points to charge (e.g., 30 = 0.3%)
* @param _deadline Unix timestamp after which the transaction reverts
* @param _to Address to receive the output tokens
* @dev Requires token approval from caller
*/
function swapNoSplit(Trade calldata _trade, uint256 _fee, uint256 _deadline, address _to)
external;
/**
* @notice Executes a swap starting from ETH
* @param _trade Trade parameters (path must start with WETH)
* @param _fee Fee amount in basis points to charge
* @param _deadline Unix timestamp after which the transaction reverts
* @param _to Address to receive the output tokens
* @dev Accepts ETH and wraps to WETH internally
*/
function swapNoSplitFromETH(Trade calldata _trade, uint256 _fee, uint256 _deadline, address _to)
external
payable;
/**
* @notice Executes a swap ending in ETH
* @param _trade Trade parameters (path must end with WETH)
* @param _fee Fee amount in basis points to charge
* @param _deadline Unix timestamp after which the transaction reverts
* @param _to Address to receive the ETH
* @dev Unwraps WETH to ETH before sending to recipient
*/
function swapNoSplitToETH(Trade calldata _trade, uint256 _fee, uint256 _deadline, address _to)
external;
/**
* @notice Executes a token-to-token swap using EIP-2612 permit
* @param _trade Trade parameters including path and amounts
* @param _fee Fee amount in basis points to charge
* @param _deadline Unix timestamp after which the transaction reverts
* @param _to Address to receive the output tokens
* @param _v Permit signature v value
* @param _r Permit signature r value
* @param _s Permit signature s value
* @dev Uses permit to avoid separate approval transaction
*/
function swapNoSplitWithPermit(
Trade calldata _trade,
uint256 _fee,
uint256 _deadline,
address _to,
uint8 _v,
bytes32 _r,
bytes32 _s
) external;
/**
* @notice Executes a swap to ETH using EIP-2612 permit
* @param _trade Trade parameters (path must end with WETH)
* @param _fee Fee amount in basis points to charge
* @param _deadline Unix timestamp after which the transaction reverts
* @param _to Address to receive the ETH
* @param _v Permit signature v value
* @param _r Permit signature r value
* @param _s Permit signature s value
* @dev Uses permit and unwraps WETH to ETH
*/
function swapNoSplitToETHWithPermit(
Trade calldata _trade,
uint256 _fee,
uint256 _deadline,
address _to,
uint8 _v,
bytes32 _r,
bytes32 _s
) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {AccessControl, Context} from "@openzeppelin/contracts/access/AccessControl.sol";
/**
* @dev Contract module which extends the basic access control mechanism of Ownable
* to include many maintainers, whom only the owner (DEFAULT_ADMIN_ROLE) may add and
* remove.
*
* 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 this modifier:
* `onlyMaintainer`, which can be applied to your functions to restrict their use to
* the accounts with the role of maintainer.
*/
abstract contract Maintainable is Context, AccessControl {
error OnlyMaintainer();
bytes32 public constant MAINTAINER_ROLE = keccak256("MAINTAINER_ROLE");
constructor() {
address msgSender = _msgSender();
// members of the DEFAULT_ADMIN_ROLE alone may revoke and grant role membership
_setupRole(DEFAULT_ADMIN_ROLE, msgSender);
_setupRole(MAINTAINER_ROLE, msgSender);
}
function addMaintainer(address addedMaintainer) public virtual {
grantRole(MAINTAINER_ROLE, addedMaintainer);
}
function removeMaintainer(address removedMaintainer) public virtual {
revokeRole(MAINTAINER_ROLE, removedMaintainer);
}
function renounceRole(bytes32 role) public virtual {
address msgSender = _msgSender();
renounceRole(role, msgSender);
}
function transferOwnership(address newOwner) public virtual {
address msgSender = _msgSender();
grantRole(DEFAULT_ADMIN_ROLE, newOwner);
renounceRole(DEFAULT_ADMIN_ROLE, msgSender);
}
modifier onlyMaintainer() {
address msgSender = _msgSender();
if (!hasRole(MAINTAINER_ROLE, msgSender)) revert OnlyMaintainer();
_;
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
import {SafeERC20, IERC20} from "contracts/lib/SafeERC20.sol";
import {Maintainable} from "contracts/lib/Maintainable.sol";
abstract contract Recoverable is Maintainable {
using SafeERC20 for IERC20;
error ETHTransferFailed();
error NothingToRecover();
event Recovered(address indexed _asset, uint256 amount);
/**
* @notice Recover ERC20 from contract
* @param _tokenAddress token address
* @param _tokenAmount amount to recover
*/
function recoverERC20(address _tokenAddress, uint256 _tokenAmount) external onlyMaintainer {
if (_tokenAmount == 0) revert NothingToRecover();
IERC20(_tokenAddress).safeTransfer(msg.sender, _tokenAmount);
emit Recovered(_tokenAddress, _tokenAmount);
}
/**
* @notice Recover native asset from contract
* @param _amount amount
*/
function recoverNative(uint256 _amount) external onlyMaintainer {
if (_amount == 0) revert NothingToRecover();
(bool refunded,) = msg.sender.call{value: _amount}("");
if (!refunded) revert ETHTransferFailed();
emit Recovered(address(0), _amount);
}
}// This is a simplified version of OpenZepplin's SafeERC20 library
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma experimental ABIEncoderV2;
import {IERC20} from "contracts/interface/IERC20.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 ERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
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)
);
}
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'
// solhint-disable-next-line max-line-length
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));
}
/**
* @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.
// A Solidity high level call has three parts:
// 1. The target address is checked to verify it contains contract code
// 2. The call itself is made, and success asserted
// 3. The return value is decoded, which in turn checks the size of the returned data.
// solhint-disable-next-line max-line-length
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = address(token).call(data);
require(success, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
// Return data is optional
// solhint-disable-next-line max-line-length
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
library TypeConversion {
function toBytes12(address x) internal pure returns (bytes12 y) {
assembly { y := x }
}
function toBytes32(address x) internal pure returns (bytes32 y) {
assembly { y := x }
}
function toAddress(bytes32 x) internal pure returns (address y) {
assembly { y := x }
}
function toBytes(address x) internal pure returns (bytes memory y) {
y = new bytes(32);
assembly { mstore(add(y, 32), x) }
}
function toBytes(bytes32 x) internal pure returns (bytes memory y) {
y = new bytes(32);
assembly { mstore(add(y, 32), x) }
}
function toBytes(uint x) internal pure returns (bytes memory y) {
y = new bytes(32);
assembly { mstore(add(y, 32), x) }
}
function toAddress(
bytes memory x,
uint offset
) internal pure returns (address y) {
assembly { y := mload(add(x, offset)) }
}
function toUint(
bytes memory x,
uint offset
) internal pure returns (uint y) {
assembly { y := mload(add(x, offset)) }
}
function toBytes12(
bytes memory x,
uint offset
) internal pure returns (bytes12 y) {
assembly { y := mload(add(x, offset)) }
}
function toBytes32(
bytes memory x,
uint offset
) internal pure returns (bytes32 y) {
assembly { y := mload(add(x, offset)) }
}
function toAddresses(
bytes memory xs
) internal pure returns (address[] memory ys) {
ys = new address[](xs.length/32);
for (uint i=0; i < xs.length/32; i++) {
ys[i] = toAddress(xs, i*32 + 32);
}
}
function toUints(
bytes memory xs
) internal pure returns (uint[] memory ys) {
ys = new uint[](xs.length/32);
for (uint i=0; i < xs.length/32; i++) {
ys[i] = toUint(xs, i*32 + 32);
}
}
function toBytes32s(
bytes memory xs
) internal pure returns (bytes32[] memory ys) {
ys = new bytes32[](xs.length/32);
for (uint i=0; i < xs.length/32; i++) {
ys[i] = toBytes32(xs, i*32 + 32);
}
}
}// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >=0.8.4;
import {Offer, FormattedOffer} from "contracts/interface/IYakRouter.sol";
import {TypeConversion} from "contracts/lib/TypeConversion.sol";
library OfferUtils {
using TypeConversion for address;
using TypeConversion for uint256;
using TypeConversion for bytes;
uint256 public constant SLOT_LENGTH = 32; // Storage slot length in bytes
function newOffer(uint256 _amount, address _token) internal pure returns (Offer memory offer) {
offer.amounts = _amount.toBytes();
offer.path = _token.toBytes();
}
/**
* Makes a deep copy of Offer struct
*/
function clone(Offer memory _queries) internal pure returns (Offer memory) {
return Offer(_queries.amounts, _queries.adapters, _queries.path, _queries.recipients, _queries.deployers);
}
/**
* Appends new elements to the top of Offer struct
*/
function addToHead(
Offer memory _queries,
uint256 _amount,
address _adapter,
address _recipient,
address _token
) internal pure {
_queries.path = bytes.concat(_token.toBytes(), _queries.path);
_queries.adapters = bytes.concat(_adapter.toBytes(), _queries.adapters);
_queries.amounts = bytes.concat(_amount.toBytes(), _queries.amounts);
_queries.recipients = bytes.concat(_recipient.toBytes(), _queries.recipients);
_queries.deployers = bytes.concat(address(0).toBytes(), _queries.deployers);
}
function addToHead(
Offer memory _queries,
uint256 _amount,
address _adapter,
address _recipient,
address _token,
address _deployer
) internal pure {
_queries.path = bytes.concat(_token.toBytes(), _queries.path);
_queries.adapters = bytes.concat(_adapter.toBytes(), _queries.adapters);
_queries.amounts = bytes.concat(_amount.toBytes(), _queries.amounts);
_queries.recipients = bytes.concat(_recipient.toBytes(), _queries.recipients);
_queries.deployers = bytes.concat(_deployer.toBytes(), _queries.deployers);
}
/**
* Appends new elements to the end of Offer struct
*/
function addToTail(
Offer memory _queries,
uint256 _amount,
address _adapter,
address _recipient,
address _token
) internal pure {
_queries.path = bytes.concat(_queries.path, _token.toBytes());
_queries.adapters = bytes.concat(_queries.adapters, _adapter.toBytes());
_queries.amounts = bytes.concat(_queries.amounts, _amount.toBytes());
_queries.recipients = bytes.concat(_queries.recipients, _recipient.toBytes());
_queries.deployers = bytes.concat(_queries.deployers, address(0).toBytes());
}
function addToTail(
Offer memory _queries,
uint256 _amount,
address _adapter,
address _recipient,
address _token,
address _deployer
) internal pure {
_queries.path = bytes.concat(_queries.path, _token.toBytes());
_queries.adapters = bytes.concat(_queries.adapters, _adapter.toBytes());
_queries.amounts = bytes.concat(_queries.amounts, _amount.toBytes());
_queries.recipients = bytes.concat(_queries.recipients, _recipient.toBytes());
_queries.deployers = bytes.concat(_queries.deployers, _deployer.toBytes());
}
/**
* Formats elements in the Offer object from byte-arrays to integers and addresses
*/
function format(Offer memory _queries) internal pure returns (FormattedOffer memory) {
return FormattedOffer(
_queries.amounts.toUints(),
_queries.adapters.toAddresses(),
_queries.path.toAddresses(),
_queries.recipients.toAddresses(),
_queries.deployers.toAddresses()
);
}
function getTokenOut(Offer memory _offer) internal pure returns (address tokenOut) {
tokenOut = _offer.path.toAddress(_offer.path.length); // Last SLOT_LENGTH bytes
}
function getTokenIn(Offer memory _offer) internal pure returns (address tokenIn) {
tokenIn = _offer.path.toAddress(SLOT_LENGTH); // First SLOT_LENGTH bytes
}
function getAmountOut(Offer memory _offer) internal pure returns (uint256 amount) {
amount = _offer.amounts.toUint(_offer.amounts.length); // Last SLOT_LENGTH bytes
}
function getAmountIn(Offer memory _offer) internal pure returns (uint256 amount) {
amount = _offer.amounts.toUint(SLOT_LENGTH); // First SLOT_LENGTH bytes
}
}
library FormattedOfferUtils {
using TypeConversion for address;
using TypeConversion for uint256;
using TypeConversion for bytes;
/**
* Appends new elements to the end of FormattedOffer
*/
function addToTail(
FormattedOffer memory offer,
uint256 amount,
address wrapper,
address token,
address recipient
) internal pure {
offer.amounts = bytes.concat(abi.encodePacked(offer.amounts), amount.toBytes()).toUints();
offer.adapters =
bytes.concat(abi.encodePacked(offer.adapters), wrapper.toBytes()).toAddresses();
offer.path = bytes.concat(abi.encodePacked(offer.path), token.toBytes()).toAddresses();
offer.recipients =
bytes.concat(abi.encodePacked(offer.recipients), recipient.toBytes()).toAddresses();
offer.deployers =
bytes.concat(abi.encodePacked(offer.deployers), address(0).toBytes()).toAddresses();
}
function addToTail(
FormattedOffer memory offer,
uint256 amount,
address wrapper,
address token,
address recipient,
address deployer
) internal pure {
offer.amounts = bytes.concat(abi.encodePacked(offer.amounts), amount.toBytes()).toUints();
offer.adapters =
bytes.concat(abi.encodePacked(offer.adapters), wrapper.toBytes()).toAddresses();
offer.path = bytes.concat(abi.encodePacked(offer.path), token.toBytes()).toAddresses();
offer.recipients =
bytes.concat(abi.encodePacked(offer.recipients), recipient.toBytes()).toAddresses();
offer.deployers =
bytes.concat(abi.encodePacked(offer.deployers), deployer.toBytes()).toAddresses();
}
/**
* Appends new elements to the beginning of FormattedOffer
*/
function addToHead(
FormattedOffer memory offer,
uint256 amount,
address wrapper,
address token,
address recipient
) internal pure {
offer.amounts = bytes.concat(amount.toBytes(), abi.encodePacked(offer.amounts)).toUints();
offer.adapters =
bytes.concat(wrapper.toBytes(), abi.encodePacked(offer.adapters)).toAddresses();
offer.path = bytes.concat(token.toBytes(), abi.encodePacked(offer.path)).toAddresses();
offer.recipients =
bytes.concat(recipient.toBytes(), abi.encodePacked(offer.recipients)).toAddresses();
offer.deployers =
bytes.concat(address(0).toBytes(), abi.encodePacked(offer.deployers)).toAddresses();
}
function addToHead(
FormattedOffer memory offer,
uint256 amount,
address wrapper,
address token,
address recipient,
address deployer
) internal pure {
offer.amounts = bytes.concat(amount.toBytes(), abi.encodePacked(offer.amounts)).toUints();
offer.adapters =
bytes.concat(wrapper.toBytes(), abi.encodePacked(offer.adapters)).toAddresses();
offer.path = bytes.concat(token.toBytes(), abi.encodePacked(offer.path)).toAddresses();
offer.recipients =
bytes.concat(recipient.toBytes(), abi.encodePacked(offer.recipients)).toAddresses();
offer.deployers =
bytes.concat(deployer.toBytes(), abi.encodePacked(offer.deployers)).toAddresses();
}
function getAmountOut(FormattedOffer memory offer) internal pure returns (uint256) {
return offer.amounts[offer.amounts.length - 1];
}
}{
"evmVersion": "prague",
"optimizer": {
"enabled": true,
"runs": 1000000,
"details": {
"yulDetails": {
"optimizerSteps": "u"
}
}
},
"viaIR": true,
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"metadata": {
"useLiteralContent": true
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address[]","name":"_adapters","type":"address[]"},{"internalType":"address[]","name":"_trustedTokens","type":"address[]"},{"internalType":"address","name":"_feeClaimer","type":"address"},{"internalType":"address","name":"_wrapped_native","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AddressZero","type":"error"},{"inputs":[{"internalType":"uint256","name":"_deadline","type":"uint256"},{"internalType":"uint256","name":"_currentTime","type":"uint256"}],"name":"DeadlinePassed","type":"error"},{"inputs":[],"name":"ETHTransferFailed","type":"error"},{"inputs":[{"internalType":"uint256","name":"_fee","type":"uint256"},{"internalType":"uint256","name":"_maxFee","type":"uint256"}],"name":"FeeAboveMaximum","type":"error"},{"inputs":[{"internalType":"uint256","name":"_sentAmount","type":"uint256"},{"internalType":"uint256","name":"_expectedAmount","type":"uint256"}],"name":"IncorrectETHAmount","type":"error"},{"inputs":[{"internalType":"uint256","name":"_fee","type":"uint256"},{"internalType":"uint256","name":"_minFee","type":"uint256"}],"name":"InsufficientFee","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOut","type":"uint256"},{"internalType":"uint256","name":"_minAmountOut","type":"uint256"}],"name":"InsufficientOutputAmount","type":"error"},{"inputs":[{"internalType":"uint256","name":"_maxSteps","type":"uint256"}],"name":"InvalidMaxSteps","type":"error"},{"inputs":[],"name":"NothingToRecover","type":"error"},{"inputs":[],"name":"OnlyMaintainer","type":"error"},{"inputs":[{"internalType":"address","name":"_tokenIn","type":"address"}],"name":"PathDoesNotBeginWithWETH","type":"error"},{"inputs":[{"internalType":"address","name":"_tokenOut","type":"address"}],"name":"PathDoesNotEndWithWETH","type":"error"},{"inputs":[],"name":"TradeLengthDoesNotMatch","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Recovered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"_newAdapters","type":"address[]"}],"name":"UpdatedAdapters","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_oldFeeClaimer","type":"address"},{"indexed":false,"internalType":"address","name":"_newFeeClaimer","type":"address"}],"name":"UpdatedFeeClaimer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_oldMinFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_newMinFee","type":"uint256"}],"name":"UpdatedMinFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"_newTrustedTokens","type":"address[]"}],"name":"UpdatedTrustedTokens","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_tokenIn","type":"address"},{"indexed":true,"internalType":"address","name":"_tokenOut","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amountIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_amountOut","type":"uint256"}],"name":"YakSwap","type":"event"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"ADAPTERS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_CLAIMER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_DENOMINATOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAINTAINER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NAME","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NATIVE","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SLOT_LENGTH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"TRUSTED_TOKENS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WNATIVE","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"adaptersCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addedMaintainer","type":"address"}],"name":"addMaintainer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_tokenIn","type":"address"},{"internalType":"address","name":"_tokenOut","type":"address"},{"internalType":"address[]","name":"_trustedTokens","type":"address[]"},{"internalType":"uint256","name":"_maxSteps","type":"uint256"},{"internalType":"bool","name":"_exactIn","type":"bool"}],"name":"findBestPath","outputs":[{"components":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address[]","name":"adapters","type":"address[]"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address[]","name":"recipients","type":"address[]"},{"internalType":"address[]","name":"deployers","type":"address[]"}],"internalType":"struct FormattedOffer","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_tokenIn","type":"address"},{"internalType":"address","name":"_tokenOut","type":"address"},{"internalType":"uint8","name":"_index","type":"uint8"},{"internalType":"bool","name":"_exactIn","type":"bool"}],"name":"queryAdapter","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_tokenIn","type":"address"},{"internalType":"address","name":"_tokenOut","type":"address"},{"internalType":"uint8[]","name":"_options","type":"uint8[]"},{"internalType":"bool","name":"_exactIn","type":"bool"}],"name":"queryNoSplit","outputs":[{"components":[{"internalType":"address","name":"adapter","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct Query","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_tokenIn","type":"address"},{"internalType":"address","name":"_tokenOut","type":"address"},{"internalType":"bool","name":"_exactIn","type":"bool"}],"name":"queryNoSplit","outputs":[{"components":[{"internalType":"address","name":"adapter","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct Query","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"uint256","name":"_tokenAmount","type":"uint256"}],"name":"recoverERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"recoverNative","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"removedMaintainer","type":"address"}],"name":"removeMaintainer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_adapters","type":"address[]"}],"name":"setAdapters","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_claimer","type":"address"}],"name":"setFeeClaimer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fee","type":"uint256"}],"name":"setMinFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_trustedTokens","type":"address[]"}],"name":"setTrustedTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address[]","name":"adapters","type":"address[]"},{"internalType":"address[]","name":"recipients","type":"address[]"},{"internalType":"address[]","name":"deployers","type":"address[]"}],"internalType":"struct Trade","name":"_trade","type":"tuple"},{"internalType":"uint256","name":"_fee","type":"uint256"},{"internalType":"uint256","name":"_deadline","type":"uint256"},{"internalType":"address","name":"_to","type":"address"}],"name":"swapNoSplit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address[]","name":"adapters","type":"address[]"},{"internalType":"address[]","name":"recipients","type":"address[]"},{"internalType":"address[]","name":"deployers","type":"address[]"}],"internalType":"struct Trade","name":"_trade","type":"tuple"},{"internalType":"uint256","name":"_fee","type":"uint256"},{"internalType":"uint256","name":"_deadline","type":"uint256"},{"internalType":"address","name":"_to","type":"address"}],"name":"swapNoSplitFromETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address[]","name":"adapters","type":"address[]"},{"internalType":"address[]","name":"recipients","type":"address[]"},{"internalType":"address[]","name":"deployers","type":"address[]"}],"internalType":"struct Trade","name":"_trade","type":"tuple"},{"internalType":"uint256","name":"_fee","type":"uint256"},{"internalType":"uint256","name":"_deadline","type":"uint256"},{"internalType":"address","name":"_to","type":"address"}],"name":"swapNoSplitToETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address[]","name":"adapters","type":"address[]"},{"internalType":"address[]","name":"recipients","type":"address[]"},{"internalType":"address[]","name":"deployers","type":"address[]"}],"internalType":"struct Trade","name":"_trade","type":"tuple"},{"internalType":"uint256","name":"_fee","type":"uint256"},{"internalType":"uint256","name":"_deadline","type":"uint256"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint8","name":"_v","type":"uint8"},{"internalType":"bytes32","name":"_r","type":"bytes32"},{"internalType":"bytes32","name":"_s","type":"bytes32"}],"name":"swapNoSplitToETHWithPermit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address[]","name":"adapters","type":"address[]"},{"internalType":"address[]","name":"recipients","type":"address[]"},{"internalType":"address[]","name":"deployers","type":"address[]"}],"internalType":"struct Trade","name":"_trade","type":"tuple"},{"internalType":"uint256","name":"_fee","type":"uint256"},{"internalType":"uint256","name":"_deadline","type":"uint256"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint8","name":"_v","type":"uint8"},{"internalType":"bytes32","name":"_r","type":"bytes32"},{"internalType":"bytes32","name":"_s","type":"bytes32"}],"name":"swapNoSplitWithPermit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"trustedTokensCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60a0604052346100535761001d6100146101b9565b9291909161022a565b6040516142516107408239608051818181610cd401528181611ac9015281816120d801528181613130015261324a015261425190f35b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b90601f01601f191681019081106001600160401b0382111761008c57604052565b610057565b906100a561009e60405190565b928361006b565b565b6001600160401b03811161008c5760208091020190565b6001600160a01b031690565b90565b6001600160a01b0381160361005357565b905051906100a5826100cd565b909291926101006100fb826100a7565b610091565b938185526020808601920283019281841161005357915b8383106101245750505050565b6020809161013284866100de565b815201920191610117565b9080601f830112156100535781516100ca926020016100eb565b6080818303126100535780516001600160401b038111610053578261017d91830161013d565b60208201519093906001600160401b038111610053576101a2846100ca92850161013d565b9360606101b282604087016100de565b94016100de565b6101d76149b1803803806101cc81610091565b928339810190610157565b90919293565b905f19905b9181191691161790565b6100ca6100ca6100ca9290565b906102096100ca610210926101ec565b82546101dd565b9055565b6100be6100ca6100ca9290565b6100ca90610214565b906102336102b5565b61023e5f60016101f9565b6102475f610221565b6001600160a01b0381166001600160a01b03851614908115610299575b50610288576102839261027961027e92610521565b610608565b610655565b608052565b639fabe1c160e01b5f908152600490fd5b6001600160a01b031690506001600160a01b038516145f610264565b6100a56100a56102c9565b6100ca5f6101ec565b6100a5336102de816102d96102c0565b61065e565b5f5160206149915f395f51905f5261065e565b61031061030c335b5f5160206149915f395f51905f52610680565b1590565b61031d576100a5906104e0565b6301c42f3160e61b5f908152600490fd5b915f1960089290920291821b911b6101e2565b91906103526100ca610210936101ec565b90835461032e565b6100a5915f91610341565b818110610370575050565b8061037d5f60019361035a565b01610365565b91909182821061039257505050565b6100a592916103a590915f5260205f2090565b9182019101610365565b9068010000000000000000811161008c57816103cc6100a5935490565b90828155610383565b6100ca906100be906001600160a01b031682565b6100ca906103d5565b6100ca906103e9565b8151916001600160401b03831161008c5761042f61042560019261041f86866103af565b60200190565b925f5260205f2090565b9204915f5b8381106104415750505050565b600190602061045a6100ca86516001600160a01b031690565b9401938184015501610434565b906100a5916103fb565b9061049161048a610480845190565b8084529260200190565b9260200190565b905f5b8181106104a15750505090565b9091926104c76104c060019286516001600160a01b0316815260200190565b9460200190565b929101610494565b60208082526100ca92910190610471565b61051c7f658ff1688002926d8f426cb10c052ec29003f50042df9652d8613484c1a5864791610510816003610467565b604051918291826104cf565b0390a1565b6100a5906102f1565b61053661030c336102f9565b61031d576100a590610596565b6100ca906100be565b6100ca9054610543565b906001600160a01b03906101e2565b906105756100ca610210926103f2565b8254610556565b6001600160a01b0391821681529116602082015260400190565b6105a26100be5f610221565b6001600160a01b03821614610288577fb2c853ac4d80d18d058c43d8018d077a036e542a79acae1647f5ad2a8c76f4e2906105e86105e0600261054c565b916002610565565b6105f2600261054c565b9061051c6105ff60405190565b9283928361057c565b6100a59061052a565b61061d61030c336102f9565b61031d576100a59061051c7febf7325f48e05e5e38809c69f8b02a7c907ed31d8768e6c2d841b1296a9225fe91610510816004610467565b6100a590610611565b906100a5916106c7565b905b5f5260205260405f2090565b9061066a906103f2565b6100ca915f61069a6106a0936106935f90565b5082610668565b01610676565b5460ff1690565b9060ff906101e2565b906106c06100ca61021092151590565b82546106a7565b6106d461030c8383610680565b6106dc575050565b6106f560016106f0845f61069a8682610668565b6106b0565b61070f610709610703339390565b936103f2565b916103f2565b917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d61073a60405190565b5f90a456fe6080604052600436101561001a575b3615610018575f80fd5b005b5f3560e01c8062b99e361461027857806301ffc9a714610273578063243f8bfc1461026e578063248a9ca3146102695780632f2ff15d1461026457806331ac99201461025f57806336568abe1461025a5780633a9a40811461025557806352a52ab01461025057806356ca76b41461024b578063645d916b146102465780636b453c1f1461024157806375c834b51461023c57806376c7a3c71461023757806376ebe69c1461023257806377d007f71461022d5780637c7a561b146102285780638980f11f146102235780638bb9c5bf1461021e57806391d1485414610219578063952e901214610214578063974584601461020f578063a0cf0aea1461020a578063a217fddf14610205578063a3f4df7e14610200578063aede3693146101fb578063b0873e5e146101f6578063b381cf40146101f1578063b5ce5649146101ec578063c3accd48146101e7578063c8a3a5c6146101e2578063cc299d4f146101dd578063d547741f146101d8578063d73792a9146101d3578063d8baf7cf146101ce578063db6a5897146101c9578063f2fde38b146101c45763f87422540361000e57610f88565b610f70565b610f42565b610daa565b610d8f565b610d63565b610d47565b610d2f565b610d17565b610cf8565b610cbf565b610ca4565b610c7a565b610c53565b610b2e565b610af5565b610aaf565b610a22565b6109ee565b6109d6565b6109bd565b61097e565b610967565b61094b565b610930565b6108f3565b610885565b610852565b6107eb565b610756565b6106ce565b610584565b61056c565b61054e565b6104ff565b6104bd565b61035c565b6102e5565b5f91031261028757565b5f80fd5b6102ad916008021c5b73ffffffffffffffffffffffffffffffffffffffff1690565b90565b906102ad915461028b565b6102ad5f60026102b0565b6102cf90610294565b9052565b6020810192916102e391906102c6565b565b34610287576102f536600461027d565b61030c6103006102bb565b604051918291826102d3565b0390f35b7fffffffff0000000000000000000000000000000000000000000000000000000081165b0361028757565b905035906102e382610310565b90602082820312610287576102ad9161033b565b346102875761030c610377610372366004610348565b610fc1565b60405191829182901515815260200190565b80610334565b905035906102e382610389565b61033481610294565b905035906102e38261039c565b909182601f830112156102875781359167ffffffffffffffff831161028757602001926020830284011161028757565b801515610334565b905035906102e3826103e2565b9160a0838303126102875761040c828461038f565b9261041a83602083016103a5565b9261042881604084016103a5565b92606083013567ffffffffffffffff8111610287578261044f6080946102ad9387016103b2565b949095016103ea565b906080806102e3936104705f8201515f8601906102c6565b610482602082015160208601906102c6565b610494604082015160408601906102c6565b6104a6606082015160608601906102c6565b0151910152565b60a0810192916102e39190610458565b346102875761030c6104df6104d33660046103f7565b949390939291926111d6565b604051918291826104ad565b90602082820312610287576102ad9161038f565b346102875761030c61051a6105153660046104eb565b6113d1565b6040515b9182918290815260200190565b9190604083820312610287576102ad906020610547828661038f565b94016103a5565b346102875761056761056136600461052b565b9061140e565b604051005b346102875761056761057f3660046104eb565b6115db565b346102875761056761059736600461052b565b90611675565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b90601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810190811067ffffffffffffffff82111761060a57604052565b61059d565b906102e361061c60405190565b92836105ca565b67ffffffffffffffff811161060a5760208091020190565b9092919261065061064b82610623565b61060f565b938185526020808601920283019281841161028757915b8383106106745750505050565b6020809161068284866103a5565b815201920191610667565b9080601f83011215610287578160206102ad9335910161063b565b9060208282031261028757813567ffffffffffffffff8111610287576102ad920161068d565b34610287576105676106e13660046106a8565b611897565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b80548210156107335761072b6001915f5260205f2090565b910201905f90565b6106e6565b600354811015610287576107506102ad916003610713565b906102b0565b346102875761030c61030061076c3660046104eb565b610738565b60ff8116610334565b905035906102e382610771565b919060a0838203126102875761079d818461038f565b926107ab82602083016103a5565b926102ad6107bc84604085016103a5565b9360806107cc826060870161077a565b94016103ea565b9081526040810192916102e3916020905b01906102c6565b34610287576108076107fe366004610787565b939290926118a0565b9061030c61081460405190565b928392836107d3565b60808183031261028757610831828261038f565b926102ad61084284602085016103a5565b9360606107cc82604087016103a5565b346102875761030c6104df61086836600461081d565b9291909161195a565b90602082820312610287576102ad916103a5565b3461028757610567610898366004610871565b611973565b908160c09103126102875790565b60808183031261028757803567ffffffffffffffff811161028757826108d291830161089d565b926102ad6108e3846020850161038f565b936060610547826040870161038f565b34610287576105676109063660046108ab565b929190916119f5565b6102ad916008021c81565b906102ad915461090f565b6102ad5f600161091a565b346102875761094036600461027d565b61030c61051a610925565b346102875761095b36600461027d565b61030c61051a60035490565b6105676109753660046108ab565b92919091611ba3565b346102875761098e36600461027d565b61030c61051a60045490565b9190604083820312610287576102ad9060206109b682866103a5565b940161038f565b34610287576105676109d036600461099a565b90611c48565b34610287576105676109e93660046104eb565b611c52565b346102875761030c610377610a0436600461052b565b90611c79565b600454811015610287576107506102ad916004610713565b346102875761030c610300610a383660046104eb565b610a0a565b60e08183031261028757803567ffffffffffffffff81116102875782610a6491830161089d565b92610a72836020840161038f565b92610a80816040850161038f565b92610a8e82606083016103a5565b926102ad610a9f846080850161077a565b9360c06109b68260a0870161038f565b3461028757610567610ac2366004610a3d565b95949094939193611ce1565b6102946102ad6102ad9290565b6102ad90610ace565b6102ad5f610adb565b6102ad610ae4565b3461028757610b0536600461027d565b61030c610300610aed565b6102ad6102ad6102ad9290565b6102ad5f610b10565b6102ad610b1d565b3461028757610b3e36600461027d565b61030c61051a610b26565b67ffffffffffffffff811161060a57602090601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160190565b0190565b90610b9561064b83610b49565b918252565b610ba46010610b88565b7f43616d656c6f7459616b526f7574657200000000000000000000000000000000602082015290565b6102ad610b9a565b6102ad610bcd565b6102ad610bd5565b90825f9392825e0152565b610c11610c1a602093610b8493610c05815190565b80835293849260200190565b95869101610be5565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690565b60208082526102ad92910190610bf0565b3461028757610c6336600461027d565b61030c610c6e610bdd565b60405191829182610c42565b3461028757610567610c8d3660046104eb565b611e7a565b6102ad6020610b10565b6102ad610c92565b3461028757610cb436600461027d565b61030c61051a610c9c565b3461028757610ccf36600461027d565b61030c7f0000000000000000000000000000000000000000000000000000000000000000610300565b3461028757610567610d0b366004610a3d565b95949094939193611e83565b3461028757610567610d2a366004610871565b61201b565b3461028757610567610d423660046106a8565b612068565b3461028757610567610d5a3660046108ab565b92919091612185565b3461028757610567610d7636600461052b565b906121ac565b6102ad612710610b10565b6102ad610d7c565b3461028757610d9f36600461027d565b61030c61051a610d87565b3461028757610567610dbd366004610871565b6121b6565b909160c08284031261028757610dd8838361038f565b92610de681602085016103a5565b92610df482604083016103a5565b92606082013567ffffffffffffffff811161028757610e18846102ad92850161068d565b9360a06107cc826080870161038f565b90610e48610e41610e37845190565b8084529260200190565b9260200190565b905f5b818110610e585750505090565b909192610e75610e6e6001928651815260200190565b9460200190565b929101610e4b565b90610b84816020936102c6565b90610e99610e41610e37845190565b905f5b818110610ea95750505090565b909192610ebc610e6e6001928651610e7d565b929101610e9c565b6102ad916080610f20610f0e610efc610eea60a086015f8801518782035f890152610e28565b60208701518682036020880152610e8a565b60408601518582036040870152610e8a565b60608501518482036060860152610e8a565b920151906080818403910152610e8a565b60208082526102ad92910190610ec4565b346102875761030c610f64610f58366004610dc2565b94939093929192612296565b60405191829182610f31565b3461028757610567610f83366004610871565b612432565b3461028757610f9836600461027d565b61030c7f339759585899103d2ace64958e37e18ccb0504652c81d4a1b8aa80fe2126ab9561051a565b7f7965db0b000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000821614908115611011575090565b6102ad91507fffffffff00000000000000000000000000000000000000000000000000000000167f01ffc9a7000000000000000000000000000000000000000000000000000000001490565b6102ad60a061060f565b61106f61105d565b905f825260208080808086015f8152015f8152015f8152015f905250565b6102ad611067565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b60ff1660ff81146110d35760010190565b611095565b6102ad6102ad6102ad9260ff1690565b9190811015610733576020020190565b356102ad81610771565b6102946102ad6102ad9273ffffffffffffffffffffffffffffffffffffffff1690565b6102ad90611102565b6102ad90611125565b905051906102e382610389565b905051906102e38261039c565b9190604083820312610287576102ad90602061116d8286611137565b9401611144565b6111a66102e39461119c606094989795611192608086019a5f870152565b60208501906102c6565b60408301906102c6565b019015159052565b6040513d5f823e3d90fd5b6111c66102ad6102ad9290565b60ff1690565b906102cf90610294565b93959491926111e361108d565b506111ec61108d565b965f5b816111f9826110d8565b10156113a95760048660408661122c61075061122661122161121a896110d8565b8a8c6110e8565b6110f8565b86610713565b938b61123f61123a8761112e565b61112e565b9161127f8c61124d60405190565b978896879586957f409d653d000000000000000000000000000000000000000000000000000000005b87528601611174565b03915afa5f9182919081611376575b506112a5575050506112a0905b6110c2565b6111ef565b8b6112af5f6111b9565b60ff861614801561136f575b1561132b576080015182115b6112d8575b5050506112a0906110c2565b6112a0939b5090611301611322926112f86112f161105d565b95866111cc565b602085016111cc565b61130e87604085016111cc565b61131b89606085016111cc565b6080830152565b98905f806112cc565b506113355f610b10565b82141580156112c7575060808c0180516113556113515f610b10565b9190565b14908115611364575b506112c7565b51905082105f61135e565b50886112bb565b90925061139a915060403d81116113a2575b61139281836105ca565b810190611151565b90915f61128e565b503d611388565b50505050505050565b905b5f5260205260405f2090565b6102ad9081565b6102ad90546113c0565b60016113e86102ad926113e15f90565b505f6113b2565b016113c7565b906102e3916114046113ff826113d1565b61244f565b906102e39161247a565b906102e3916113ee565b61144a611446335b7f339759585899103d2ace64958e37e18ccb0504652c81d4a1b8aa80fe2126ab95611c79565b1590565b611457576102e39061151f565b7f710bcc40000000000000000000000000000000000000000000000000000000005f90815260045b035ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b81156114ba570490565b611483565b9081526040810192916102e39160200152565b0152565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff905b9181191691161790565b906115146102ad61151b92610b10565b82546114d6565b9055565b611527610d7c565b61153d6102ad611537600a610b10565b836114b0565b821161159557507f4bb8a6184424e4bb853a4836042f5a726e4e710873989bfc6abdab19966f5b709061157060016113c7565b61157b826001611504565b61159061158760405190565b928392836114bf565b0390a1565b5f916115ae61147f926115a8600a610b10565b906114b0565b907f38c7b9ea000000000000000000000000000000000000000000000000000000008452600484016114bf565b6102e390611418565b156115eb57565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c660000000000000000000000000000000000606482015280608481015b0390fd5b6102e3919061169a61168b33610294565b610294565b61169484610294565b146115e4565b6124f2565b6116ab61144633611420565b611457576102e39061185b565b818102929181159184041417156110d357565b919060086114fa9102916116fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff841b90565b921b90565b91906117146102ad61151b93610b10565b9083546116cb565b6102e3915f91611703565b818110611732575050565b8061173f5f60019361171c565b01611727565b91909182821061175457505050565b6102e3929161176790915f5260205f2090565b9182019101611727565b9068010000000000000000811161060a578161178e6102e3935490565b90828155611745565b6102ad9051610294565b81519167ffffffffffffffff831161060a576117d66117cc6001926117c68686611771565b60200190565b925f5260205f2090565b9204915f5b8381106117e85750505050565b60019060206117f96102ad86611797565b94019381840155016117db565b906102e3916117a1565b9061181f610e41610e37845190565b905f5b81811061182f5750505090565b909192611842610e6e6001928651610e7d565b929101611822565b60208082526102ad92910190611810565b6115907febf7325f48e05e5e38809c69f8b02a7c907ed31d8768e6c2d841b1296a9225fe9161188b816004611806565b6040519182918261184a565b6102e39061169f565b90949293916040915f966118bd61123a806107505f9a6004610713565b916118fd6118ca60405190565b968795869485947f409d653d00000000000000000000000000000000000000000000000000000000865260048601611174565b03915afa805f80939092611937575b50611931575050600161191b57565b9150506119275f610adb565b906113515f610b10565b93509150565b909250611953915060403d6040116113a25761139281836105ca565b915f61190c565b9061196f93929161196961108d565b50612579565b5090565b6102e3907f339759585899103d2ace64958e37e18ccb0504652c81d4a1b8aa80fe2126ab9561140e565b919392914285106119b457906102e39394916119e5565b7f83f2ba20000000000000000000000000000000000000000000000000000000005f90815261147f428760046114bf565b6119f29392503390612910565b50565b906102e393929161199d565b919392914285106119b457906102e3939491611a81565b356102ad81610389565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe13682900301821215610287570180359067ffffffffffffffff82116102875760200191602082023603831361028757565b356102ad8161039c565b9392915083611a926102ad82611a18565b3403611b69575060408401611ac1611abc611aad8388611a22565b611ab65f610b10565b916110e8565b611a77565b611af3611aed7f0000000000000000000000000000000000000000000000000000000000000000610294565b91610294565b03611b20575083611b11611b0c5f6119f2969701611a18565b613128565b611b1a3061112e565b90612910565b61147f611b3d611abc611b345f9489611a22565b611ab686610b10565b7f1c4f4020000000000000000000000000000000000000000000000000000000008352600483016102d3565b61147f611b765f92611a18565b7f1791902400000000000000000000000000000000000000000000000000000000835234600484016114bf565b906102e3939291611a01565b90611bbc61144633611420565b611457576102e391611bcd5f610b10565b8214611c1e57611c19611c0f8261123a85611c087f8c1256b8896378cd5044f80c202f9772b9d77dc85c8a6eb51967210b09bfaa289661112e565b33906131fa565b9261051e60405190565b0390a2565b7faba3a548000000000000000000000000000000000000000000000000000000005f908152600490fd5b906102e391611baf565b6102e39033610597565b906113b49061112e565b6102ad906111c6565b6102ad9054611c66565b6102ad915f611c93611c9993611c8c5f90565b50826113b2565b01611c5c565b611c6f565b949290979695939160e08601985f8701611cb7916102c6565b60208601611cc4916102c6565b6040850152606084015260ff16608083015260a082015260c00152565b95909294939193611d0161123a61123a611abc611aad60408c018c611a22565b611d0a3061112e565b92611d1489611a18565b90823b15610287575f94611d6286928a96611d2e60405190565b998a98899788967fd505accf0000000000000000000000000000000000000000000000000000000088523360048901611c9e565b03925af19081611d98575b50611d8f57611d7d565b50505050565b611d8693612185565b5f808080611d77565b6102e393612185565b611daf905f611da781836105ca565b81019061027d565b5f611d6d565b611dc161144633611420565b611457576102e390611dec565b3d15611de757611ddd3d610b88565b903d5f602084013e565b606090565b611df55f610b10565b8114611c1e57611e1c5f80611e0960405190565b5f9085335af1611e17611dce565b501590565b611e50577f8c1256b8896378cd5044f80c202f9772b9d77dc85c8a6eb51967210b09bfaa28611c19611c0f61123a5f610adb565b7fb12d13eb000000000000000000000000000000000000000000000000000000005f908152600490fd5b6102e390611db5565b95909294939193611ea361123a61123a611abc611aad60408c018c611a22565b611eac3061112e565b92611eb689611a18565b90823b15610287575f94611ed086928a96611d2e60405190565b03925af19081611ef2575b50611ee957611d86936119f5565b6102e3936119f5565b611f01905f611da781836105ca565b5f611edb565b611f1361144633611420565b611457576102e390611f80565b6102ad90610294565b6102ad9054611f20565b9073ffffffffffffffffffffffffffffffffffffffff906114fa565b90611f5f6102ad61151b9261112e565b8254611f33565b9160206102e39294936107e460408201965f8301906102c6565b611f8c6116865f610adb565b611f9582610294565b14611ff1577fb2c853ac4d80d18d058c43d8018d077a036e542a79acae1647f5ad2a8c76f4e290611fd1611fc96002611f29565b916002611f4f565b611fdb6002611f29565b90611590611fe860405190565b92839283611f66565b7f9fabe1c1000000000000000000000000000000000000000000000000000000005f908152600490fd5b6102e390611f07565b61203061144633611420565b611457576102e3906115907f658ff1688002926d8f426cb10c052ec29003f50042df9652d8613484c1a586479161188b816003611806565b6102e390612024565b919392914285106119b457906102e3939491612095565b919082039182116110d357565b9150604082016120d0611abc6120ab8386611a22565b611ab66120c06120bb878a611a22565b905090565b6120ca6001610b10565b90612088565b6120fc611aed7f0000000000000000000000000000000000000000000000000000000000000000610294565b0361213257506102e3929161211c916121143061112e565b913390612910565b61212581613242565b61212d610ae4565b6132be565b61147f612159611abc8584611ab66120c06120bb6121515f9986611a22565b949095611a22565b7f4f157e96000000000000000000000000000000000000000000000000000000008352600483016102d3565b906102e3939291612071565b906102e3916121a26113ff826113d1565b906102e3916124f2565b906102e391612191565b6102e3907f339759585899103d2ace64958e37e18ccb0504652c81d4a1b8aa80fe2126ab956121ac565b6121e861105d565b906060825260208080808086016060815201606081520160608152016060905250565b6102ad6121e0565b919082018092116110d357565b90610b9561064b83610623565b369037565b906102e361224861224284612220565b93610623565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0016020840161222d565b9061227c825190565b811015610733576020809102010190565b6102ad5f610b88565b9594929093946122a461220b565b506122ae5f610b10565b8614801561241f575b6123f05783156123e7576122cc855b8861333a565b946003976122d960035490565b956122f36122ee6122e8875190565b89612213565b612232565b975f998a5b8981101561233057806123258c8f8361231a61075061232b9761232094610713565b92612273565b6111cc565b60010190565b6122f8565b50919395979a50919395985b6123476102ad895190565b81101561238157806123258c6123206123768461237061236b8f9861237c99612273565b611797565b93612213565b8d612273565b61233c565b5091939690929498506123ac95506102ad9761239c5f610b10565b976123a689612232565b96613360565b906123bc6102ad60208401515190565b03613792576123d06123cc61228d565b8252565b6123e26123db61228d565b6040830152565b613792565b6122cc836122c6565b7f73f24386000000000000000000000000000000000000000000000000000000005f9081526004879052602490fd5b5061242a6005610b10565b8610156122b7565b6102e390339061244a612443610b1d565b918261140e565b611675565b6102e39033906138a0565b9060ff906114fa565b906124736102ad61151b92151590565b825461245a565b6124876114468383611c79565b61248f575050565b6124a860016124a3845f611c9386826113b2565b612463565b6124c26124bc6124b6339390565b9361112e565b9161112e565b917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d6124ed60405190565b5f90a4565b6124fc8282611c79565b612504575050565b6125175f6124a38482611c9386826113b2565b6125256124bc6124b6339390565b917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b6124ed60405190565b9091606082840312610287576102ad6125698484611137565b93604061116d8260208701611144565b9190939261258561108d565b945f956004612592815490565b965f5b885b6125a0826110d8565b101561285657866125b46107508386610713565b6060876125c361123a8461112e565b8c886125ff8d6125d260405190565b988996879586957ffe6cd70d00000000000000000000000000000000000000000000000000000000611276565b03915afa5f928391829181612823575b5061275a57505090508760408761262861123a8561112e565b8c886126378d61124d60405190565b03915afa5f9182919081612737575b506126675750505061266061259791600161129b576110c2565b9050612595565b6126705f6111b9565b60ff8516148015612730575b156126f15761268f6102ad608089015190565b82115b6126a6575b505050612660612597916110c2565b6126d9939c506126bf91929496506112f86112f161105d565b6126cc86604085016111cc565b61131b88606085016111cc565b916125976126606126e95f610adb565b9a915f612697565b6126fa5f610b10565b821415801561269257506080870180516127166113515f610b10565b14908115612725575b50612692565b51905082105f61271f565b508861267c565b909250612752915060403d81116113a25761139281836105ca565b90915f612646565b6127635f6111b9565b60ff861614801561281c575b156127dd576127826102ad60808a015190565b82115b61279a575b50505050612660612597916110c2565b612597949d50612660939750906127b96127d3926112f86112f161105d565b6127c689604085016111cc565b61131b8b606085016111cc565b949a915f8061278a565b6127e65f610b10565b821415801561278557506080880180516128026113515f610b10565b14908115612811575b50612785565b51905082105f61280b565b508961276f565b91509350612848915060603d811161284f575b61284081836105ca565b810190612550565b935f61260f565b503d612836565b5096505093505050509190565b90602082820312610287576102ad91611137565b6102cf90610b10565b909594926102e3946128b76107e4926128ad6080966128a360a088019c5f890152565b6020870190612877565b60408501906102c6565b60608301906102c6565b91946129066107e4929897956128fc60a0966128f26102e39a6128e860c08a019e5f8b0152565b6020890190612877565b60408701906102c6565b60608501906102c6565b60808301906102c6565b92939291905f9461292a6120c06120bb6040870187611a22565b6129406113516102ad6120bb6060890189611a22565b141580156130fa575b80156130a1575b6130775761295d84611a18565b926129675f610b10565b8111801561305a575b613003575b506129d461299261123a61123a611abc611aad60408a018a611a22565b926370a0823194602060808801956129b0611abc611aad898c611a22565b906129ba60405190565b80809781946129c98d60e01b90565b8352600483016102d3565b03915afa908115612cfc57612a60935f92612fe0575b508192612a1c9250612a05611abc611aad60408c018c611a22565b90612a16611abc611aad8a8d611a22565b916139b2565b6020612a3761123a61123a611abc611aad60408c018c611a22565b612a47611abc611aad888b611a22565b90612a5160405190565b80809681946129c98c60e01b90565b03915afa8015612cfc57612a7b925f91612fc7575b50612088565b95612aa2611abc612a8f6040880188611a22565b611ab66120c06120bb60408c018c611a22565b95612ab36120bb6060880188611a22565b91975b82891015612f055786908986612ad86102ad612ad26001610b10565b88612088565b821015612eea5761123a611abc612b3493611ab6612b21612b15611abc612b0261123a988c611a22565b611ab6612b0f6001610b10565b88612213565b985b6040810190611a22565b919092612b2e6001610b10565b90612213565b916020612b4060405190565b8094612b4c8b60e01b90565b82528180612b5d86600483016102d3565b03915afa928315612cfc575f93612eca575b508a60a08a0192612b836120bb858d611a22565b612b8f6113515f610b10565b1182858d83612e9e575b5050505f14612e1a578a612bfb611abc612bc961123a61123a611abc88612bc36060890189611a22565b906110e8565b94612bc3612be1611abc83612bc36040890189611a22565b98612bf5611abc612b026040890189611a22565b95611a22565b90833b1561028757848f96945f928f968490612c4e612c1960405190565b978896879586947f230f11c7000000000000000000000000000000000000000000000000000000008652868d600488016128c1565b03925af19081612e05575b50612de557612d01565b5090612c8861123a61123a611abc612ca296611ab6612b216020986040810190611a22565b6129c98a612c9560405190565b9586948593849360e01b90565b03915afa918215612cfc57612cc892612cc1925f91612cce5750612088565b9860010190565b97612ab6565b612cef915060203d8111612cf5575b612ce781836105ca565b810190612863565b5f612a75565b503d612cdd565b6111ae565b90612d48611abc612d2261123a61123a611abc89612bc36060890189611a22565b95611ab6612b21612d3d611abc84612bc360408a018a611a22565b956040810190611a22565b93803b15610287575f808094612d9487612d6160405190565b998a97889687957feab90da600000000000000000000000000000000000000000000000000000000875260048701612880565b03925af1908115612cfc57612c8861123a61123a611abc8f611ab68f612b2190612ca29a60209a612dd0575b5097985050509650505050612c63565b612ddf905f611da781836105ca565b5f612dc0565b5090612c8861123a61123a611abc612ca296611ab6612b21602098612b17565b612e14905f611da781836105ca565b5f612c59565b90925089612e3e611abc612d2261123a61123a611abc89612bc36060890189611a22565b93803b15610287575f808094612e5787612d6160405190565b03925af1908115612cfc57612c8861123a61123a611abc8f611ab68f612b2190612ca29a60209a612e89575b50612b17565b612e98905f611da781836105ca565b5f612e83565b612eb19350611abc9291612bc391611a22565b612ec0611aed6116865f610adb565b141582858d612b99565b612ee391935060203d8111612cf557612ce781836105ca565b915f612b6f565b5061123a61123a611abc612b3493611ab6612b218b98612b17565b969450965050505060208201612f1d6102ad82611a18565b8410612f8c57507f9fc8352e52998db4087d5e6e1c1aafa38788e749e5d7a24f5cb230f73795440283612f796124b6612f735f612f6c611abc612f6360408b018b611a22565b611ab685610b10565b9701611a18565b9561112e565b93612f8661158760405190565b0390a390565b61147f84612f9a5f93611a18565b907fd28d3eb5000000000000000000000000000000000000000000000000000000008452600484016114bf565b612cef915060203d602011612cf557612ce781836105ca565b612a1c9250612ffd9060203d602011612cf557612ce781836105ca565b916129ea565b8493506130549061301c9061301786611a18565b61393e565b80948461304e613035611abc611aad60408c018c611a22565b936130496130436002611f29565b94611a18565b612088565b926139b2565b5f612975565b5061306560016113c7565b6130716113515f610b10565b11612970565b7f454b6c9a000000000000000000000000000000000000000000000000000000005f908152600490fd5b5060a084016130b36120bb8287611a22565b6130bf6113515f610b10565b1190816130cd575b50612950565b6130dc91506120bb9086611a22565b6130f26113516102ad6120bb6060890189611a22565b14155f6130c7565b5061310b6120bb6080860186611a22565b6131216113516102ad6120bb6060890189611a22565b1415612949565b61315461123a7f000000000000000000000000000000000000000000000000000000000000000061112e565b63d0e30db0813b15610287575f9161317a9161316f60405190565b948593849260e01b90565b825281600481015b03925af18015612cfc576131935750565b6102e3905f611da781836105ca565b6131bb6131b56102ad9263ffffffff1690565b60e01b90565b7fffffffff000000000000000000000000000000000000000000000000000000001690565b9160206102e39294936114d260408201965f8301906102c6565b61323d60049261322e6102e39561321463a9059cbb6131a2565b9261321e60405190565b96879460208601908152016131e0565b602082018103825203836105ca565b613b04565b61326e61123a7f000000000000000000000000000000000000000000000000000000000000000061112e565b803b15610287576131825f9291839261328660405190565b94859384928391907f2e1a7d4d0000000000000000000000000000000000000000000000000000000083526004830190815260200190565b6132c73061112e565b6132d3611aed85610294565b036132dd57505050565b6132e8611686610ae4565b6132f182610294565b0361332857505f809161330961123a6133229561112e565b9061331360405190565b90818003925af1611e17611dce565b611e5057565b916133356102e39361112e565b6131fa565b9190604061335b61334961220b565b926133548496613b78565b8452613b78565b910152565b949290939695919561337061220b565b5061337a84613b93565b9384986133845f90565b9789888a9861339589848487612579565b91908860808201956133a5875190565b6133b16113515f610b10565b116136e9575b505050505050506001986133cb6001610b10565b8311806136b1575b6133e6575b505050505050505050505090565b808a5b6133f4575b506133d8565b6133ff6102ad885190565b8110156136ac57858a89878f8b8991845f1461368d5761342561168661236b8a85612273565b61342e87610294565b145b61367c5761343c61108d565b5084156136515761345b8561345461236b8b86612273565b888d612579565b9790613468608082015190565b915b6134735f610b10565b831461363d578715613615576134a18a8c8b61349b61236b61349488611797565b938b612273565b91613c04565b965b6134ad8289613c59565b613600576134bd6134c591613b93565b918298613db7565b9888156135b757505061351598816134e15f6135029401611797565b906134fa60606134f360208401611797565b9201611797565b91858a613d47565b61350f61236b8a85612273565b90613360565b881561359c578c61352b611aed61168684613e51565b145b61353d575b506001015b8a6133e9565b881561358e5761354c81613e74565b6135555f610b10565b8b148015613577575b613569575b50613532565b909d5098506135375f613563565b508915613586578a811161355e565b8a811061355e565b61359781613e68565b61354c565b6135a861168682613e34565b6135b18c610294565b1461352d565b6135fb9a9197509293506135e8916135ce81611797565b906135e060406134f360208401611797565b91868a613cd8565b6135f561236b8a85612273565b91613360565b613515565b50505050505050505050506135379060010190565b6136378a858d61363161236b61362a88611797565b928b612273565b90613c04565b966134a3565b505050505050505050506135379060010190565b613669858261366361236b8c87612273565b8d612579565b9790613676608082015190565b9161346a565b505050505050506135379060010190565b61369d61168661236b8a85612273565b6136a682610294565b14613430565b6133ee565b506136c96136c160208601515190565b6115a8610c92565b6136e26113516102ad6136dc6002610b10565b87612088565b11156133d3565b61370c9161370786611446935f8701996137028b611797565b613c04565b613c59565b61371b575b8c9350888f6133b7565b613760959b508a5f1461376b5761375c9361373d613737875190565b91611797565b90613756606061374f60208601611797565b9401611797565b93613d47565b5190565b955f80808080613711565b61375c9361377a613737875190565b9061378c604061374f60208601611797565b93613cd8565b61379a61220b565b506102ad6137aa5f830151613e80565b9161131b6137bb6020830151613f03565b916138086137cc6040830151613f03565b6138016137e960806137e16060870151613f03565b950151613f03565b956137fa6137f561105d565b998a52565b6020890152565b6040870152565b6060850152565b6102ad90610b10565b610b846138309260209261382a815190565b94859290565b93849101610be5565b6138776102ad9392613871613871937f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260170190565b90613818565b7f206973206d697373696e6720726f6c6520000000000000000000000000000000815260110190565b906138ae6114468284611c79565b6138b6575050565b6139006102ad611671936138e86138d86138d261390c96613f8e565b9261380f565b6138e26020610b10565b90614080565b906138f260405190565b938492602084019283613839565b908103825203826105ca565b6040519182917f08c379a000000000000000000000000000000000000000000000000000000000835260048301610c42565b61394b6102ad60016113c7565b821061397657906139716102ad9261396b613964610d7c565b9384612088565b906116b8565b6114b0565b5f61147f8361398560016113c7565b907fa458261b000000000000000000000000000000000000000000000000000000008452600484016114bf565b9291906139c16116863061112e565b6139ca82610294565b146139e0576139db6102e39461112e565b6141e5565b506133356102e39361112e565b156139f457565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815280611671600482016020808252818101527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564604082015260600190565b905051906102e3826103e2565b90602082820312610287576102ad91613a57565b15613a7f57565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608490fd5b5f91613b10839261112e565b82602083519301915af1613b2b613b25611dce565b916139ed565b8051613b396113515f610b10565b11613b415750565b613b5d816020613b526102e3945190565b818301019101613a64565b613a78565b906102e3612248613b7284610b88565b93610b49565b90613b8b613b866020610b10565b613b62565b916020830152565b613b9b61220b565b506102ad5f8201519161131b602082015191613808604082015161380160806060850151940151956137fa6137f561105d565b613bda6102cf91610294565b60601b90565b92613bfc6014610b8494613bfc8288613bfc829b9a8399613bce565b018092613bce565b613c399291613c1283610294565b613c1b82610294565b1015613c4f576139009092945b604051958694602086019485613be0565b613c4b613c44825190565b9160200190565b2090565b9361390090613c28565b613c625f610b10565b613c6d6102ad845190565b811015613c9757613c8161375c8285612273565b8214613c8f57600101613c62565b505050600190565b5050505f90565b613871906102ad9392613818565b613ccc92916102e391613cbe60405190565b948592602084019283613c9e565b908103825203836105ca565b9490608093613d1e613d2c92613d0e613d3c96613cf76102cf9a613b78565b613d0760408d0191825190613cac565b9052613b78565b613d0760208b0191825190613cac565b87518891613d079190613cac565b613d076060870191825190613cac565b920191825190613cac565b9190608093916102cf95613d6a6040860191613d64835191613b78565b90613cac565b9052613d7f6020850191613d64835191613b78565b9052613d935f840191613d64835191613b78565b9052613da86060830191613d64835191613b78565b90520191613d64835191613b78565b815191613dcd6122ee600194612b2e6001610b10565b9280613dd85f610b10565b905b613df9575b505090613df6613df06102ad935190565b84612273565b52565b613e046102ad845190565b811015613e2f5780612325613e1f61375c613e299487612273565b613df68389612273565b81613dda565b613ddf565b60406102ad91613e415f90565b500151613e4c610c92565b015190565b60406102ad91613e5e5f90565b5001518051015190565b5f6102ad91613e415f90565b5f6102ad91613e5e5f90565b90815191613e966122ee6020946115a886610b10565b9283613ea15f610b10565b613eb86102ad613eaf865190565b6115a886610b10565b811015613efc57613ef790612325613eed613ee7613ede613ed888610b10565b856116b8565b612b2e88610b10565b87015190565b613df6838a612273565b613ea1565b5093505050565b90815191613f196122ee6020946115a886610b10565b9283613f245f610b10565b613f326102ad613eaf865190565b811015613efc57613f5c90612325613f52613ee7613ede613ed888610b10565b612320838a612273565b613f24565b6102ad6102ad6102ad9273ffffffffffffffffffffffffffffffffffffffff1690565b6102ad60146111b9565b613fab613fa66102ad92613fa0606090565b50611125565b613f61565b6138e2613fb6613f84565b6110d8565b90613fc4825190565b811015610733570160200190565b80156110d3577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b6102ad906140116113516102ad9460ff1690565b901c90565b1561401d57565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815280611671600482016020808252818101527f537472696e67733a20686578206c656e67746820696e73756666696369656e74604082015260600190565b6140a3613b86614099846140946002610b10565b6116b8565b612b2e6002610b10565b9160306140b86140b25f610b10565b85613fbb565b537f780000000000000000000000000000000000000000000000000000000000000061410d61410460019384935f1a6140f96140f386610b10565b89613fbb565b536140946002610b10565b612b2e83610b10565b915b614130575b5050906102ad6102ad9261412a6113515f610b10565b14614016565b909161413b82610b10565b8311156141b6577f303132333435363738396162636465660000000000000000000000000000000061416d600f610b10565b821690601082101561073357839261418d6141aa926141b0941a60f81b90565b5f1a6141998789613fbb565b536141a460046111b9565b90613ffd565b93613fd2565b9161410f565b91614114565b6040906114d26102e394969593966141db60608401985f8501906102c6565b60208301906102c6565b9061323d9061322e6102e3956004956142016323b872dd6131a2565b9361420b60405190565b97889560208701908152016141bc56fea2646970667358221220575e7d2416d18ff2bf2ce8b3cf20997bf0c80ed664a436fc3bfbf02d1b43b0c164736f6c634300081e0033339759585899103d2ace64958e37e18ccb0504652c81d4a1b8aa80fe2126ab950000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000010000000000000000000000000001bb7b44cc398aaa2b76ac6253f0f5634279db9d00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab10000000000000000000000000000000000000000000000000000000000000003000000000000000000000000abc401a16595077881964683450ad63ab3688dab0000000000000000000000001486882e02e6a1037da6afc324b2f911f4c893a000000000000000000000000064c0861a141a7f80ac0b3a32312acad3c62947f3000000000000000000000000000000000000000000000000000000000000000700000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab10000000000000000000000002f2a2543b76a4166549f7aab2e75bef0aefc5b0f000000000000000000000000af88d065e77c8cc2239327c5edb3a432268e5831000000000000000000000000ff970a61a04b1ca14834a43f5de4533ebddb5cc8000000000000000000000000912ce59144191c1204e64559fe8253a0e49e6548000000000000000000000000fd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9000000000000000000000000da10009cbd5d07dd0cecc66161fc93d7c9000da1
Deployed Bytecode
0x6080604052600436101561001a575b3615610018575f80fd5b005b5f3560e01c8062b99e361461027857806301ffc9a714610273578063243f8bfc1461026e578063248a9ca3146102695780632f2ff15d1461026457806331ac99201461025f57806336568abe1461025a5780633a9a40811461025557806352a52ab01461025057806356ca76b41461024b578063645d916b146102465780636b453c1f1461024157806375c834b51461023c57806376c7a3c71461023757806376ebe69c1461023257806377d007f71461022d5780637c7a561b146102285780638980f11f146102235780638bb9c5bf1461021e57806391d1485414610219578063952e901214610214578063974584601461020f578063a0cf0aea1461020a578063a217fddf14610205578063a3f4df7e14610200578063aede3693146101fb578063b0873e5e146101f6578063b381cf40146101f1578063b5ce5649146101ec578063c3accd48146101e7578063c8a3a5c6146101e2578063cc299d4f146101dd578063d547741f146101d8578063d73792a9146101d3578063d8baf7cf146101ce578063db6a5897146101c9578063f2fde38b146101c45763f87422540361000e57610f88565b610f70565b610f42565b610daa565b610d8f565b610d63565b610d47565b610d2f565b610d17565b610cf8565b610cbf565b610ca4565b610c7a565b610c53565b610b2e565b610af5565b610aaf565b610a22565b6109ee565b6109d6565b6109bd565b61097e565b610967565b61094b565b610930565b6108f3565b610885565b610852565b6107eb565b610756565b6106ce565b610584565b61056c565b61054e565b6104ff565b6104bd565b61035c565b6102e5565b5f91031261028757565b5f80fd5b6102ad916008021c5b73ffffffffffffffffffffffffffffffffffffffff1690565b90565b906102ad915461028b565b6102ad5f60026102b0565b6102cf90610294565b9052565b6020810192916102e391906102c6565b565b34610287576102f536600461027d565b61030c6103006102bb565b604051918291826102d3565b0390f35b7fffffffff0000000000000000000000000000000000000000000000000000000081165b0361028757565b905035906102e382610310565b90602082820312610287576102ad9161033b565b346102875761030c610377610372366004610348565b610fc1565b60405191829182901515815260200190565b80610334565b905035906102e382610389565b61033481610294565b905035906102e38261039c565b909182601f830112156102875781359167ffffffffffffffff831161028757602001926020830284011161028757565b801515610334565b905035906102e3826103e2565b9160a0838303126102875761040c828461038f565b9261041a83602083016103a5565b9261042881604084016103a5565b92606083013567ffffffffffffffff8111610287578261044f6080946102ad9387016103b2565b949095016103ea565b906080806102e3936104705f8201515f8601906102c6565b610482602082015160208601906102c6565b610494604082015160408601906102c6565b6104a6606082015160608601906102c6565b0151910152565b60a0810192916102e39190610458565b346102875761030c6104df6104d33660046103f7565b949390939291926111d6565b604051918291826104ad565b90602082820312610287576102ad9161038f565b346102875761030c61051a6105153660046104eb565b6113d1565b6040515b9182918290815260200190565b9190604083820312610287576102ad906020610547828661038f565b94016103a5565b346102875761056761056136600461052b565b9061140e565b604051005b346102875761056761057f3660046104eb565b6115db565b346102875761056761059736600461052b565b90611675565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b90601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810190811067ffffffffffffffff82111761060a57604052565b61059d565b906102e361061c60405190565b92836105ca565b67ffffffffffffffff811161060a5760208091020190565b9092919261065061064b82610623565b61060f565b938185526020808601920283019281841161028757915b8383106106745750505050565b6020809161068284866103a5565b815201920191610667565b9080601f83011215610287578160206102ad9335910161063b565b9060208282031261028757813567ffffffffffffffff8111610287576102ad920161068d565b34610287576105676106e13660046106a8565b611897565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b80548210156107335761072b6001915f5260205f2090565b910201905f90565b6106e6565b600354811015610287576107506102ad916003610713565b906102b0565b346102875761030c61030061076c3660046104eb565b610738565b60ff8116610334565b905035906102e382610771565b919060a0838203126102875761079d818461038f565b926107ab82602083016103a5565b926102ad6107bc84604085016103a5565b9360806107cc826060870161077a565b94016103ea565b9081526040810192916102e3916020905b01906102c6565b34610287576108076107fe366004610787565b939290926118a0565b9061030c61081460405190565b928392836107d3565b60808183031261028757610831828261038f565b926102ad61084284602085016103a5565b9360606107cc82604087016103a5565b346102875761030c6104df61086836600461081d565b9291909161195a565b90602082820312610287576102ad916103a5565b3461028757610567610898366004610871565b611973565b908160c09103126102875790565b60808183031261028757803567ffffffffffffffff811161028757826108d291830161089d565b926102ad6108e3846020850161038f565b936060610547826040870161038f565b34610287576105676109063660046108ab565b929190916119f5565b6102ad916008021c81565b906102ad915461090f565b6102ad5f600161091a565b346102875761094036600461027d565b61030c61051a610925565b346102875761095b36600461027d565b61030c61051a60035490565b6105676109753660046108ab565b92919091611ba3565b346102875761098e36600461027d565b61030c61051a60045490565b9190604083820312610287576102ad9060206109b682866103a5565b940161038f565b34610287576105676109d036600461099a565b90611c48565b34610287576105676109e93660046104eb565b611c52565b346102875761030c610377610a0436600461052b565b90611c79565b600454811015610287576107506102ad916004610713565b346102875761030c610300610a383660046104eb565b610a0a565b60e08183031261028757803567ffffffffffffffff81116102875782610a6491830161089d565b92610a72836020840161038f565b92610a80816040850161038f565b92610a8e82606083016103a5565b926102ad610a9f846080850161077a565b9360c06109b68260a0870161038f565b3461028757610567610ac2366004610a3d565b95949094939193611ce1565b6102946102ad6102ad9290565b6102ad90610ace565b6102ad5f610adb565b6102ad610ae4565b3461028757610b0536600461027d565b61030c610300610aed565b6102ad6102ad6102ad9290565b6102ad5f610b10565b6102ad610b1d565b3461028757610b3e36600461027d565b61030c61051a610b26565b67ffffffffffffffff811161060a57602090601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160190565b0190565b90610b9561064b83610b49565b918252565b610ba46010610b88565b7f43616d656c6f7459616b526f7574657200000000000000000000000000000000602082015290565b6102ad610b9a565b6102ad610bcd565b6102ad610bd5565b90825f9392825e0152565b610c11610c1a602093610b8493610c05815190565b80835293849260200190565b95869101610be5565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690565b60208082526102ad92910190610bf0565b3461028757610c6336600461027d565b61030c610c6e610bdd565b60405191829182610c42565b3461028757610567610c8d3660046104eb565b611e7a565b6102ad6020610b10565b6102ad610c92565b3461028757610cb436600461027d565b61030c61051a610c9c565b3461028757610ccf36600461027d565b61030c7f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab1610300565b3461028757610567610d0b366004610a3d565b95949094939193611e83565b3461028757610567610d2a366004610871565b61201b565b3461028757610567610d423660046106a8565b612068565b3461028757610567610d5a3660046108ab565b92919091612185565b3461028757610567610d7636600461052b565b906121ac565b6102ad612710610b10565b6102ad610d7c565b3461028757610d9f36600461027d565b61030c61051a610d87565b3461028757610567610dbd366004610871565b6121b6565b909160c08284031261028757610dd8838361038f565b92610de681602085016103a5565b92610df482604083016103a5565b92606082013567ffffffffffffffff811161028757610e18846102ad92850161068d565b9360a06107cc826080870161038f565b90610e48610e41610e37845190565b8084529260200190565b9260200190565b905f5b818110610e585750505090565b909192610e75610e6e6001928651815260200190565b9460200190565b929101610e4b565b90610b84816020936102c6565b90610e99610e41610e37845190565b905f5b818110610ea95750505090565b909192610ebc610e6e6001928651610e7d565b929101610e9c565b6102ad916080610f20610f0e610efc610eea60a086015f8801518782035f890152610e28565b60208701518682036020880152610e8a565b60408601518582036040870152610e8a565b60608501518482036060860152610e8a565b920151906080818403910152610e8a565b60208082526102ad92910190610ec4565b346102875761030c610f64610f58366004610dc2565b94939093929192612296565b60405191829182610f31565b3461028757610567610f83366004610871565b612432565b3461028757610f9836600461027d565b61030c7f339759585899103d2ace64958e37e18ccb0504652c81d4a1b8aa80fe2126ab9561051a565b7f7965db0b000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000821614908115611011575090565b6102ad91507fffffffff00000000000000000000000000000000000000000000000000000000167f01ffc9a7000000000000000000000000000000000000000000000000000000001490565b6102ad60a061060f565b61106f61105d565b905f825260208080808086015f8152015f8152015f8152015f905250565b6102ad611067565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b60ff1660ff81146110d35760010190565b611095565b6102ad6102ad6102ad9260ff1690565b9190811015610733576020020190565b356102ad81610771565b6102946102ad6102ad9273ffffffffffffffffffffffffffffffffffffffff1690565b6102ad90611102565b6102ad90611125565b905051906102e382610389565b905051906102e38261039c565b9190604083820312610287576102ad90602061116d8286611137565b9401611144565b6111a66102e39461119c606094989795611192608086019a5f870152565b60208501906102c6565b60408301906102c6565b019015159052565b6040513d5f823e3d90fd5b6111c66102ad6102ad9290565b60ff1690565b906102cf90610294565b93959491926111e361108d565b506111ec61108d565b965f5b816111f9826110d8565b10156113a95760048660408661122c61075061122661122161121a896110d8565b8a8c6110e8565b6110f8565b86610713565b938b61123f61123a8761112e565b61112e565b9161127f8c61124d60405190565b978896879586957f409d653d000000000000000000000000000000000000000000000000000000005b87528601611174565b03915afa5f9182919081611376575b506112a5575050506112a0905b6110c2565b6111ef565b8b6112af5f6111b9565b60ff861614801561136f575b1561132b576080015182115b6112d8575b5050506112a0906110c2565b6112a0939b5090611301611322926112f86112f161105d565b95866111cc565b602085016111cc565b61130e87604085016111cc565b61131b89606085016111cc565b6080830152565b98905f806112cc565b506113355f610b10565b82141580156112c7575060808c0180516113556113515f610b10565b9190565b14908115611364575b506112c7565b51905082105f61135e565b50886112bb565b90925061139a915060403d81116113a2575b61139281836105ca565b810190611151565b90915f61128e565b503d611388565b50505050505050565b905b5f5260205260405f2090565b6102ad9081565b6102ad90546113c0565b60016113e86102ad926113e15f90565b505f6113b2565b016113c7565b906102e3916114046113ff826113d1565b61244f565b906102e39161247a565b906102e3916113ee565b61144a611446335b7f339759585899103d2ace64958e37e18ccb0504652c81d4a1b8aa80fe2126ab95611c79565b1590565b611457576102e39061151f565b7f710bcc40000000000000000000000000000000000000000000000000000000005f90815260045b035ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b81156114ba570490565b611483565b9081526040810192916102e39160200152565b0152565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff905b9181191691161790565b906115146102ad61151b92610b10565b82546114d6565b9055565b611527610d7c565b61153d6102ad611537600a610b10565b836114b0565b821161159557507f4bb8a6184424e4bb853a4836042f5a726e4e710873989bfc6abdab19966f5b709061157060016113c7565b61157b826001611504565b61159061158760405190565b928392836114bf565b0390a1565b5f916115ae61147f926115a8600a610b10565b906114b0565b907f38c7b9ea000000000000000000000000000000000000000000000000000000008452600484016114bf565b6102e390611418565b156115eb57565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c660000000000000000000000000000000000606482015280608481015b0390fd5b6102e3919061169a61168b33610294565b610294565b61169484610294565b146115e4565b6124f2565b6116ab61144633611420565b611457576102e39061185b565b818102929181159184041417156110d357565b919060086114fa9102916116fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff841b90565b921b90565b91906117146102ad61151b93610b10565b9083546116cb565b6102e3915f91611703565b818110611732575050565b8061173f5f60019361171c565b01611727565b91909182821061175457505050565b6102e3929161176790915f5260205f2090565b9182019101611727565b9068010000000000000000811161060a578161178e6102e3935490565b90828155611745565b6102ad9051610294565b81519167ffffffffffffffff831161060a576117d66117cc6001926117c68686611771565b60200190565b925f5260205f2090565b9204915f5b8381106117e85750505050565b60019060206117f96102ad86611797565b94019381840155016117db565b906102e3916117a1565b9061181f610e41610e37845190565b905f5b81811061182f5750505090565b909192611842610e6e6001928651610e7d565b929101611822565b60208082526102ad92910190611810565b6115907febf7325f48e05e5e38809c69f8b02a7c907ed31d8768e6c2d841b1296a9225fe9161188b816004611806565b6040519182918261184a565b6102e39061169f565b90949293916040915f966118bd61123a806107505f9a6004610713565b916118fd6118ca60405190565b968795869485947f409d653d00000000000000000000000000000000000000000000000000000000865260048601611174565b03915afa805f80939092611937575b50611931575050600161191b57565b9150506119275f610adb565b906113515f610b10565b93509150565b909250611953915060403d6040116113a25761139281836105ca565b915f61190c565b9061196f93929161196961108d565b50612579565b5090565b6102e3907f339759585899103d2ace64958e37e18ccb0504652c81d4a1b8aa80fe2126ab9561140e565b919392914285106119b457906102e39394916119e5565b7f83f2ba20000000000000000000000000000000000000000000000000000000005f90815261147f428760046114bf565b6119f29392503390612910565b50565b906102e393929161199d565b919392914285106119b457906102e3939491611a81565b356102ad81610389565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe13682900301821215610287570180359067ffffffffffffffff82116102875760200191602082023603831361028757565b356102ad8161039c565b9392915083611a926102ad82611a18565b3403611b69575060408401611ac1611abc611aad8388611a22565b611ab65f610b10565b916110e8565b611a77565b611af3611aed7f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab1610294565b91610294565b03611b20575083611b11611b0c5f6119f2969701611a18565b613128565b611b1a3061112e565b90612910565b61147f611b3d611abc611b345f9489611a22565b611ab686610b10565b7f1c4f4020000000000000000000000000000000000000000000000000000000008352600483016102d3565b61147f611b765f92611a18565b7f1791902400000000000000000000000000000000000000000000000000000000835234600484016114bf565b906102e3939291611a01565b90611bbc61144633611420565b611457576102e391611bcd5f610b10565b8214611c1e57611c19611c0f8261123a85611c087f8c1256b8896378cd5044f80c202f9772b9d77dc85c8a6eb51967210b09bfaa289661112e565b33906131fa565b9261051e60405190565b0390a2565b7faba3a548000000000000000000000000000000000000000000000000000000005f908152600490fd5b906102e391611baf565b6102e39033610597565b906113b49061112e565b6102ad906111c6565b6102ad9054611c66565b6102ad915f611c93611c9993611c8c5f90565b50826113b2565b01611c5c565b611c6f565b949290979695939160e08601985f8701611cb7916102c6565b60208601611cc4916102c6565b6040850152606084015260ff16608083015260a082015260c00152565b95909294939193611d0161123a61123a611abc611aad60408c018c611a22565b611d0a3061112e565b92611d1489611a18565b90823b15610287575f94611d6286928a96611d2e60405190565b998a98899788967fd505accf0000000000000000000000000000000000000000000000000000000088523360048901611c9e565b03925af19081611d98575b50611d8f57611d7d565b50505050565b611d8693612185565b5f808080611d77565b6102e393612185565b611daf905f611da781836105ca565b81019061027d565b5f611d6d565b611dc161144633611420565b611457576102e390611dec565b3d15611de757611ddd3d610b88565b903d5f602084013e565b606090565b611df55f610b10565b8114611c1e57611e1c5f80611e0960405190565b5f9085335af1611e17611dce565b501590565b611e50577f8c1256b8896378cd5044f80c202f9772b9d77dc85c8a6eb51967210b09bfaa28611c19611c0f61123a5f610adb565b7fb12d13eb000000000000000000000000000000000000000000000000000000005f908152600490fd5b6102e390611db5565b95909294939193611ea361123a61123a611abc611aad60408c018c611a22565b611eac3061112e565b92611eb689611a18565b90823b15610287575f94611ed086928a96611d2e60405190565b03925af19081611ef2575b50611ee957611d86936119f5565b6102e3936119f5565b611f01905f611da781836105ca565b5f611edb565b611f1361144633611420565b611457576102e390611f80565b6102ad90610294565b6102ad9054611f20565b9073ffffffffffffffffffffffffffffffffffffffff906114fa565b90611f5f6102ad61151b9261112e565b8254611f33565b9160206102e39294936107e460408201965f8301906102c6565b611f8c6116865f610adb565b611f9582610294565b14611ff1577fb2c853ac4d80d18d058c43d8018d077a036e542a79acae1647f5ad2a8c76f4e290611fd1611fc96002611f29565b916002611f4f565b611fdb6002611f29565b90611590611fe860405190565b92839283611f66565b7f9fabe1c1000000000000000000000000000000000000000000000000000000005f908152600490fd5b6102e390611f07565b61203061144633611420565b611457576102e3906115907f658ff1688002926d8f426cb10c052ec29003f50042df9652d8613484c1a586479161188b816003611806565b6102e390612024565b919392914285106119b457906102e3939491612095565b919082039182116110d357565b9150604082016120d0611abc6120ab8386611a22565b611ab66120c06120bb878a611a22565b905090565b6120ca6001610b10565b90612088565b6120fc611aed7f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab1610294565b0361213257506102e3929161211c916121143061112e565b913390612910565b61212581613242565b61212d610ae4565b6132be565b61147f612159611abc8584611ab66120c06120bb6121515f9986611a22565b949095611a22565b7f4f157e96000000000000000000000000000000000000000000000000000000008352600483016102d3565b906102e3939291612071565b906102e3916121a26113ff826113d1565b906102e3916124f2565b906102e391612191565b6102e3907f339759585899103d2ace64958e37e18ccb0504652c81d4a1b8aa80fe2126ab956121ac565b6121e861105d565b906060825260208080808086016060815201606081520160608152016060905250565b6102ad6121e0565b919082018092116110d357565b90610b9561064b83610623565b369037565b906102e361224861224284612220565b93610623565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0016020840161222d565b9061227c825190565b811015610733576020809102010190565b6102ad5f610b88565b9594929093946122a461220b565b506122ae5f610b10565b8614801561241f575b6123f05783156123e7576122cc855b8861333a565b946003976122d960035490565b956122f36122ee6122e8875190565b89612213565b612232565b975f998a5b8981101561233057806123258c8f8361231a61075061232b9761232094610713565b92612273565b6111cc565b60010190565b6122f8565b50919395979a50919395985b6123476102ad895190565b81101561238157806123258c6123206123768461237061236b8f9861237c99612273565b611797565b93612213565b8d612273565b61233c565b5091939690929498506123ac95506102ad9761239c5f610b10565b976123a689612232565b96613360565b906123bc6102ad60208401515190565b03613792576123d06123cc61228d565b8252565b6123e26123db61228d565b6040830152565b613792565b6122cc836122c6565b7f73f24386000000000000000000000000000000000000000000000000000000005f9081526004879052602490fd5b5061242a6005610b10565b8610156122b7565b6102e390339061244a612443610b1d565b918261140e565b611675565b6102e39033906138a0565b9060ff906114fa565b906124736102ad61151b92151590565b825461245a565b6124876114468383611c79565b61248f575050565b6124a860016124a3845f611c9386826113b2565b612463565b6124c26124bc6124b6339390565b9361112e565b9161112e565b917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d6124ed60405190565b5f90a4565b6124fc8282611c79565b612504575050565b6125175f6124a38482611c9386826113b2565b6125256124bc6124b6339390565b917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b6124ed60405190565b9091606082840312610287576102ad6125698484611137565b93604061116d8260208701611144565b9190939261258561108d565b945f956004612592815490565b965f5b885b6125a0826110d8565b101561285657866125b46107508386610713565b6060876125c361123a8461112e565b8c886125ff8d6125d260405190565b988996879586957ffe6cd70d00000000000000000000000000000000000000000000000000000000611276565b03915afa5f928391829181612823575b5061275a57505090508760408761262861123a8561112e565b8c886126378d61124d60405190565b03915afa5f9182919081612737575b506126675750505061266061259791600161129b576110c2565b9050612595565b6126705f6111b9565b60ff8516148015612730575b156126f15761268f6102ad608089015190565b82115b6126a6575b505050612660612597916110c2565b6126d9939c506126bf91929496506112f86112f161105d565b6126cc86604085016111cc565b61131b88606085016111cc565b916125976126606126e95f610adb565b9a915f612697565b6126fa5f610b10565b821415801561269257506080870180516127166113515f610b10565b14908115612725575b50612692565b51905082105f61271f565b508861267c565b909250612752915060403d81116113a25761139281836105ca565b90915f612646565b6127635f6111b9565b60ff861614801561281c575b156127dd576127826102ad60808a015190565b82115b61279a575b50505050612660612597916110c2565b612597949d50612660939750906127b96127d3926112f86112f161105d565b6127c689604085016111cc565b61131b8b606085016111cc565b949a915f8061278a565b6127e65f610b10565b821415801561278557506080880180516128026113515f610b10565b14908115612811575b50612785565b51905082105f61280b565b508961276f565b91509350612848915060603d811161284f575b61284081836105ca565b810190612550565b935f61260f565b503d612836565b5096505093505050509190565b90602082820312610287576102ad91611137565b6102cf90610b10565b909594926102e3946128b76107e4926128ad6080966128a360a088019c5f890152565b6020870190612877565b60408501906102c6565b60608301906102c6565b91946129066107e4929897956128fc60a0966128f26102e39a6128e860c08a019e5f8b0152565b6020890190612877565b60408701906102c6565b60608501906102c6565b60808301906102c6565b92939291905f9461292a6120c06120bb6040870187611a22565b6129406113516102ad6120bb6060890189611a22565b141580156130fa575b80156130a1575b6130775761295d84611a18565b926129675f610b10565b8111801561305a575b613003575b506129d461299261123a61123a611abc611aad60408a018a611a22565b926370a0823194602060808801956129b0611abc611aad898c611a22565b906129ba60405190565b80809781946129c98d60e01b90565b8352600483016102d3565b03915afa908115612cfc57612a60935f92612fe0575b508192612a1c9250612a05611abc611aad60408c018c611a22565b90612a16611abc611aad8a8d611a22565b916139b2565b6020612a3761123a61123a611abc611aad60408c018c611a22565b612a47611abc611aad888b611a22565b90612a5160405190565b80809681946129c98c60e01b90565b03915afa8015612cfc57612a7b925f91612fc7575b50612088565b95612aa2611abc612a8f6040880188611a22565b611ab66120c06120bb60408c018c611a22565b95612ab36120bb6060880188611a22565b91975b82891015612f055786908986612ad86102ad612ad26001610b10565b88612088565b821015612eea5761123a611abc612b3493611ab6612b21612b15611abc612b0261123a988c611a22565b611ab6612b0f6001610b10565b88612213565b985b6040810190611a22565b919092612b2e6001610b10565b90612213565b916020612b4060405190565b8094612b4c8b60e01b90565b82528180612b5d86600483016102d3565b03915afa928315612cfc575f93612eca575b508a60a08a0192612b836120bb858d611a22565b612b8f6113515f610b10565b1182858d83612e9e575b5050505f14612e1a578a612bfb611abc612bc961123a61123a611abc88612bc36060890189611a22565b906110e8565b94612bc3612be1611abc83612bc36040890189611a22565b98612bf5611abc612b026040890189611a22565b95611a22565b90833b1561028757848f96945f928f968490612c4e612c1960405190565b978896879586947f230f11c7000000000000000000000000000000000000000000000000000000008652868d600488016128c1565b03925af19081612e05575b50612de557612d01565b5090612c8861123a61123a611abc612ca296611ab6612b216020986040810190611a22565b6129c98a612c9560405190565b9586948593849360e01b90565b03915afa918215612cfc57612cc892612cc1925f91612cce5750612088565b9860010190565b97612ab6565b612cef915060203d8111612cf5575b612ce781836105ca565b810190612863565b5f612a75565b503d612cdd565b6111ae565b90612d48611abc612d2261123a61123a611abc89612bc36060890189611a22565b95611ab6612b21612d3d611abc84612bc360408a018a611a22565b956040810190611a22565b93803b15610287575f808094612d9487612d6160405190565b998a97889687957feab90da600000000000000000000000000000000000000000000000000000000875260048701612880565b03925af1908115612cfc57612c8861123a61123a611abc8f611ab68f612b2190612ca29a60209a612dd0575b5097985050509650505050612c63565b612ddf905f611da781836105ca565b5f612dc0565b5090612c8861123a61123a611abc612ca296611ab6612b21602098612b17565b612e14905f611da781836105ca565b5f612c59565b90925089612e3e611abc612d2261123a61123a611abc89612bc36060890189611a22565b93803b15610287575f808094612e5787612d6160405190565b03925af1908115612cfc57612c8861123a61123a611abc8f611ab68f612b2190612ca29a60209a612e89575b50612b17565b612e98905f611da781836105ca565b5f612e83565b612eb19350611abc9291612bc391611a22565b612ec0611aed6116865f610adb565b141582858d612b99565b612ee391935060203d8111612cf557612ce781836105ca565b915f612b6f565b5061123a61123a611abc612b3493611ab6612b218b98612b17565b969450965050505060208201612f1d6102ad82611a18565b8410612f8c57507f9fc8352e52998db4087d5e6e1c1aafa38788e749e5d7a24f5cb230f73795440283612f796124b6612f735f612f6c611abc612f6360408b018b611a22565b611ab685610b10565b9701611a18565b9561112e565b93612f8661158760405190565b0390a390565b61147f84612f9a5f93611a18565b907fd28d3eb5000000000000000000000000000000000000000000000000000000008452600484016114bf565b612cef915060203d602011612cf557612ce781836105ca565b612a1c9250612ffd9060203d602011612cf557612ce781836105ca565b916129ea565b8493506130549061301c9061301786611a18565b61393e565b80948461304e613035611abc611aad60408c018c611a22565b936130496130436002611f29565b94611a18565b612088565b926139b2565b5f612975565b5061306560016113c7565b6130716113515f610b10565b11612970565b7f454b6c9a000000000000000000000000000000000000000000000000000000005f908152600490fd5b5060a084016130b36120bb8287611a22565b6130bf6113515f610b10565b1190816130cd575b50612950565b6130dc91506120bb9086611a22565b6130f26113516102ad6120bb6060890189611a22565b14155f6130c7565b5061310b6120bb6080860186611a22565b6131216113516102ad6120bb6060890189611a22565b1415612949565b61315461123a7f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab161112e565b63d0e30db0813b15610287575f9161317a9161316f60405190565b948593849260e01b90565b825281600481015b03925af18015612cfc576131935750565b6102e3905f611da781836105ca565b6131bb6131b56102ad9263ffffffff1690565b60e01b90565b7fffffffff000000000000000000000000000000000000000000000000000000001690565b9160206102e39294936114d260408201965f8301906102c6565b61323d60049261322e6102e39561321463a9059cbb6131a2565b9261321e60405190565b96879460208601908152016131e0565b602082018103825203836105ca565b613b04565b61326e61123a7f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab161112e565b803b15610287576131825f9291839261328660405190565b94859384928391907f2e1a7d4d0000000000000000000000000000000000000000000000000000000083526004830190815260200190565b6132c73061112e565b6132d3611aed85610294565b036132dd57505050565b6132e8611686610ae4565b6132f182610294565b0361332857505f809161330961123a6133229561112e565b9061331360405190565b90818003925af1611e17611dce565b611e5057565b916133356102e39361112e565b6131fa565b9190604061335b61334961220b565b926133548496613b78565b8452613b78565b910152565b949290939695919561337061220b565b5061337a84613b93565b9384986133845f90565b9789888a9861339589848487612579565b91908860808201956133a5875190565b6133b16113515f610b10565b116136e9575b505050505050506001986133cb6001610b10565b8311806136b1575b6133e6575b505050505050505050505090565b808a5b6133f4575b506133d8565b6133ff6102ad885190565b8110156136ac57858a89878f8b8991845f1461368d5761342561168661236b8a85612273565b61342e87610294565b145b61367c5761343c61108d565b5084156136515761345b8561345461236b8b86612273565b888d612579565b9790613468608082015190565b915b6134735f610b10565b831461363d578715613615576134a18a8c8b61349b61236b61349488611797565b938b612273565b91613c04565b965b6134ad8289613c59565b613600576134bd6134c591613b93565b918298613db7565b9888156135b757505061351598816134e15f6135029401611797565b906134fa60606134f360208401611797565b9201611797565b91858a613d47565b61350f61236b8a85612273565b90613360565b881561359c578c61352b611aed61168684613e51565b145b61353d575b506001015b8a6133e9565b881561358e5761354c81613e74565b6135555f610b10565b8b148015613577575b613569575b50613532565b909d5098506135375f613563565b508915613586578a811161355e565b8a811061355e565b61359781613e68565b61354c565b6135a861168682613e34565b6135b18c610294565b1461352d565b6135fb9a9197509293506135e8916135ce81611797565b906135e060406134f360208401611797565b91868a613cd8565b6135f561236b8a85612273565b91613360565b613515565b50505050505050505050506135379060010190565b6136378a858d61363161236b61362a88611797565b928b612273565b90613c04565b966134a3565b505050505050505050506135379060010190565b613669858261366361236b8c87612273565b8d612579565b9790613676608082015190565b9161346a565b505050505050506135379060010190565b61369d61168661236b8a85612273565b6136a682610294565b14613430565b6133ee565b506136c96136c160208601515190565b6115a8610c92565b6136e26113516102ad6136dc6002610b10565b87612088565b11156133d3565b61370c9161370786611446935f8701996137028b611797565b613c04565b613c59565b61371b575b8c9350888f6133b7565b613760959b508a5f1461376b5761375c9361373d613737875190565b91611797565b90613756606061374f60208601611797565b9401611797565b93613d47565b5190565b955f80808080613711565b61375c9361377a613737875190565b9061378c604061374f60208601611797565b93613cd8565b61379a61220b565b506102ad6137aa5f830151613e80565b9161131b6137bb6020830151613f03565b916138086137cc6040830151613f03565b6138016137e960806137e16060870151613f03565b950151613f03565b956137fa6137f561105d565b998a52565b6020890152565b6040870152565b6060850152565b6102ad90610b10565b610b846138309260209261382a815190565b94859290565b93849101610be5565b6138776102ad9392613871613871937f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260170190565b90613818565b7f206973206d697373696e6720726f6c6520000000000000000000000000000000815260110190565b906138ae6114468284611c79565b6138b6575050565b6139006102ad611671936138e86138d86138d261390c96613f8e565b9261380f565b6138e26020610b10565b90614080565b906138f260405190565b938492602084019283613839565b908103825203826105ca565b6040519182917f08c379a000000000000000000000000000000000000000000000000000000000835260048301610c42565b61394b6102ad60016113c7565b821061397657906139716102ad9261396b613964610d7c565b9384612088565b906116b8565b6114b0565b5f61147f8361398560016113c7565b907fa458261b000000000000000000000000000000000000000000000000000000008452600484016114bf565b9291906139c16116863061112e565b6139ca82610294565b146139e0576139db6102e39461112e565b6141e5565b506133356102e39361112e565b156139f457565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815280611671600482016020808252818101527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564604082015260600190565b905051906102e3826103e2565b90602082820312610287576102ad91613a57565b15613a7f57565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608490fd5b5f91613b10839261112e565b82602083519301915af1613b2b613b25611dce565b916139ed565b8051613b396113515f610b10565b11613b415750565b613b5d816020613b526102e3945190565b818301019101613a64565b613a78565b906102e3612248613b7284610b88565b93610b49565b90613b8b613b866020610b10565b613b62565b916020830152565b613b9b61220b565b506102ad5f8201519161131b602082015191613808604082015161380160806060850151940151956137fa6137f561105d565b613bda6102cf91610294565b60601b90565b92613bfc6014610b8494613bfc8288613bfc829b9a8399613bce565b018092613bce565b613c399291613c1283610294565b613c1b82610294565b1015613c4f576139009092945b604051958694602086019485613be0565b613c4b613c44825190565b9160200190565b2090565b9361390090613c28565b613c625f610b10565b613c6d6102ad845190565b811015613c9757613c8161375c8285612273565b8214613c8f57600101613c62565b505050600190565b5050505f90565b613871906102ad9392613818565b613ccc92916102e391613cbe60405190565b948592602084019283613c9e565b908103825203836105ca565b9490608093613d1e613d2c92613d0e613d3c96613cf76102cf9a613b78565b613d0760408d0191825190613cac565b9052613b78565b613d0760208b0191825190613cac565b87518891613d079190613cac565b613d076060870191825190613cac565b920191825190613cac565b9190608093916102cf95613d6a6040860191613d64835191613b78565b90613cac565b9052613d7f6020850191613d64835191613b78565b9052613d935f840191613d64835191613b78565b9052613da86060830191613d64835191613b78565b90520191613d64835191613b78565b815191613dcd6122ee600194612b2e6001610b10565b9280613dd85f610b10565b905b613df9575b505090613df6613df06102ad935190565b84612273565b52565b613e046102ad845190565b811015613e2f5780612325613e1f61375c613e299487612273565b613df68389612273565b81613dda565b613ddf565b60406102ad91613e415f90565b500151613e4c610c92565b015190565b60406102ad91613e5e5f90565b5001518051015190565b5f6102ad91613e415f90565b5f6102ad91613e5e5f90565b90815191613e966122ee6020946115a886610b10565b9283613ea15f610b10565b613eb86102ad613eaf865190565b6115a886610b10565b811015613efc57613ef790612325613eed613ee7613ede613ed888610b10565b856116b8565b612b2e88610b10565b87015190565b613df6838a612273565b613ea1565b5093505050565b90815191613f196122ee6020946115a886610b10565b9283613f245f610b10565b613f326102ad613eaf865190565b811015613efc57613f5c90612325613f52613ee7613ede613ed888610b10565b612320838a612273565b613f24565b6102ad6102ad6102ad9273ffffffffffffffffffffffffffffffffffffffff1690565b6102ad60146111b9565b613fab613fa66102ad92613fa0606090565b50611125565b613f61565b6138e2613fb6613f84565b6110d8565b90613fc4825190565b811015610733570160200190565b80156110d3577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b6102ad906140116113516102ad9460ff1690565b901c90565b1561401d57565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815280611671600482016020808252818101527f537472696e67733a20686578206c656e67746820696e73756666696369656e74604082015260600190565b6140a3613b86614099846140946002610b10565b6116b8565b612b2e6002610b10565b9160306140b86140b25f610b10565b85613fbb565b537f780000000000000000000000000000000000000000000000000000000000000061410d61410460019384935f1a6140f96140f386610b10565b89613fbb565b536140946002610b10565b612b2e83610b10565b915b614130575b5050906102ad6102ad9261412a6113515f610b10565b14614016565b909161413b82610b10565b8311156141b6577f303132333435363738396162636465660000000000000000000000000000000061416d600f610b10565b821690601082101561073357839261418d6141aa926141b0941a60f81b90565b5f1a6141998789613fbb565b536141a460046111b9565b90613ffd565b93613fd2565b9161410f565b91614114565b6040906114d26102e394969593966141db60608401985f8501906102c6565b60208301906102c6565b9061323d9061322e6102e3956004956142016323b872dd6131a2565b9361420b60405190565b97889560208701908152016141bc56fea2646970667358221220575e7d2416d18ff2bf2ce8b3cf20997bf0c80ed664a436fc3bfbf02d1b43b0c164736f6c634300081e0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000010000000000000000000000000001bb7b44cc398aaa2b76ac6253f0f5634279db9d00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab10000000000000000000000000000000000000000000000000000000000000003000000000000000000000000abc401a16595077881964683450ad63ab3688dab0000000000000000000000001486882e02e6a1037da6afc324b2f911f4c893a000000000000000000000000064c0861a141a7f80ac0b3a32312acad3c62947f3000000000000000000000000000000000000000000000000000000000000000700000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab10000000000000000000000002f2a2543b76a4166549f7aab2e75bef0aefc5b0f000000000000000000000000af88d065e77c8cc2239327c5edb3a432268e5831000000000000000000000000ff970a61a04b1ca14834a43f5de4533ebddb5cc8000000000000000000000000912ce59144191c1204e64559fe8253a0e49e6548000000000000000000000000fd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9000000000000000000000000da10009cbd5d07dd0cecc66161fc93d7c9000da1
-----Decoded View---------------
Arg [0] : _adapters (address[]): 0xaBC401a16595077881964683450ad63aB3688DAb,0x1486882E02E6A1037DA6AfC324b2F911f4c893A0,0x64C0861A141a7F80Ac0B3a32312acAD3c62947f3
Arg [1] : _trustedTokens (address[]): 0x82aF49447D8a07e3bd95BD0d56f35241523fBab1,0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f,0xaf88d065e77c8cC2239327C5EDb3A432268e5831,0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8,0x912CE59144191C1204E64559FE8253a0e49E6548,0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9,0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1
Arg [2] : _feeClaimer (address): 0x01Bb7B44cc398AaA2b76Ac6253F0F5634279Db9D
Arg [3] : _wrapped_native (address): 0x82aF49447D8a07e3bd95BD0d56f35241523fBab1
-----Encoded View---------------
16 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000080
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000100
Arg [2] : 00000000000000000000000001bb7b44cc398aaa2b76ac6253f0f5634279db9d
Arg [3] : 00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab1
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000003
Arg [5] : 000000000000000000000000abc401a16595077881964683450ad63ab3688dab
Arg [6] : 0000000000000000000000001486882e02e6a1037da6afc324b2f911f4c893a0
Arg [7] : 00000000000000000000000064c0861a141a7f80ac0b3a32312acad3c62947f3
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000007
Arg [9] : 00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab1
Arg [10] : 0000000000000000000000002f2a2543b76a4166549f7aab2e75bef0aefc5b0f
Arg [11] : 000000000000000000000000af88d065e77c8cc2239327c5edb3a432268e5831
Arg [12] : 000000000000000000000000ff970a61a04b1ca14834a43f5de4533ebddb5cc8
Arg [13] : 000000000000000000000000912ce59144191c1204e64559fe8253a0e49e6548
Arg [14] : 000000000000000000000000fd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9
Arg [15] : 000000000000000000000000da10009cbd5d07dd0cecc66161fc93d7c9000da1
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.