Feature Tip: Add private address tag to any address under My Name Tag !
Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00Showing the last 7 transactions (View Advanced Filter)
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Grant Role | 24497610 | 43 hrs ago | IN | 0 ETH | 0.00000413 | ||||
| Grant Role | 24497549 | 44 hrs ago | IN | 0 ETH | 0.00000246 | ||||
| Set Routing Conf... | 24497545 | 44 hrs ago | IN | 0 ETH | 0.00000177 | ||||
| Set Routing Conf... | 24497545 | 44 hrs ago | IN | 0 ETH | 0.00000177 | ||||
| Set Routing Conf... | 24497545 | 44 hrs ago | IN | 0 ETH | 0.00000173 | ||||
| Grant Role | 24497544 | 44 hrs ago | IN | 0 ETH | 0.00000217 | ||||
| 0x3462000b | 24497544 | 44 hrs ago | IN | 0 ETH | 0.00014757 |
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
There are no matching entriesUpdate your filters to view other transactions | |||||||||
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
EnhancedSwapRouter
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 200 runs
Other Settings:
london EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "./LiquidityPoolETH.sol";
import "./interfaces/ISwapRouter.sol";
import "./interfaces/ICurvePool.sol";
import "./interfaces/IAggregationRouter.sol";
import "./interfaces/IDodoexRouter.sol";
import "./interfaces/IBalancerVault.sol";
import "./interfaces/IWETH.sol";
/**
* @title EnhancedSwapRouter
* @notice Multi-protocol swap router with intelligent routing and decision logic
* @dev Supports Uniswap V3, Curve, Dodoex PMM, Balancer, and 1inch aggregation
*/
contract EnhancedSwapRouter is AccessControl, ReentrancyGuard {
using SafeERC20 for IERC20;
bytes32 public constant COORDINATOR_ROLE = keccak256("COORDINATOR_ROLE");
bytes32 public constant ROUTING_MANAGER_ROLE = keccak256("ROUTING_MANAGER_ROLE");
enum SwapProvider {
UniswapV3,
Curve,
Dodoex,
Balancer,
OneInch
}
// Protocol addresses
address public immutable uniswapV3Router;
address public immutable curve3Pool;
address public immutable dodoexRouter;
address public immutable balancerVault;
address public immutable oneInchRouter;
// Token addresses
address public immutable weth;
address public immutable usdt;
address public immutable usdc;
address public immutable dai;
// Routing configuration
struct RoutingConfig {
SwapProvider[] providers; // Ordered list of providers to try
uint256[] sizeThresholds; // Size thresholds in wei
bool enabled;
}
mapping(SwapProvider => bool) public providerEnabled;
mapping(uint256 => RoutingConfig) public sizeBasedRouting; // size category => config
uint256 public constant SMALL_SWAP_THRESHOLD = 10_000 * 1e18; // $10k
uint256 public constant MEDIUM_SWAP_THRESHOLD = 100_000 * 1e18; // $100k
// Uniswap V3 fee tiers
uint24 public constant FEE_TIER_LOW = 500;
uint24 public constant FEE_TIER_MEDIUM = 3000;
uint24 public constant FEE_TIER_HIGH = 10000;
// Balancer pool IDs (example - would be set via admin)
mapping(address => mapping(address => bytes32)) public balancerPoolIds; // tokenIn => tokenOut => poolId
// Dodoex PMM pool addresses (tokenIn => tokenOut => PMM pool address)
mapping(address => mapping(address => address)) public dodoPoolAddresses;
/// @dev Uniswap V3 Quoter for on-chain quotes; set via setUniswapQuoter when deployed on 138/651940
address public uniswapQuoter;
event SwapExecuted(
SwapProvider indexed provider,
LiquidityPoolETH.AssetType indexed inputAsset,
address indexed tokenIn,
address tokenOut,
uint256 amountIn,
uint256 amountOut,
uint256 gasUsed
);
event RoutingConfigUpdated(uint256 sizeCategory, SwapProvider[] providers);
event ProviderToggled(SwapProvider provider, bool enabled);
error ZeroAddress();
error ZeroAmount();
error SwapFailed();
error InvalidProvider();
error ProviderDisabled();
error InsufficientOutput();
error InvalidRoutingConfig();
/**
* @notice Constructor
* @param _uniswapV3Router Uniswap V3 SwapRouter address
* @param _curve3Pool Curve 3pool address
* @param _dodoexRouter Dodoex Router address
* @param _balancerVault Balancer Vault address
* @param _oneInchRouter 1inch Router address (can be address(0))
* @param _weth WETH address
* @param _usdt USDT address
* @param _usdc USDC address
* @param _dai DAI address
*/
constructor(
address _uniswapV3Router,
address _curve3Pool,
address _dodoexRouter,
address _balancerVault,
address _oneInchRouter,
address _weth,
address _usdt,
address _usdc,
address _dai
) {
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
if (_uniswapV3Router == address(0) || _curve3Pool == address(0) ||
_dodoexRouter == address(0) || _balancerVault == address(0) ||
_weth == address(0) || _usdt == address(0) || _usdc == address(0) || _dai == address(0)) {
revert ZeroAddress();
}
uniswapV3Router = _uniswapV3Router;
curve3Pool = _curve3Pool;
dodoexRouter = _dodoexRouter;
balancerVault = _balancerVault;
oneInchRouter = _oneInchRouter;
weth = _weth;
usdt = _usdt;
usdc = _usdc;
dai = _dai;
// Enable all providers by default
providerEnabled[SwapProvider.UniswapV3] = true;
providerEnabled[SwapProvider.Curve] = true;
providerEnabled[SwapProvider.Dodoex] = true;
providerEnabled[SwapProvider.Balancer] = true;
if (_oneInchRouter != address(0)) {
providerEnabled[SwapProvider.OneInch] = true;
}
// Initialize default routing configs
_initializeDefaultRouting();
}
/**
* @notice Swap to stablecoin using intelligent routing
* @param inputAsset Input asset type (ETH or WETH)
* @param stablecoinToken Target stablecoin
* @param amountIn Input amount
* @param amountOutMin Minimum output (slippage protection)
* @param preferredProvider Optional preferred provider (0 = auto-select)
* @return amountOut Output amount
* @return providerUsed Provider that executed the swap
*/
function swapToStablecoin(
LiquidityPoolETH.AssetType inputAsset,
address stablecoinToken,
uint256 amountIn,
uint256 amountOutMin,
SwapProvider preferredProvider
) external payable nonReentrant returns (uint256 amountOut, SwapProvider providerUsed) {
if (amountIn == 0) revert ZeroAmount();
if (stablecoinToken == address(0)) revert ZeroAddress();
if (!_isValidStablecoin(stablecoinToken)) revert("EnhancedSwapRouter: invalid stablecoin");
// Convert ETH to WETH if needed
if (inputAsset == LiquidityPoolETH.AssetType.ETH) {
require(msg.value == amountIn, "EnhancedSwapRouter: ETH amount mismatch");
IWETH(weth).deposit{value: amountIn}();
}
// Get routing providers based on swap size
SwapProvider[] memory providers = _getRoutingProviders(amountIn, preferredProvider);
// Try each provider in order
for (uint256 i = 0; i < providers.length; i++) {
if (!providerEnabled[providers[i]]) continue;
try this._executeSwap(
providers[i],
stablecoinToken,
amountIn,
amountOutMin
) returns (uint256 output) {
if (output >= amountOutMin) {
// Transfer output to caller
IERC20(stablecoinToken).safeTransfer(msg.sender, output);
emit SwapExecuted(
providers[i],
inputAsset,
weth,
stablecoinToken,
amountIn,
output,
gasleft()
);
return (output, providers[i]);
}
} catch {
// Try next provider
continue;
}
}
revert SwapFailed();
}
/**
* @notice Get quote from all enabled providers
* @param stablecoinToken Target stablecoin
* @param amountIn Input amount
* @return providers Array of providers that returned quotes
* @return amounts Array of output amounts for each provider
*/
function getQuotes(
address stablecoinToken,
uint256 amountIn
) external view returns (SwapProvider[] memory providers, uint256[] memory amounts) {
SwapProvider[] memory enabledProviders = new SwapProvider[](5);
uint256[] memory quotes = new uint256[](5);
uint256 count = 0;
// Query each enabled provider
if (providerEnabled[SwapProvider.UniswapV3]) {
try this._getUniswapV3Quote(stablecoinToken, amountIn) returns (uint256 quote) {
enabledProviders[count] = SwapProvider.UniswapV3;
quotes[count] = quote;
count++;
} catch {}
}
if (providerEnabled[SwapProvider.Dodoex]) {
try this._getDodoexQuote(stablecoinToken, amountIn) returns (uint256 quote) {
enabledProviders[count] = SwapProvider.Dodoex;
quotes[count] = quote;
count++;
} catch {}
}
if (providerEnabled[SwapProvider.Balancer]) {
try this._getBalancerQuote(stablecoinToken, amountIn) returns (uint256 quote) {
enabledProviders[count] = SwapProvider.Balancer;
quotes[count] = quote;
count++;
} catch {}
}
// Resize arrays
SwapProvider[] memory resultProviders = new SwapProvider[](count);
uint256[] memory resultQuotes = new uint256[](count);
for (uint256 i = 0; i < count; i++) {
resultProviders[i] = enabledProviders[i];
resultQuotes[i] = quotes[i];
}
return (resultProviders, resultQuotes);
}
/**
* @notice Set routing configuration for a size category
* @param sizeCategory 0 = small, 1 = medium, 2 = large
* @param providers Ordered list of providers to try
*/
function setRoutingConfig(
uint256 sizeCategory,
SwapProvider[] calldata providers
) external onlyRole(ROUTING_MANAGER_ROLE) {
require(sizeCategory < 3, "EnhancedSwapRouter: invalid size category");
require(providers.length > 0, "EnhancedSwapRouter: empty providers");
sizeBasedRouting[sizeCategory] = RoutingConfig({
providers: providers,
sizeThresholds: new uint256[](0),
enabled: true
});
emit RoutingConfigUpdated(sizeCategory, providers);
}
/**
* @notice Toggle provider on/off
* @param provider Provider to toggle
* @param enabled Whether to enable
*/
function setProviderEnabled(
SwapProvider provider,
bool enabled
) external onlyRole(ROUTING_MANAGER_ROLE) {
providerEnabled[provider] = enabled;
emit ProviderToggled(provider, enabled);
}
/**
* @notice Set Balancer pool ID for a token pair
* @param tokenIn Input token
* @param tokenOut Output token
* @param poolId Balancer pool ID
*/
function setBalancerPoolId(
address tokenIn,
address tokenOut,
bytes32 poolId
) external onlyRole(ROUTING_MANAGER_ROLE) {
balancerPoolIds[tokenIn][tokenOut] = poolId;
}
/**
* @notice Set Dodoex PMM pool address for a token pair
* @param tokenIn Input token
* @param tokenOut Output token
* @param poolAddress Dodo PMM pool address
*/
function setDodoPoolAddress(
address tokenIn,
address tokenOut,
address poolAddress
) external onlyRole(ROUTING_MANAGER_ROLE) {
dodoPoolAddresses[tokenIn][tokenOut] = poolAddress;
}
/**
* @notice Set Uniswap V3 Quoter address for on-chain quotes
* @param _quoter Quoter contract address (address(0) to use 0.5% slippage estimate)
*/
function setUniswapQuoter(address _quoter) external onlyRole(ROUTING_MANAGER_ROLE) {
uniswapQuoter = _quoter;
}
/**
* @notice Swap arbitrary token pair via Dodoex when pool is configured
* @param tokenIn Input token
* @param tokenOut Output token
* @param amountIn Input amount
* @param amountOutMin Minimum output (slippage protection)
* @return amountOut Output amount
*/
function swapTokenToToken(
address tokenIn,
address tokenOut,
uint256 amountIn,
uint256 amountOutMin
) external nonReentrant returns (uint256 amountOut) {
if (amountIn == 0) revert ZeroAmount();
if (tokenIn == address(0) || tokenOut == address(0)) revert ZeroAddress();
address pool = dodoPoolAddresses[tokenIn][tokenOut];
require(pool != address(0), "EnhancedSwapRouter: Dodoex pool not configured");
IERC20(tokenIn).safeTransferFrom(msg.sender, address(this), amountIn);
IERC20(tokenIn).approve(dodoexRouter, amountIn);
address[] memory dodoPairs = new address[](1);
dodoPairs[0] = pool;
IDodoexRouter.DodoSwapParams memory params = IDodoexRouter.DodoSwapParams({
fromToken: tokenIn,
toToken: tokenOut,
fromTokenAmount: amountIn,
minReturnAmount: amountOutMin,
dodoPairs: dodoPairs,
directions: 0,
isIncentive: false,
deadLine: block.timestamp + 300
});
amountOut = IDodoexRouter(dodoexRouter).dodoSwapV2TokenToToken(params);
require(amountOut >= amountOutMin, "EnhancedSwapRouter: insufficient output");
IERC20(tokenOut).safeTransfer(msg.sender, amountOut);
return amountOut;
}
// ============ Internal Functions ============
/**
* @notice Execute swap via specified provider
*/
function _executeSwap(
SwapProvider provider,
address stablecoinToken,
uint256 amountIn,
uint256 amountOutMin
) external returns (uint256) {
require(msg.sender == address(this), "EnhancedSwapRouter: internal only");
if (provider == SwapProvider.UniswapV3) {
return _executeUniswapV3Swap(stablecoinToken, amountIn, amountOutMin);
} else if (provider == SwapProvider.Dodoex) {
return _executeDodoexSwap(stablecoinToken, amountIn, amountOutMin);
} else if (provider == SwapProvider.Balancer) {
return _executeBalancerSwap(stablecoinToken, amountIn, amountOutMin);
} else if (provider == SwapProvider.Curve) {
return _executeCurveSwap(stablecoinToken, amountIn, amountOutMin);
} else if (provider == SwapProvider.OneInch && oneInchRouter != address(0)) {
return _execute1inchSwap(stablecoinToken, amountIn, amountOutMin);
}
revert InvalidProvider();
}
/**
* @notice Get routing providers based on swap size
*/
function _getRoutingProviders(
uint256 amountIn,
SwapProvider preferredProvider
) internal view returns (SwapProvider[] memory) {
// If preferred provider is specified and enabled, use it first
if (preferredProvider != SwapProvider.UniswapV3 && providerEnabled[preferredProvider]) {
SwapProvider[] memory providers = new SwapProvider[](1);
providers[0] = preferredProvider;
return providers;
}
// Determine size category
uint256 category;
if (amountIn < SMALL_SWAP_THRESHOLD) {
category = 0; // Small
} else if (amountIn < MEDIUM_SWAP_THRESHOLD) {
category = 1; // Medium
} else {
category = 2; // Large
}
RoutingConfig memory config = sizeBasedRouting[category];
if (config.enabled && config.providers.length > 0) {
return config.providers;
}
// Default fallback routing
SwapProvider[] memory defaultProviders = new SwapProvider[](5);
defaultProviders[0] = SwapProvider.Dodoex;
defaultProviders[1] = SwapProvider.UniswapV3;
defaultProviders[2] = SwapProvider.Balancer;
defaultProviders[3] = SwapProvider.Curve;
defaultProviders[4] = SwapProvider.OneInch;
return defaultProviders;
}
/**
* @notice Execute Uniswap V3 swap
*/
function _executeUniswapV3Swap(
address stablecoinToken,
uint256 amountIn,
uint256 amountOutMin
) internal returns (uint256) {
// Approve for swap
IERC20 wethToken = IERC20(weth);
wethToken.approve(uniswapV3Router, amountIn);
ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams({
tokenIn: weth,
tokenOut: stablecoinToken,
fee: FEE_TIER_MEDIUM,
recipient: address(this),
deadline: block.timestamp + 300,
amountIn: amountIn,
amountOutMinimum: amountOutMin,
sqrtPriceLimitX96: 0
});
return ISwapRouter(uniswapV3Router).exactInputSingle(params);
}
/**
* @notice Execute Dodoex PMM swap
*/
function _executeDodoexSwap(
address stablecoinToken,
uint256 amountIn,
uint256 amountOutMin
) internal returns (uint256) {
address pool = dodoPoolAddresses[weth][stablecoinToken];
require(pool != address(0), "EnhancedSwapRouter: Dodoex pool not configured");
IERC20 wethToken = IERC20(weth);
wethToken.approve(dodoexRouter, amountIn);
address[] memory dodoPairs = new address[](1);
dodoPairs[0] = pool;
IDodoexRouter.DodoSwapParams memory params = IDodoexRouter.DodoSwapParams({
fromToken: weth,
toToken: stablecoinToken,
fromTokenAmount: amountIn,
minReturnAmount: amountOutMin,
dodoPairs: dodoPairs,
directions: 0,
isIncentive: false,
deadLine: block.timestamp + 300
});
return IDodoexRouter(dodoexRouter).dodoSwapV2TokenToToken(params);
}
/**
* @notice Execute Balancer swap
*/
function _executeBalancerSwap(
address stablecoinToken,
uint256 amountIn,
uint256 amountOutMin
) internal returns (uint256) {
bytes32 poolId = balancerPoolIds[weth][stablecoinToken];
require(poolId != bytes32(0), "EnhancedSwapRouter: pool not configured");
IERC20 wethToken = IERC20(weth);
wethToken.approve(balancerVault, amountIn);
IBalancerVault.SingleSwap memory singleSwap = IBalancerVault.SingleSwap({
poolId: poolId,
kind: IBalancerVault.SwapKind.GIVEN_IN,
assetIn: weth,
assetOut: stablecoinToken,
amount: amountIn,
userData: ""
});
IBalancerVault.FundManagement memory funds = IBalancerVault.FundManagement({
sender: address(this),
fromInternalBalance: false,
recipient: payable(address(this)),
toInternalBalance: false
});
return IBalancerVault(balancerVault).swap(
singleSwap,
funds,
amountOutMin,
block.timestamp + 300
);
}
/**
* @notice Execute Curve swap
*/
function _executeCurveSwap(
address stablecoinToken,
uint256 amountIn,
uint256 amountOutMin
) internal returns (uint256) {
// Curve 3pool doesn't support WETH directly
// Would need intermediate swap or different pool
revert("EnhancedSwapRouter: Curve direct swap not supported");
}
/**
* @notice Execute 1inch swap
*/
function _execute1inchSwap(
address stablecoinToken,
uint256 amountIn,
uint256 amountOutMin
) internal returns (uint256) {
if (oneInchRouter == address(0)) revert ProviderDisabled();
IERC20 wethToken = IERC20(weth);
wethToken.approve(oneInchRouter, amountIn);
// 1inch: requires route data from 1inch API (e.g. /swap/v5.2/138/swap). Use 1inch SDK or API to get calldata and execute separately.
revert("EnhancedSwapRouter: 1inch requires route calldata from API; use 1inch aggregator SDK");
}
/**
* @notice Get Uniswap V3 quote (view)
* When UNISWAP_QUOTER_ADDRESS is configured, queries quoter. Otherwise returns
* estimate via amountIn * 9950/10000 (0.5% slippage) for stablecoin pairs.
*/
function _getUniswapV3Quote(
address stablecoinToken,
uint256 amountIn
) external view returns (uint256) {
if (uniswapQuoter != address(0) && _isValidStablecoin(stablecoinToken)) {
// IQuoter.quoteExactInputSingle(tokenIn, tokenOut, fee, amountIn, sqrtPriceLimitX96)
(bool ok, bytes memory data) = uniswapQuoter.staticcall(
abi.encodeWithSignature(
"quoteExactInputSingle(address,address,uint24,uint256,uint160)",
weth,
stablecoinToken,
FEE_TIER_MEDIUM,
amountIn,
uint160(0)
)
);
if (ok && data.length >= 32) {
uint256 quoted = abi.decode(data, (uint256));
if (quoted > 0) return quoted;
}
}
if (_isValidStablecoin(stablecoinToken)) {
return (amountIn * 9950) / 10000; // 0.5% slippage estimate for WETH->stable
}
return 0;
}
/**
* @notice Get Dodoex quote (view)
*/
function _getDodoexQuote(
address stablecoinToken,
uint256 amountIn
) external view returns (uint256) {
return IDodoexRouter(dodoexRouter).getDodoSwapQuote(weth, stablecoinToken, amountIn);
}
/**
* @notice Get Balancer quote (view)
* When poolId configured, would query Balancer. Otherwise estimate for stablecoins.
*/
function _getBalancerQuote(
address stablecoinToken,
uint256 amountIn
) external view returns (uint256) {
bytes32 poolId = balancerPoolIds[weth][stablecoinToken];
if (poolId != bytes32(0)) {
(address[] memory tokens, uint256[] memory balances,) =
IBalancerVault(balancerVault).getPoolTokens(poolId);
if (tokens.length >= 2 && balances.length >= 2) {
uint256 wethIdx = type(uint256).max;
uint256 stableIdx = type(uint256).max;
for (uint256 i = 0; i < tokens.length; i++) {
if (tokens[i] == weth) wethIdx = i;
if (tokens[i] == stablecoinToken) stableIdx = i;
}
if (wethIdx != type(uint256).max && stableIdx != type(uint256).max && balances[wethIdx] > 0) {
uint256 amountOut = (amountIn * balances[stableIdx]) / balances[wethIdx];
return (amountOut * 9950) / 10000; // 0.5% slippage
}
}
}
if (_isValidStablecoin(stablecoinToken)) {
return (amountIn * 9950) / 10000; // 0.5% slippage estimate when pool not configured
}
return 0;
}
/**
* @notice Initialize default routing configurations
*/
function _initializeDefaultRouting() internal {
// Small swaps (< $10k): Uniswap V3, Dodoex
SwapProvider[] memory smallProviders = new SwapProvider[](2);
smallProviders[0] = SwapProvider.UniswapV3;
smallProviders[1] = SwapProvider.Dodoex;
sizeBasedRouting[0] = RoutingConfig({
providers: smallProviders,
sizeThresholds: new uint256[](0),
enabled: true
});
// Medium swaps ($10k-$100k): Dodoex, Balancer, Uniswap V3
SwapProvider[] memory mediumProviders = new SwapProvider[](3);
mediumProviders[0] = SwapProvider.Dodoex;
mediumProviders[1] = SwapProvider.Balancer;
mediumProviders[2] = SwapProvider.UniswapV3;
sizeBasedRouting[1] = RoutingConfig({
providers: mediumProviders,
sizeThresholds: new uint256[](0),
enabled: true
});
// Large swaps (> $100k): Dodoex, Curve, Balancer
SwapProvider[] memory largeProviders = new SwapProvider[](3);
largeProviders[0] = SwapProvider.Dodoex;
largeProviders[1] = SwapProvider.Curve;
largeProviders[2] = SwapProvider.Balancer;
sizeBasedRouting[2] = RoutingConfig({
providers: largeProviders,
sizeThresholds: new uint256[](0),
enabled: true
});
}
/**
* @notice Check if token is valid stablecoin
*/
function _isValidStablecoin(address token) internal view returns (bool) {
return token == usdt || token == usdc || token == dai;
}
// Allow contract to receive ETH
receive() external payable {}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @dev An operation with an ERC20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data);
if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)
pragma solidity ^0.8.20;
import {IAccessControl} from "./IAccessControl.sol";
import {Context} from "../utils/Context.sol";
import {ERC165} from "../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 account => bool) hasRole;
bytes32 adminRole;
}
mapping(bytes32 role => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with an {AccessControlUnauthorizedAccount} error including the required role.
*/
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 returns (bool) {
return _roles[role].hasRole[account];
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
* is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
* is missing `role`.
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert AccessControlUnauthorizedAccount(account, role);
}
}
/**
* @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 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 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 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 `callerConfirmation`.
*
* May emit a {RoleRevoked} event.
*/
function renounceRole(bytes32 role, address callerConfirmation) public virtual {
if (callerConfirmation != _msgSender()) {
revert AccessControlBadConfirmation();
}
_revokeRole(role, callerConfirmation);
}
/**
* @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 Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/
function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
if (!hasRole(role, account)) {
_roles[role].hasRole[account] = true;
emit RoleGranted(role, account, _msgSender());
return true;
} else {
return false;
}
}
/**
* @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/
function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
if (hasRole(role, account)) {
_roles[role].hasRole[account] = false;
emit RoleRevoked(role, account, _msgSender());
return true;
} else {
return false;
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)
pragma solidity ^0.8.20;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
uint256 private _status;
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
constructor() {
_status = NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be NOT_ENTERED
if (_status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
_status = ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == ENTERED;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
/**
* @title LiquidityPoolETH
* @notice Liquidity pool for ETH and WETH with fee model and minimum liquidity ratio enforcement
* @dev Supports separate pools for native ETH and WETH (ERC-20)
*/
contract LiquidityPoolETH is ReentrancyGuard {
using SafeERC20 for IERC20;
enum AssetType {
ETH, // Native ETH
WETH // Wrapped ETH (ERC-20)
}
// Pool configuration
uint256 public immutable lpFeeBps; // Liquidity provider fee in basis points (default: 5 = 0.05%)
uint256 public immutable minLiquidityRatioBps; // Minimum liquidity ratio in basis points (default: 11000 = 110%)
address public immutable weth; // WETH token address
// WETH getter for external access
function getWeth() external view returns (address) {
return weth;
}
// Pool state
struct PoolState {
uint256 totalLiquidity;
uint256 pendingClaims; // Total amount of pending claims to be released
mapping(address => uint256) lpShares; // LP address => amount provided
}
mapping(AssetType => PoolState) public pools;
mapping(address => bool) public authorizedRelease; // Contracts authorized to release funds
event LiquidityProvided(
AssetType indexed assetType,
address indexed provider,
uint256 amount
);
event LiquidityWithdrawn(
AssetType indexed assetType,
address indexed provider,
uint256 amount
);
event FundsReleased(
AssetType indexed assetType,
uint256 indexed depositId,
address indexed recipient,
uint256 amount,
uint256 feeAmount
);
event PendingClaimAdded(
AssetType indexed assetType,
uint256 amount
);
event PendingClaimRemoved(
AssetType indexed assetType,
uint256 amount
);
error ZeroAmount();
error ZeroAddress();
error InsufficientLiquidity();
error WithdrawalBlockedByLiquidityRatio();
error UnauthorizedRelease();
error InvalidAssetType();
/**
* @notice Constructor
* @param _weth WETH token address
* @param _lpFeeBps LP fee in basis points (5 = 0.05%)
* @param _minLiquidityRatioBps Minimum liquidity ratio in basis points (11000 = 110%)
*/
constructor(
address _weth,
uint256 _lpFeeBps,
uint256 _minLiquidityRatioBps
) {
require(_weth != address(0), "LiquidityPoolETH: zero WETH address");
require(_lpFeeBps <= 10000, "LiquidityPoolETH: fee exceeds 100%");
require(_minLiquidityRatioBps >= 10000, "LiquidityPoolETH: min ratio must be >= 100%");
weth = _weth;
lpFeeBps = _lpFeeBps;
minLiquidityRatioBps = _minLiquidityRatioBps;
}
/**
* @notice Authorize a contract to release funds (called during deployment)
* @param releaser Address authorized to release funds
*/
function authorizeRelease(address releaser) external {
require(releaser != address(0), "LiquidityPoolETH: zero address");
authorizedRelease[releaser] = true;
}
/**
* @notice Provide liquidity to the pool
* @param assetType Type of asset (ETH or WETH)
*/
function provideLiquidity(AssetType assetType) external payable nonReentrant {
uint256 amount;
if (assetType == AssetType.ETH) {
if (msg.value == 0) revert ZeroAmount();
amount = msg.value;
} else if (assetType == AssetType.WETH) {
if (msg.value != 0) revert("LiquidityPoolETH: WETH deposits must use depositWETH()");
revert("LiquidityPoolETH: use depositWETH() for WETH deposits");
} else {
revert InvalidAssetType();
}
pools[assetType].totalLiquidity += amount;
pools[assetType].lpShares[msg.sender] += amount;
emit LiquidityProvided(assetType, msg.sender, amount);
}
/**
* @notice Provide WETH liquidity to the pool
* @param amount Amount of WETH to deposit
*/
function depositWETH(uint256 amount) external nonReentrant {
if (amount == 0) revert ZeroAmount();
IERC20(weth).safeTransferFrom(msg.sender, address(this), amount);
pools[AssetType.WETH].totalLiquidity += amount;
pools[AssetType.WETH].lpShares[msg.sender] += amount;
emit LiquidityProvided(AssetType.WETH, msg.sender, amount);
}
/**
* @notice Withdraw liquidity from the pool
* @param amount Amount to withdraw
* @param assetType Type of asset (ETH or WETH)
*/
function withdrawLiquidity(
uint256 amount,
AssetType assetType
) external nonReentrant {
if (amount == 0) revert ZeroAmount();
if (pools[assetType].lpShares[msg.sender] < amount) revert InsufficientLiquidity();
// Check minimum liquidity ratio
uint256 availableLiquidity = pools[assetType].totalLiquidity - pools[assetType].pendingClaims;
uint256 newAvailableLiquidity = availableLiquidity - amount;
uint256 minRequired = (pools[assetType].pendingClaims * minLiquidityRatioBps) / 10000;
if (newAvailableLiquidity < minRequired) {
revert WithdrawalBlockedByLiquidityRatio();
}
pools[assetType].totalLiquidity -= amount;
pools[assetType].lpShares[msg.sender] -= amount;
if (assetType == AssetType.ETH) {
(bool success, ) = payable(msg.sender).call{value: amount}("");
require(success, "LiquidityPoolETH: ETH transfer failed");
} else {
IERC20(weth).safeTransfer(msg.sender, amount);
}
emit LiquidityWithdrawn(assetType, msg.sender, amount);
}
/**
* @notice Release funds to recipient (only authorized contracts)
* @param depositId Deposit ID (for event tracking)
* @param recipient Recipient address
* @param amount Amount to release (before fees)
* @param assetType Type of asset (ETH or WETH)
*/
function releaseToRecipient(
uint256 depositId,
address recipient,
uint256 amount,
AssetType assetType
) external nonReentrant {
if (!authorizedRelease[msg.sender]) revert UnauthorizedRelease();
if (amount == 0) revert ZeroAmount();
if (recipient == address(0)) revert ZeroAddress();
// Calculate fee
uint256 feeAmount = (amount * lpFeeBps) / 10000;
uint256 releaseAmount = amount - feeAmount;
// Check available liquidity
PoolState storage pool = pools[assetType];
uint256 availableLiquidity = pool.totalLiquidity - pool.pendingClaims;
if (availableLiquidity < releaseAmount) {
revert InsufficientLiquidity();
}
// Reduce pending claims
pool.pendingClaims -= amount;
// Release funds to recipient
if (assetType == AssetType.ETH) {
(bool success, ) = payable(recipient).call{value: releaseAmount}("");
require(success, "LiquidityPoolETH: ETH transfer failed");
} else {
IERC20(weth).safeTransfer(recipient, releaseAmount);
}
// Fee remains in pool (increases totalLiquidity effectively by reducing pendingClaims)
emit FundsReleased(assetType, depositId, recipient, releaseAmount, feeAmount);
}
/**
* @notice Add pending claim (called when claim is submitted)
* @param amount Amount of pending claim
* @param assetType Type of asset
*/
function addPendingClaim(uint256 amount, AssetType assetType) external {
if (!authorizedRelease[msg.sender]) revert UnauthorizedRelease();
pools[assetType].pendingClaims += amount;
emit PendingClaimAdded(assetType, amount);
}
/**
* @notice Remove pending claim (called when claim is challenged/slashed)
* @param amount Amount of pending claim to remove
* @param assetType Type of asset
*/
function removePendingClaim(uint256 amount, AssetType assetType) external {
if (!authorizedRelease[msg.sender]) revert UnauthorizedRelease();
pools[assetType].pendingClaims -= amount;
emit PendingClaimRemoved(assetType, amount);
}
/**
* @notice Get available liquidity for an asset type
* @param assetType Type of asset
* @return Available liquidity (total - pending claims)
*/
function getAvailableLiquidity(AssetType assetType) external view returns (uint256) {
PoolState storage pool = pools[assetType];
uint256 pending = pool.pendingClaims;
if (pool.totalLiquidity <= pending) {
return 0;
}
return pool.totalLiquidity - pending;
}
/**
* @notice Get LP share for a provider
* @param provider LP provider address
* @param assetType Type of asset
* @return LP share amount
*/
function getLpShare(address provider, AssetType assetType) external view returns (uint256) {
return pools[assetType].lpShares[provider];
}
/**
* @notice Get pool statistics
* @param assetType Type of asset
* @return totalLiquidity Total liquidity in pool
* @return pendingClaims Total pending claims
* @return availableLiquidity Available liquidity (total - pending)
*/
function getPoolStats(
AssetType assetType
) external view returns (
uint256 totalLiquidity,
uint256 pendingClaims,
uint256 availableLiquidity
) {
PoolState storage pool = pools[assetType];
totalLiquidity = pool.totalLiquidity;
pendingClaims = pool.pendingClaims;
if (totalLiquidity > pendingClaims) {
availableLiquidity = totalLiquidity - pendingClaims;
} else {
availableLiquidity = 0;
}
}
// Allow contract to receive ETH
receive() external payable {}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
/**
* @title ISwapRouter - Uniswap V3 SwapRouter Interface
* @notice Minimal interface for Uniswap V3 SwapRouter
* @dev Based on Uniswap V3 SwapRouter02
*/
interface ISwapRouter {
struct ExactInputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 deadline;
uint256 amountIn;
uint256 amountOutMinimum;
uint160 sqrtPriceLimitX96;
}
struct ExactInputParams {
bytes path;
address recipient;
uint256 deadline;
uint256 amountIn;
uint256 amountOutMinimum;
}
function exactInputSingle(ExactInputSingleParams calldata params)
external
payable
returns (uint256 amountOut);
function exactInput(ExactInputParams calldata params)
external
payable
returns (uint256 amountOut);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
/**
* @title ICurvePool - Curve Pool Interface
* @notice Minimal interface for Curve stable pools (e.g., 3pool)
* @dev Based on Curve StableSwap pools
*/
interface ICurvePool {
function exchange(
int128 i,
int128 j,
uint256 dx,
uint256 min_dy
) external payable returns (uint256);
function exchange_underlying(
int128 i,
int128 j,
uint256 dx,
uint256 min_dy
) external payable returns (uint256);
function get_dy(
int128 i,
int128 j,
uint256 dx
) external view returns (uint256);
function coins(uint256 i) external view returns (address);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
/**
* @title IAggregationRouter - 1inch AggregationRouter Interface
* @notice Minimal interface for 1inch AggregationRouter
* @dev Based on 1inch V5 Router
*/
interface IAggregationRouter {
struct SwapDescription {
address srcToken;
address dstToken;
address srcReceiver;
address dstReceiver;
uint256 amount;
uint256 minReturnAmount;
uint256 flags;
bytes permit;
}
function swap(
address executor,
SwapDescription calldata desc,
bytes calldata permit,
bytes calldata data
) external payable returns (uint256 returnAmount, uint256 spentAmount);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
/**
* @title IDodoexRouter
* @notice Interface for Dodoex PMM (Proactive Market Maker) Router
* @dev Dodoex uses PMM which provides better price discovery and lower slippage
*/
interface IDodoexRouter {
struct DodoSwapParams {
address fromToken;
address toToken;
uint256 fromTokenAmount;
uint256 minReturnAmount;
address[] dodoPairs; // Dodo PMM pool addresses
uint256 directions; // 0 = base to quote, 1 = quote to base
bool isIncentive; // Whether to use incentive mechanism
uint256 deadLine;
}
/**
* @notice Swap tokens via Dodoex PMM
* @param params Swap parameters
* @return receivedAmount Amount received after swap
*/
function dodoSwapV2TokenToToken(
DodoSwapParams calldata params
) external returns (uint256 receivedAmount);
/**
* @notice Get quote for swap (view function)
* @param fromToken Source token
* @param toToken Destination token
* @param fromTokenAmount Amount to swap
* @return toTokenAmount Expected output amount
*/
function getDodoSwapQuote(
address fromToken,
address toToken,
uint256 fromTokenAmount
) external view returns (uint256 toTokenAmount);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
/**
* @title IBalancerVault
* @notice Interface for Balancer V2 Vault
* @dev Balancer provides weighted pools and better stablecoin swaps
*/
interface IBalancerVault {
struct SingleSwap {
bytes32 poolId;
SwapKind kind;
address assetIn;
address assetOut;
uint256 amount;
bytes userData;
}
struct FundManagement {
address sender;
bool fromInternalBalance;
address payable recipient;
bool toInternalBalance;
}
enum SwapKind {
GIVEN_IN, // Amount in is known
GIVEN_OUT // Amount out is known
}
/**
* @notice Execute a single swap
* @param singleSwap Swap parameters
* @param funds Fund management parameters
* @param limit Maximum amount to swap (slippage protection)
* @param deadline Deadline for swap
* @return amountCalculated Amount calculated for swap
*/
function swap(
SingleSwap memory singleSwap,
FundManagement memory funds,
uint256 limit,
uint256 deadline
) external payable returns (uint256 amountCalculated);
/**
* @notice Get pool information
* @param poolId Pool identifier
* @return poolAddress Pool address
* @return specialization Pool specialization type
*/
function getPool(bytes32 poolId) external view returns (address poolAddress, uint8 specialization);
/**
* @notice Query batch swap for quotes
* @param kind Swap kind
* @param swaps Array of swaps to query
* @param assets Array of assets involved
* @return assetDeltas Asset deltas for each asset
*/
function queryBatchSwap(
SwapKind kind,
SingleSwap[] memory swaps,
address[] memory assets
) external view returns (int256[] memory assetDeltas);
/**
* @notice Get pool tokens and balances
* @param poolId Pool identifier
* @return tokens Token addresses in the pool
* @return balances Token balances in the pool
* @return lastChangeBlock Last block number that changed balances
*/
function getPoolTokens(bytes32 poolId)
external
view
returns (
address[] memory tokens,
uint256[] memory balances,
uint256 lastChangeBlock
);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
/**
* @title IWETH
* @notice Minimal WETH interface for bridge contracts
*/
interface IWETH {
function deposit() external payable;
function withdraw(uint256) external;
function transfer(address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error AddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedInnerCall();
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {FailedInnerCall} error.
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
* unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {FailedInnerCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
*/
function _revert(bytes memory returndata) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)
pragma solidity ^0.8.20;
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControl {
/**
* @dev The `account` is missing a role.
*/
error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
/**
* @dev The caller of a function is not the expected one.
*
* NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
*/
error AccessControlBadConfirmation();
/**
* @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.
*/
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 `callerConfirmation`.
*/
function renounceRole(bytes32 role, address callerConfirmation) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "./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);
* }
* ```
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @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);
}{
"remappings": [
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
"forge-std/=lib/forge-std/src/",
"ds-test/=lib/forge-std/lib/ds-test/src/",
"@emoney/=contracts/emoney/",
"@emoney-scripts/=script/emoney/",
"erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
"openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"dodo-contractV2/=lib/dodo-contractV2/",
"hardhat/=lib/dodo-contractV2/node_modules/hardhat/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "london",
"viaIR": true
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_uniswapV3Router","type":"address"},{"internalType":"address","name":"_curve3Pool","type":"address"},{"internalType":"address","name":"_dodoexRouter","type":"address"},{"internalType":"address","name":"_balancerVault","type":"address"},{"internalType":"address","name":"_oneInchRouter","type":"address"},{"internalType":"address","name":"_weth","type":"address"},{"internalType":"address","name":"_usdt","type":"address"},{"internalType":"address","name":"_usdc","type":"address"},{"internalType":"address","name":"_dai","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"InsufficientOutput","type":"error"},{"inputs":[],"name":"InvalidProvider","type":"error"},{"inputs":[],"name":"InvalidRoutingConfig","type":"error"},{"inputs":[],"name":"ProviderDisabled","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"SwapFailed","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroAmount","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"enum EnhancedSwapRouter.SwapProvider","name":"provider","type":"uint8"},{"indexed":false,"internalType":"bool","name":"enabled","type":"bool"}],"name":"ProviderToggled","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":"uint256","name":"sizeCategory","type":"uint256"},{"indexed":false,"internalType":"enum EnhancedSwapRouter.SwapProvider[]","name":"providers","type":"uint8[]"}],"name":"RoutingConfigUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"enum EnhancedSwapRouter.SwapProvider","name":"provider","type":"uint8"},{"indexed":true,"internalType":"enum LiquidityPoolETH.AssetType","name":"inputAsset","type":"uint8"},{"indexed":true,"internalType":"address","name":"tokenIn","type":"address"},{"indexed":false,"internalType":"address","name":"tokenOut","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOut","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"gasUsed","type":"uint256"}],"name":"SwapExecuted","type":"event"},{"inputs":[],"name":"COORDINATOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_TIER_HIGH","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_TIER_LOW","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_TIER_MEDIUM","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MEDIUM_SWAP_THRESHOLD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ROUTING_MANAGER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SMALL_SWAP_THRESHOLD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum EnhancedSwapRouter.SwapProvider","name":"provider","type":"uint8"},{"internalType":"address","name":"stablecoinToken","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"}],"name":"_executeSwap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"stablecoinToken","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"}],"name":"_getBalancerQuote","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"stablecoinToken","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"}],"name":"_getDodoexQuote","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"stablecoinToken","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"}],"name":"_getUniswapV3Quote","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"balancerPoolIds","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"balancerVault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"curve3Pool","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dai","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"dodoPoolAddresses","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dodoexRouter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"stablecoinToken","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"}],"name":"getQuotes","outputs":[{"internalType":"enum EnhancedSwapRouter.SwapProvider[]","name":"providers","type":"uint8[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"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":[],"name":"oneInchRouter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum EnhancedSwapRouter.SwapProvider","name":"","type":"uint8"}],"name":"providerEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"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":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"bytes32","name":"poolId","type":"bytes32"}],"name":"setBalancerPoolId","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"address","name":"poolAddress","type":"address"}],"name":"setDodoPoolAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum EnhancedSwapRouter.SwapProvider","name":"provider","type":"uint8"},{"internalType":"bool","name":"enabled","type":"bool"}],"name":"setProviderEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"sizeCategory","type":"uint256"},{"internalType":"enum EnhancedSwapRouter.SwapProvider[]","name":"providers","type":"uint8[]"}],"name":"setRoutingConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_quoter","type":"address"}],"name":"setUniswapQuoter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"sizeBasedRouting","outputs":[{"internalType":"bool","name":"enabled","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum LiquidityPoolETH.AssetType","name":"inputAsset","type":"uint8"},{"internalType":"address","name":"stablecoinToken","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"enum EnhancedSwapRouter.SwapProvider","name":"preferredProvider","type":"uint8"}],"name":"swapToStablecoin","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"enum EnhancedSwapRouter.SwapProvider","name":"providerUsed","type":"uint8"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"}],"name":"swapTokenToToken","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"uniswapQuoter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"uniswapV3Router","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"usdc","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"usdt","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
3462000ba55762004390388190036101a0601f8201601f19168101906001600160401b0382119082101762000780576101209282916040526101a0391262000ba5576200004e6101a062000c0a565b6200005b6101c062000c0a565b620000686101e062000c0a565b916200007661020062000c0a565b6200008361022062000c0a565b906200009161024062000c0a565b906200009f61026062000c0a565b95620000ad61028062000c0a565b95620000bb6102a062000c0a565b9560018055620000cb3362000c7e565b506001600160a01b03811615801562000b93575b801562000b81575b801562000b6f575b801562000b5d575b801562000b4b575b801562000b39575b801562000b27575b62000b155760805260a05260c05260e0526101008290526101205261014093845261016092835261018091825260026020527fac33ff75c19e70fe83507db0d683fd3465c996598dc972688b7ace676c89077b8054600160ff1991821681179092557fe90b7bceb6e7df5418fb78d8ee546e97c83a08bbccc01a0644d599ccd2a7c2e080548216831790557f679795a0195a1b76cdebb7c51d74e058aee92919b8c3389af86ef24535e8a28c805482168317905560036000527f88601476d11616a71c5be67555bd1dff4b1cbf21533d2669b768b61518cfe1c380548216909217909155906001600160a01b031662000afb575b506200020e62000baa565b6002815260403660208301376000620002278262000c1f565b526002620002358262000c43565b526200024062000bca565b600081526200024e62000baa565b918252602080830191909152600160408301526000805260039052805180517f3617319a054d772f909f7c479a2cebe5066e836a939412e32403c99029b92eff92916001600160401b03821162000780576801000000000000000082116200078057602090845483865580841062000ac5575b5001908360005260206000209060005b8160051c811062000a735750601f19811680820362000a17575b50505050602081015180519060018401906001600160401b038311620007805768010000000000000000831162000780576020908254848455808510620009f7575b500190600052602060002060005b838110620009e25750505050906002604062000368930151151591019060ff801983541691151516179055565b6200037262000bea565b60038152606036602083013760026200038b8262000c1f565b526003620003998262000c43565b526000620003a78262000c54565b52620003b262000bca565b60008152620003c062000baa565b91825260208083019190915260016040830181905260005260039052805180517fa15bc60c955c405d20d9149c709e2460f1c2d9a497496a7f46004d1772c3054c92916001600160401b03821162000780576801000000000000000082116200078057602090845483865580841062000989575b5001908360005260206000209060005b8160051c8110620009375750601f198116808203620008db575b50505050602081015180519060018401906001600160401b038311620007805768010000000000000000831162000780576020908254848455808510620008bb575b500190600052602060002060005b838110620008a657505050509060026040620004db930151151591019060ff801983541691151516179055565b620004e562000bea565b6003815260603660208301376002620004fe8262000c1f565b5260016200050c8262000c43565b5260036200051a8262000c54565b526200052562000bca565b600081526200053362000baa565b918252602080830191825260016040840190815260026000526003909152915180517fc3a24b0501bd2c13a7e57f2db4369ec4c223447539fc0724a9d55ac4a06ebd4d9392916001600160401b03821162000780576801000000000000000082116200078057602090855483875580841062000855575b5001908460005260206000208160051c9160005b838110620008035750601f19811690038062000796575b50509151805192506001850191506001600160401b03831162000780576801000000000000000083116200078057602090825484845580851062000760575b500190600052602060002060005b8381106200074b57505050509060026200064c9251151591019060ff801983541691151516179055565b60405191613680938462000d1085396080518481816114c101528181611c6b0152611dbc015260a05184610a47015260c051848181610eec01528181610f980152818161119e0152611eb2015260e05184818161159f0152818161208801528181612249015261304c0152610100518481816107350152818161239f01526124e2015261012051848181610f50015281816110a9015281816118ee0152818161197d01528181611ca501528181611cfd01528181611e550152818161202c015281816123fa01528181612ec60152612fa101525183818161143d01526132f20152518281816113b1015261335201525181818161021a015261332a0152f35b60019060208451940193818401550162000622565b6200077990846000528584600020918201910162000c65565b3862000614565b634e487b7160e01b600052604160045260246000fd5b9260009360005b818110620007b457505050015538808080620005d5565b90919485516005811015620007ed57620007e2602091846001949060ff809160031b9316831b921b19161790565b96019291016200079d565b634e487b7160e01b600052602160045260246000fd5b6000805b602081106200081e575083820155600101620005be565b959081516005811015620007ed576200084b602091896001949060ff809160031b9316831b921b19161790565b9201960162000807565b62000884908760005283600020601f80870160051c820192818816806200088b575b500160051c019062000c65565b38620005aa565b60001990818601918254918a0360031b1c1690553862000877565b600190602084519401938184015501620004ae565b620008d490846000528584600020918201910162000c65565b38620004a0565b9260009360005b8184038110620008fe5750505060051c0155388080806200045e565b90919485516005811015620007ed576200092c602091846001949060ff809160031b9316831b921b19161790565b9601929101620008e2565b6000805b602081106200095257508382015560010162000444565b949081516005811015620007ed576200097f602091886001949060ff809160031b9316831b921b19161790565b920195016200093b565b620009b99086600052601f846000209181871680620009c0575b500160051c810190601f860160051c0162000c65565b3862000434565b6000199081848a0160051c86010191825491890360031b1c16905538620009a3565b6001906020845194019381840155016200033b565b62000a1090846000528584600020918201910162000c65565b386200032d565b9260009360005b818403811062000a3a5750505060051c015538808080620002eb565b90919485516005811015620007ed5762000a68602091846001949060ff809160031b9316831b921b19161790565b960192910162000a1e565b6000805b6020811062000a8e575083820155600101620002d1565b949081516005811015620007ed5762000abb602091886001949060ff809160031b9316831b921b19161790565b9201950162000a77565b62000af49086600052601f846000209181871680620009c057500160051c810190601f860160051c0162000c65565b38620002c1565b600460005260016040600020918254161790553862000203565b60405163d92e233d60e01b8152600490fd5b506001600160a01b038716156200010f565b506001600160a01b0388161562000107565b506001600160a01b03891615620000ff565b506001600160a01b03851615620000f7565b506001600160a01b03841615620000ef565b506001600160a01b03831615620000e7565b506001600160a01b03821615620000df565b600080fd5b60405190606082016001600160401b038111838210176200078057604052565b60405190602082016001600160401b038111838210176200078057604052565b60405190608082016001600160401b038111838210176200078057604052565b51906001600160a01b038216820362000ba557565b80511562000c2d5760200190565b634e487b7160e01b600052603260045260246000fd5b80516001101562000c2d5760400190565b80516002101562000c2d5760600190565b81811062000c71575050565b6000815560010162000c65565b6001600160a01b031660008181527fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5602052604081205490919060ff1662000d0b57818052816020526040822081835260205260408220600160ff1982541617905533917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d8180a4600190565b509056fe608080604052600436101561001d575b50361561001b57600080fd5b005b60003560e01c90816301ffc9a7146115ce57508063158274a5146115895780631c28242a14611562578063248a9ca31461153357806326158136146114f05780632c76d7a6146114ab5780632f2ff15d1461146c5780632f48ab7d1461142757806336568abe146113e05780633e413bee1461139b5780633ee2afc1146110d85780633fc8cef3146110935780634db4a3521461106a5780634f214fd31461101957806352e25bce14610f1b57806355470d8714610ed65780635559294314610eb157806359fbc2d214610a7657806363a6b1da14610a3157806365a5292e146109f65780636b366cb5146109bb5780636c04a824146109325780637574d9a0146109155780637c47ddd01461089c57806381cfa7a01461086657806382cb9ae8146108415780638f40e8f51461082457806391d14854146107d757806395e42ded14610780578063a217fddf14610764578063ac3af2081461071f578063b8ad530e146106e6578063c5b35f63146106b7578063cb29ac5c14610652578063d547741f14610613578063d713da52146105df578063de5663141461058f578063e785f45b14610249578063f4b9fa75146102045763f6b9ec7c146101e2573861000f565b346101ff5760003660031901126101ff5760206040516101f48152f35b600080fd5b346101ff5760003660031901126101ff576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b346101ff5760403660031901126101ff57610262611621565b60405160243591610272826116ea565b6005825260209260a036858501376040519161028d836116ea565b6005835260a0368685013784600092600080526002825260ff604060002054166104fa575b60026000526002825260ff60406000205416610465575b60036000526002825260ff604060002054166103d4575b5050506102ec81611aca565b916102f682611aca565b9360005b83811061038c5786858760405192839260408401604085528151809152826060860192019060005b818110610368575050508381038285015281808451928381520193019160005b82811061035157505050500390f35b835185528695509381019392810192600101610342565b919495509183808261037d6001948951611666565b01950191019186959492610322565b806103b46103a56103a06103cf9486611758565b61176c565b6103af8389611758565b611afc565b6103be8185611758565b516103c98289611758565b52611726565b6102fa565b60405163c5b35f6360e01b81526001600160a01b03939093166004840152602483015281604481305afa60009181610436575b50610414575b84816102e0565b906104309160036104258387611758565b526103c98285611758565b8461040d565b9091508581813d831161045e575b61044e8183611705565b810103126101ff57519086610407565b503d610444565b6040516329712de760e11b81526001600160a01b0384166004820152602481018290528281604481305afa600091816104c9575b506104a5575b506102c9565b936104c2919460026104b7838a611758565b526103c98288611758565b928761049f565b8481959293503d83116104f3575b6104e18183611705565b810103126101ff578792519089610499565b503d6104d7565b604051630e14121560e11b81526001600160a01b0384166004820152602481018290528281604481305afa6000918161055e575b5061053a575b506102b2565b91509250600061054986611735565b5261055384611735565b528460019287610534565b8481959293503d8311610588575b6105768183611705565b810103126101ff57879251908961052e565b503d61056c565b346101ff5760403660031901126101ff5760206105aa611621565b6105b2611637565b60018060a01b03809216600052600583528160406000209116600052825260406000205416604051908152f35b346101ff5760203660031901126101ff576004356000526003602052602060ff600260406000200154166040519015158152f35b346101ff5760403660031901126101ff5761001b600435610632611637565b9080600052600060205261064d6001604060002001546133f6565b61349a565b60a03660031901126101ff5760043560028110156101ff57610672611637565b6084359160058310156101ff576040926106b59261069f92610692613627565b6064359160443591611779565b6001809392935583519283526020830190611666565bf35b346101ff5760403660031901126101ff5760206106de6106d5611621565b60243590612f95565b604051908152f35b346101ff5760803660031901126101ff5760043560058110156101ff576106de602091610711611637565b906064359160443591611c3a565b346101ff5760003660031901126101ff576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b346101ff5760003660031901126101ff57602060405160008152f35b346101ff5760603660031901126101ff57610799611621565b6107a1611637565b906107aa61337c565b60018060a01b03809116600052600460205260406000209116600052602052604435604060002055600080f35b346101ff5760403660031901126101ff576107f0611637565b600435600052600060205260406000209060018060a01b0316600052602052602060ff604060002054166040519015158152f35b346101ff5760003660031901126101ff576020604051610bb88152f35b346101ff5760003660031901126101ff57602060405169152d02c7e14af68000008152f35b346101ff5760203660031901126101ff5760043560058110156101ff5760ff61089060209261164d565b54166040519015158152f35b346101ff5760603660031901126101ff576108b5611621565b6108bd611637565b6001600160a01b0360443581811693908490036101ff5781906108de61337c565b166000526005602052604060002091166000526020526040600020906bffffffffffffffffffffffff60a01b825416179055600080f35b346101ff5760003660031901126101ff5760206040516127108152f35b346101ff5760403660031901126101ff5760043560058110156101ff57602435801515918282036101ff577f6be7b5903863679a655e520a2395f264a654b5663f6ceb97c8a878f8983534cb926109a760409361098d61337c565b6109968461164d565b9060ff801983541691151516179055565b6109b383518093611666565b6020820152a1005b346101ff5760003660031901126101ff5760206040517f2e8b98eef02e8df3bd27d1270ded3bea3d14db99c5234c7b14001a7fff957bcc8152f35b346101ff5760003660031901126101ff5760206040517fa842d0039ede86e50de3e76d5357314d987325eb17d7eb32afe0fdec2be0031e8152f35b346101ff5760003660031901126101ff576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b346101ff5760403660031901126101ff576024356001600160401b0381116101ff57366023820112156101ff576001600160401b038160040135116101ff576024816004013560051b820101903682116101ff57610ad261337c565b60036004351015610e5a57806004013515610e0957604051610af3816116cf565b6000815260405190610b0482611699565b610b118360040135611ab3565b610b1e6040519182611705565b6004840135815260248401948590602083015b818310610df0575050508252602082015260016040820152600435600052600360205260406000209080518051906001600160401b038211610cd457600160401b8211610cd4576020908454838655808410610da4575b5001908360005260206000209060005b8160051c8110610d575750601f198116808203610cea575b50505050600182016020820151908151916001600160401b038311610cd457600160401b8311610cd4576020908254848455808510610cb7575b500190600052602060002060005b838110610ca3578787610c2188600260408a0151151591019060ff801983541691151516179055565b6040519060408201600435835260406020840152816004013590526060820192906000905b80600401358210610c79577f266370fe8933b3766025a9b1de987798164b818824e57c1057eeb8f9ae71ce3e84860385a1005b90919384359060058210156101ff57602081610c988293600195611666565b019501920190610c46565b600190602084519401938184015501610bf8565b610cce908460005285846000209182019101611b08565b88610bea565b634e487b7160e01b600052604160045260246000fd5b9260009360005b8184038110610d0b5750505060051c015584808080610bb0565b90919485516005811015610d4157610d37602091846001949060ff809160031b9316831b921b19161790565b9601929101610cf1565b634e487b7160e01b600052602160045260246000fd5b6000805b60208110610d70575083820155600101610b98565b949081516005811015610d4157610d9b602091886001949060ff809160031b9316831b921b19161790565b92019501610d5b565b610dd0908660005283600020601f80870160051c82019281881680610dd6575b500160051c0190611b08565b87610b88565b60001990818601918254918a0360031b1c1690558c610dc4565b823560058110156101ff57815260209283019201610b31565b60405162461bcd60e51b815260206004820152602360248201527f456e68616e63656453776170526f757465723a20656d7074792070726f76696460448201526265727360e81b6064820152608490fd5b60405162461bcd60e51b815260206004820152602960248201527f456e68616e63656453776170526f757465723a20696e76616c69642073697a656044820152682063617465676f727960b81b6064820152608490fd5b346101ff5760003660031901126101ff57602060405169021e19e0c9bab24000008152f35b346101ff5760003660031901126101ff576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b346101ff5760403660031901126101ff57610f946020610f39611621565b60405163137dbaf360e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015290911660248083019190915235604482015291829081906064820190565b03817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa801561100d57600090610fdb575b602090604051908152f35b506020813d8211611005575b81610ff460209383611705565b810103126101ff5760209051610fd0565b3d9150610fe7565b6040513d6000823e3d90fd5b346101ff5760403660031901126101ff57611032611621565b61103a611637565b9060018060a01b038091166000526004602052604060002091166000526020526020604060002054604051908152f35b346101ff5760003660031901126101ff576006546040516001600160a01b039091168152602090f35b346101ff5760003660031901126101ff576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b346101ff5760803660031901126101ff576110f1611621565b6110f9611637565b9060443591606435611109613627565b8315611389576001600160a01b039283168015801561137f575b61136d578060005260209460058652846040600020941693846000528652846040600020541691611155831515611b1f565b6040516323b872dd60e01b888201523360248201523060448201526064808201849052815261118f90611189608482611705565b82613552565b60405163095ea7b360e01b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b038116600483015260248201849052919088816044816000865af1801561100d57611340575b50604051936111f8856116b4565b6001855288368187013761120b85611735565b5261012c420180421161132a578894611273946040519361122b8561167d565b8452888785015260408401528660608401526080830152600060a0830152600060c083015260e08201526000604051978880958194630b5e801360e01b835260048301611b9a565b0393165af192831561100d576000936112fb575b5082106112a6578161129a91339061350f565b60018055604051908152f35b60405162461bcd60e51b815260048101849052602760248201527f456e68616e63656453776170526f757465723a20696e73756666696369656e74604482015266081bdd5d1c1d5d60ca1b6064820152608490fd5b9092508381813d8311611323575b6113138183611705565b810103126101ff57519184611287565b503d611309565b634e487b7160e01b600052601160045260246000fd5b61135f90893d8b11611366575b6113578183611705565b810190611b82565b50886111ea565b503d61134d565b60405163d92e233d60e01b8152600490fd5b5083831615611123565b604051631f2a200560e01b8152600490fd5b346101ff5760003660031901126101ff576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b346101ff5760403660031901126101ff576113f9611637565b336001600160a01b038216036114155761001b9060043561349a565b60405163334bd91960e11b8152600490fd5b346101ff5760003660031901126101ff576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b346101ff5760403660031901126101ff5761001b60043561148b611637565b908060005260006020526114a66001604060002001546133f6565b61341c565b346101ff5760003660031901126101ff576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b346101ff5760203660031901126101ff57611509611621565b61151161337c565b600680546001600160a01b0319166001600160a01b0392909216919091179055005b346101ff5760203660031901126101ff5760043560005260006020526020600160406000200154604051908152f35b346101ff5760403660031901126101ff5760206106de611580611621565b60243590612e63565b346101ff5760003660031901126101ff576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b346101ff5760203660031901126101ff576004359063ffffffff60e01b82168092036101ff57602091637965db0b60e01b8114908115611610575b5015158152f35b6301ffc9a760e01b14905083611609565b600435906001600160a01b03821682036101ff57565b602435906001600160a01b03821682036101ff57565b6005811015610d41576000526002602052604060002090565b906005821015610d415752565b60021115610d4157565b61010081019081106001600160401b03821117610cd457604052565b606081019081106001600160401b03821117610cd457604052565b604081019081106001600160401b03821117610cd457604052565b602081019081106001600160401b03821117610cd457604052565b60c081019081106001600160401b03821117610cd457604052565b90601f801991011681019081106001600160401b03821117610cd457604052565b600019811461132a5760010190565b8051156117425760200190565b634e487b7160e01b600052603260045260246000fd5b80518210156117425760209160051b010190565b516005811015610d415790565b94929493919360008515611389576001600160a01b039383851693841561136d576117a3906132e5565b15611a5f576117b183611673565b8215611972575b6117c29087612560565b93815b85518110156119605760ff6117e56117e06103a0848a611758565b61164d565b541615611957576117f96103a08288611758565b60408051635c56a98760e11b815291600491906118199083850190611666565b602488818501528b60448501528c606485015260209081856084818b305af1889581611928575b5061185857505050505061185390611726565b6117c5565b8d85101561186e57505050505061185390611726565b9091939c506118838d9c93959b9c338b61350f565b6118906103a08c8c611758565b965a9560058910156119185750505093611915999795938c7f471477f254242ea7aad26ea1f3bd0deca99d48aa097615152bf8f64ec41f3bf2946080948a986118dc6103a09e9c611673565b82519a8b528a015288015260608701527f00000000000000000000000000000000000000000000000000000000000000001694a4611758565b90565b634e487b7160e01b825260219052fd5b9095508281813d8311611950575b6119408183611705565b810103126101ff57519438611840565b503d611936565b61185390611726565b60405163081ceff360e41b8152600490fd5b90863403611a0a57847f000000000000000000000000000000000000000000000000000000000000000016803b15611a0657818891600460405180948193630d0e30db60e41b83525af180156119fb576119ce575b50906117b8565b6001600160401b0381116119e7576040526117c26119c7565b634e487b7160e01b82526041600452602482fd5b6040513d84823e3d90fd5b5080fd5b60405162461bcd60e51b815260206004820152602760248201527f456e68616e63656453776170526f757465723a2045544820616d6f756e74206d6044820152660d2e6dac2e8c6d60cb1b6064820152608490fd5b60405162461bcd60e51b815260206004820152602660248201527f456e68616e63656453776170526f757465723a20696e76616c696420737461626044820152653632b1b7b4b760d11b6064820152608490fd5b6001600160401b038111610cd45760051b60200190565b90611ad482611ab3565b611ae16040519182611705565b8281528092611af2601f1991611ab3565b0190602036910137565b6005821015610d415752565b818110611b13575050565b60008155600101611b08565b15611b2657565b60405162461bcd60e51b815260206004820152602e60248201527f456e68616e63656453776170526f757465723a20446f646f657820706f6f6c2060448201526d1b9bdd0818dbdb999a59dd5c995960921b6064820152608490fd5b908160209103126101ff575180151581036101ff5790565b602080825261012082019260018060a01b03808251168385015280838301511660408501526040820151606085015260608201516080850152608082015194610100938460a087015286518092528061014087019701926000905b838210611c215750505050508060a060e092015160c085015260c0810151151582850152015191015290565b8451811689529782019793820193600190910190611bf5565b92919092303303612511576005811015610d415780611e3e575060405163095ea7b360e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166004820152602481018290526020818060448101038160007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af1801561100d57611e1f575b5061012c4201421161132a5760405192611cf38461167d565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811685529081166020808601918252610bb86040808801918252306060890190815261012c420160808a0190815260a08a0197885260c08a01988952600060e08b01818152935163414bf38960e01b81529a51881660048c01529551871660248b0152925162ffffff1660448a0152518516606489015290516084880152935160a4870152935160c48601529151811660e48501528391610104918391907f0000000000000000000000000000000000000000000000000000000000000000165af190811561100d57600091611df0575090565b90506020813d602011611e17575b81611e0b60209383611705565b810103126101ff575190565b3d9150611dfe565b611e379060203d602011611366576113578183611705565b5038611cda565b91929160028103612017575060018060a01b0391827f000000000000000000000000000000000000000000000000000000000000000016916000928084526020926005845260409686888720921691828752855286888720541690611ea4821515611b1f565b885163095ea7b360e01b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b038116600483015260248201879052959087816044818c8a5af1801561200d57611ff0575b50895192611f0a846116b4565b60018452873681860137611f1d84611735565b5261012c420193844211611fdc5791611f83959391889795938c5195611f428761167d565b8652888601528b850152606084015260808301528660a08301528660c083015260e0820152858851978880958194630b5e801360e01b835260048301611b9a565b0393165af1938415611fd157508193611f9d575b50505090565b9091809350813d8311611fca575b611fb58183611705565b81010312611fc7575051388080611f97565b80fd5b503d611fab565b51913d9150823e3d90fd5b634e487b7160e01b89526011600452602489fd5b61200690883d8a11611366576113578183611705565b5038611efd565b8b513d8b823e3d90fd5b9092906003810361230a575060018060a01b037f0000000000000000000000000000000000000000000000000000000000000000169283600052600460205260406000209260018060a01b031692836000526020526040600020549283156122b55760405163095ea7b360e01b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031660048201526024810183905260208160448160008a5af1801561100d57612296575b50604051946001600160401b039460c0870186811188821017610cd457604052865260006020870152604086015260608501526080840152604051612116816116cf565b6000815260a0840152604051916080830190811183821017610cd457604052308252600060208301523060408301526000606083015261012c4201421161132a579160a0926040519384926352bbbe2960e01b845260e06004850152805160e4850152602081015161218781611673565b61010485015260408101516000196001841b019081166101248601526060820151166101448501526080810151610164850152015160c061018484015280516101a48401819052919060005b83811061227d57505060006101c4838501810182905285516001600160a01b039081166024870152602080880151151560448801526040880151821660648801526060909701511515608487015260a486019390935261012c420160c4860152601f909301601f191684018490039092019183917f0000000000000000000000000000000000000000000000000000000000000000165af190811561100d57600091611df0575090565b60208282018101516101c48984010152879550016121d3565b6122ae9060203d602011611366576113578183611705565b50386120d2565b60405162461bcd60e51b815260206004820152602760248201527f456e68616e63656453776170526f757465723a20706f6f6c206e6f7420636f6e604482015266199a59dd5c995960ca1b6064820152608490fd5b8390600181036123755760405162461bcd60e51b815260206004820152603360248201527f456e68616e63656453776170526f757465723a20437572766520646972656374604482015272081cddd85c081b9bdd081cdd5c1c1bdc9d1959606a1b6064820152608490fd5b600414806124df575b61239457604051633b136dc160e11b8152600490fd5b6001600160a01b03907f000000000000000000000000000000000000000000000000000000000000000090828216156124cd5760405163095ea7b360e01b81526001600160a01b03929092166004830152602482015290602090829060449082906000907f0000000000000000000000000000000000000000000000000000000000000000165af1801561100d576124af575b60405162461bcd60e51b815260206004820152605460248201527f456e68616e63656453776170526f757465723a2031696e63682072657175697260448201527f657320726f7574652063616c6c646174612066726f6d204150493b207573652060648201527331696e63682061676772656761746f722053444b60601b608482015260a490fd5b6124c69060203d8111611366576113578183611705565b5080612427565b604051631368c7cb60e21b8152600490fd5b507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316151561237e565b60405162461bcd60e51b815260206004820152602160248201527f456e68616e63656453776170526f757465723a20696e7465726e616c206f6e6c6044820152607960f81b6064820152608490fd5b906005811015610d415780151580612e11575b612deb575069021e19e0c9bab2400000811015612dcc575060005b6000526020600381526040806000209080516125a981611699565b815180818680875493848152018760005281600020936000905b80601f830110612b58576126df95549184828210612b3e575b828210612b21575b828210612b04575b828210612ae7575b828210612acb575b828210612aae575b828210612a91575b828210612a74575b8a838310612a57575b50828210612a3a575b828210612a1d575b828210612a00575b8282106129e3575b8282106129c6575b8282106129a9575b82821061298c575b82821061296f575b828210612952575b828210612935575b828210612918575b8282106128fb575b8282106128de575b8282106128c1575b8282106128a4575b828210612887575b82821061286a575b82821061284d575b828210612830575b828210612813575b8282106127f6575b8282106127d9575b50106127c3575b5090500382611705565b815260019283810183519081878254918281520191600052876000209060005b888a8383106127b1575050505050918161271f60029360ff950382611705565b8785015201541615158083830152806127a6575b61279e575060a0815193612746856116ea565b600585523690850137600261275a84611735565b52825182101561174257600090830152815160021015611742576003606083015281516003101561174257608082015280516004101561174257600460a082015290565b925050505190565b508051511515612733565b845486529094019392830192016126ff565b816127d09160f81c611666565b018790386126d5565b846127ed6001939660ff8760f01c16611666565b019301846126ce565b8461280a6001939660ff8760e81c16611666565b019301846126c6565b846128276001939660ff8760e01c16611666565b019301846126be565b846128446001939660ff8760d81c16611666565b019301846126b6565b846128616001939660ff8760d01c16611666565b019301846126ae565b8461287e6001939660ff8760c81c16611666565b019301846126a6565b8461289b6001939660ff8760c01c16611666565b0193018461269e565b846128b86001939660ff8760b81c16611666565b01930184612696565b846128d56001939660ff8760b01c16611666565b0193018461268e565b846128f26001939660ff8760a81c16611666565b01930184612686565b8461290f6001939660ff8760a01c16611666565b0193018461267e565b8461292c6001939660ff8760981c16611666565b01930184612676565b846129496001939660ff8760901c16611666565b0193018461266e565b846129666001939660ff8760881c16611666565b01930184612666565b846129836001939660ff8760801c16611666565b0193018461265e565b846129a06001939660ff8760781c16611666565b01930184612656565b846129bd6001939660ff8760701c16611666565b0193018461264e565b846129da6001939660ff8760681c16611666565b01930184612646565b846129f76001939660ff8760601c16611666565b0193018461263e565b84612a146001939660ff8760581c16611666565b01930184612636565b84612a316001939660ff8760501c16611666565b0193018461262e565b84612a4e6001939660ff8760481c16611666565b01930184612626565b94612a6a8160ff87600196991c16611666565b019301848a61261d565b84612a886001939660ff8760381c16611666565b01930184612614565b84612aa56001939660ff8760301c16611666565b0193018461260c565b84612ac26001939660ff8760281c16611666565b01930184612604565b84612ade6001939660ff87851c16611666565b019301846125fc565b84612afb6001939660ff8760181c16611666565b019301846125f4565b84612b186001939660ff8760101c16611666565b019301846125ec565b84612b356001939660ff8760081c16611666565b019301846125e4565b84612b4f6001939660ff8716611666565b019301846125dc565b9291600191945061040090612dbc8a612dae86612d8b612c1a612d438d5495612cfb89612cb360ff97612b8d838a8d16611666565b612b9e8184018a8d60081c16611666565b612baf8584018a8d60101c16611666565b888b610200606095612bc8878201858560181c16611666565b612bdb6080958585888501921c16611666565b612c7160a097612bf2898401878760281c16611666565b612c2960c09b612c098d8601898960301c16611666565b60e09e8f8601898960381c16611666565b87876101008701921c16611666565b612c3c6101208401878760481c16611666565b612c4f6101408401878760501c16611666565b612c626101608401878760581c16611666565b85856101808501921c16611666565b612c846101a08201858560681c16611666565b612c976101c08201858560701c16611666565b612caa6101e08201858560781c16611666565b01921c16611666565b612cc66102208c01888b60881c16611666565b612cd96102408c01888b60901c16611666565b612cec6102608c01888b60981c16611666565b86896102808d01921c16611666565b612d0e6102a08a01868960a81c16611666565b612d216102c08a01868960b01c16611666565b612d346102e08a01868960b81c16611666565b84876103008b01921c16611666565b612d566103208801848760c81c16611666565b612d696103408801848760d01c16611666565b612d7c6103608801848760d81c16611666565b82856103808901921c16611666565b612d9e6103a08601828560e81c16611666565b6103c08501908360f01c16611666565b6103e083019060f81c611666565b01940192019284929389926125c3565b69152d02c7e14af68000001115612de457600161258e565b600261258e565b905061191560405191612dfd836116b4565b60018352602036818501376103af83611735565b5060ff612e1d8261164d565b5416612573565b3d15612e5e573d906001600160401b038211610cd45760405191612e52601f8201601f191660200184611705565b82523d6000602084013e565b606090565b6006546001600160a01b0390811680151580612f86575b612eb0575b5050612e8a906132e5565b612e945750600090565b6126de9081810291818304149015171561132a57612710900490565b60405191602083019063f7729d4360e01b8252807f000000000000000000000000000000000000000000000000000000000000000016602485015284166044840152610bb860648401528460848401526000928360a482015260a4815260e081018181106001600160401b03821117612f72576040525183928392905afa90612f37612e24565b9180612f66575b15612e7f57602082805181010312611fc757506020015180612f605780612e7f565b91505090565b50602082511015612f3e565b634e487b7160e01b85526041600452602485fd5b50612f90836132e5565b612e7a565b9060018060a01b0391827f0000000000000000000000000000000000000000000000000000000000000000166000938185526020916004835260409182872091818616928389528552838820549384613032575b505050505050612ff8906132e5565b613000575090565b906126de9182810292818404149015171561301e5750612710900490565b634e487b7160e01b81526011600452602490fd5b805194631f29a8cd60e31b865260048601528885602481867f0000000000000000000000000000000000000000000000000000000000000000165afa9485156132db5789968a966131c5575b505050600285511015806131b9575b613098575b80612fe9565b9397929691959094600019908198845b8b518110156130fa5789898d8a826130c08684611758565b5116146130f0575b836130d291611758565b5116146130e8575b6130e390611726565b6130a8565b9950896130da565b92955085926130c8565b5094995094509450945094600019841415806131ad575b8061319a575b61312357808394613092565b8161312f929350611758565b5192838102938185041490151715613186579061314b91611758565b519081156131725704906126de9182810292818404149015171561301e5750612710900490565b634e487b7160e01b83526012600452602483fd5b634e487b7160e01b84526011600452602484fd5b506131a58483611758565b511515613117565b50600019811415613111565b5060028451101561308d565b9196509194503d808a843e6131da8184611705565b82016060838203126132d75782516001600160401b03908181116132af5784019382601f860112156132af5784519461321286611ab3565b9561321f8b519788611705565b808752858088019160051b830101918583116132d3578601905b8282106132b757505050838101519182116132af570181601f820112156132b35780519061327261326983611ab3565b9951998a611705565b81895283808a019260051b8201019283116132af578301905b8282106132a05750505050939238808061307e565b8151815290830190830161328b565b8b80fd5b8a80fd5b815189811681036132cf578152908601908601613239565b8f80fd5b8e80fd5b8980fd5b81513d8b823e3d90fd5b6001600160a01b039081167f000000000000000000000000000000000000000000000000000000000000000082168114918215613350575b821561332857505090565b7f00000000000000000000000000000000000000000000000000000000000000001614919050565b7f000000000000000000000000000000000000000000000000000000000000000081168214925061331d565b3360009081527f17e306466f0d09a5f30cdc36b7cbca18c119dc1a4639b791678f67eca9a1571360205260409020547fa842d0039ede86e50de3e76d5357314d987325eb17d7eb32afe0fdec2be0031e9060ff16156133d85750565b6044906040519063e2517d3f60e01b82523360048301526024820152fd5b80600052600060205260406000203360005260205260ff60406000205416156133d85750565b9060009180835282602052604083209160018060a01b03169182845260205260ff6040842054161560001461349557808352826020526040832082845260205260408320600160ff198254161790557f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d339380a4600190565b505090565b9060009180835282602052604083209160018060a01b03169182845260205260ff6040842054166000146134955780835282602052604083208284526020526040832060ff1981541690557ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b339380a4600190565b60405163a9059cbb60e01b60208201526001600160a01b039290921660248301526044808301939093529181526135509161354b606483611705565b613552565b565b60008061357b9260018060a01b03169360208151910182865af1613574612e24565b90836135c4565b80519081151591826135a9575b50506135915750565b60249060405190635274afe760e01b82526004820152fd5b6135bc9250602080918301019101611b82565b153880613588565b906135eb57508051156135d957805190602001fd5b604051630a12f52160e11b8152600490fd5b8151158061361e575b6135fc575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b156135f4565b600260015414613638576002600155565b604051633ee5aeb560e01b8152600490fdfea264697066735822122046a67042375eaf85066a73901de0c3e794f11bf746a06101cf6e17fbf9b9758a64736f6c6343000814003300000000000000000000000068b3465833fb72a70ecdf485e0e4c7bd8665fc45000000000000000000000000bebc44782c7db0a1a60cb6fe97d0b483032ff1c7000000000000000000000000a356867fdcea8e71aeaf87805808803806231fdc000000000000000000000000ba12222222228d8ba445958a75a0704d566bf2c80000000000000000000000001111111254eeb25477b68fb85ed929f73a960582000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000006b175474e89094c44da98b954eedeac495271d0f
Deployed Bytecode
0x608080604052600436101561001d575b50361561001b57600080fd5b005b60003560e01c90816301ffc9a7146115ce57508063158274a5146115895780631c28242a14611562578063248a9ca31461153357806326158136146114f05780632c76d7a6146114ab5780632f2ff15d1461146c5780632f48ab7d1461142757806336568abe146113e05780633e413bee1461139b5780633ee2afc1146110d85780633fc8cef3146110935780634db4a3521461106a5780634f214fd31461101957806352e25bce14610f1b57806355470d8714610ed65780635559294314610eb157806359fbc2d214610a7657806363a6b1da14610a3157806365a5292e146109f65780636b366cb5146109bb5780636c04a824146109325780637574d9a0146109155780637c47ddd01461089c57806381cfa7a01461086657806382cb9ae8146108415780638f40e8f51461082457806391d14854146107d757806395e42ded14610780578063a217fddf14610764578063ac3af2081461071f578063b8ad530e146106e6578063c5b35f63146106b7578063cb29ac5c14610652578063d547741f14610613578063d713da52146105df578063de5663141461058f578063e785f45b14610249578063f4b9fa75146102045763f6b9ec7c146101e2573861000f565b346101ff5760003660031901126101ff5760206040516101f48152f35b600080fd5b346101ff5760003660031901126101ff576040517f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f6001600160a01b03168152602090f35b346101ff5760403660031901126101ff57610262611621565b60405160243591610272826116ea565b6005825260209260a036858501376040519161028d836116ea565b6005835260a0368685013784600092600080526002825260ff604060002054166104fa575b60026000526002825260ff60406000205416610465575b60036000526002825260ff604060002054166103d4575b5050506102ec81611aca565b916102f682611aca565b9360005b83811061038c5786858760405192839260408401604085528151809152826060860192019060005b818110610368575050508381038285015281808451928381520193019160005b82811061035157505050500390f35b835185528695509381019392810192600101610342565b919495509183808261037d6001948951611666565b01950191019186959492610322565b806103b46103a56103a06103cf9486611758565b61176c565b6103af8389611758565b611afc565b6103be8185611758565b516103c98289611758565b52611726565b6102fa565b60405163c5b35f6360e01b81526001600160a01b03939093166004840152602483015281604481305afa60009181610436575b50610414575b84816102e0565b906104309160036104258387611758565b526103c98285611758565b8461040d565b9091508581813d831161045e575b61044e8183611705565b810103126101ff57519086610407565b503d610444565b6040516329712de760e11b81526001600160a01b0384166004820152602481018290528281604481305afa600091816104c9575b506104a5575b506102c9565b936104c2919460026104b7838a611758565b526103c98288611758565b928761049f565b8481959293503d83116104f3575b6104e18183611705565b810103126101ff578792519089610499565b503d6104d7565b604051630e14121560e11b81526001600160a01b0384166004820152602481018290528281604481305afa6000918161055e575b5061053a575b506102b2565b91509250600061054986611735565b5261055384611735565b528460019287610534565b8481959293503d8311610588575b6105768183611705565b810103126101ff57879251908961052e565b503d61056c565b346101ff5760403660031901126101ff5760206105aa611621565b6105b2611637565b60018060a01b03809216600052600583528160406000209116600052825260406000205416604051908152f35b346101ff5760203660031901126101ff576004356000526003602052602060ff600260406000200154166040519015158152f35b346101ff5760403660031901126101ff5761001b600435610632611637565b9080600052600060205261064d6001604060002001546133f6565b61349a565b60a03660031901126101ff5760043560028110156101ff57610672611637565b6084359160058310156101ff576040926106b59261069f92610692613627565b6064359160443591611779565b6001809392935583519283526020830190611666565bf35b346101ff5760403660031901126101ff5760206106de6106d5611621565b60243590612f95565b604051908152f35b346101ff5760803660031901126101ff5760043560058110156101ff576106de602091610711611637565b906064359160443591611c3a565b346101ff5760003660031901126101ff576040517f0000000000000000000000001111111254eeb25477b68fb85ed929f73a9605826001600160a01b03168152602090f35b346101ff5760003660031901126101ff57602060405160008152f35b346101ff5760603660031901126101ff57610799611621565b6107a1611637565b906107aa61337c565b60018060a01b03809116600052600460205260406000209116600052602052604435604060002055600080f35b346101ff5760403660031901126101ff576107f0611637565b600435600052600060205260406000209060018060a01b0316600052602052602060ff604060002054166040519015158152f35b346101ff5760003660031901126101ff576020604051610bb88152f35b346101ff5760003660031901126101ff57602060405169152d02c7e14af68000008152f35b346101ff5760203660031901126101ff5760043560058110156101ff5760ff61089060209261164d565b54166040519015158152f35b346101ff5760603660031901126101ff576108b5611621565b6108bd611637565b6001600160a01b0360443581811693908490036101ff5781906108de61337c565b166000526005602052604060002091166000526020526040600020906bffffffffffffffffffffffff60a01b825416179055600080f35b346101ff5760003660031901126101ff5760206040516127108152f35b346101ff5760403660031901126101ff5760043560058110156101ff57602435801515918282036101ff577f6be7b5903863679a655e520a2395f264a654b5663f6ceb97c8a878f8983534cb926109a760409361098d61337c565b6109968461164d565b9060ff801983541691151516179055565b6109b383518093611666565b6020820152a1005b346101ff5760003660031901126101ff5760206040517f2e8b98eef02e8df3bd27d1270ded3bea3d14db99c5234c7b14001a7fff957bcc8152f35b346101ff5760003660031901126101ff5760206040517fa842d0039ede86e50de3e76d5357314d987325eb17d7eb32afe0fdec2be0031e8152f35b346101ff5760003660031901126101ff576040517f000000000000000000000000bebc44782c7db0a1a60cb6fe97d0b483032ff1c76001600160a01b03168152602090f35b346101ff5760403660031901126101ff576024356001600160401b0381116101ff57366023820112156101ff576001600160401b038160040135116101ff576024816004013560051b820101903682116101ff57610ad261337c565b60036004351015610e5a57806004013515610e0957604051610af3816116cf565b6000815260405190610b0482611699565b610b118360040135611ab3565b610b1e6040519182611705565b6004840135815260248401948590602083015b818310610df0575050508252602082015260016040820152600435600052600360205260406000209080518051906001600160401b038211610cd457600160401b8211610cd4576020908454838655808410610da4575b5001908360005260206000209060005b8160051c8110610d575750601f198116808203610cea575b50505050600182016020820151908151916001600160401b038311610cd457600160401b8311610cd4576020908254848455808510610cb7575b500190600052602060002060005b838110610ca3578787610c2188600260408a0151151591019060ff801983541691151516179055565b6040519060408201600435835260406020840152816004013590526060820192906000905b80600401358210610c79577f266370fe8933b3766025a9b1de987798164b818824e57c1057eeb8f9ae71ce3e84860385a1005b90919384359060058210156101ff57602081610c988293600195611666565b019501920190610c46565b600190602084519401938184015501610bf8565b610cce908460005285846000209182019101611b08565b88610bea565b634e487b7160e01b600052604160045260246000fd5b9260009360005b8184038110610d0b5750505060051c015584808080610bb0565b90919485516005811015610d4157610d37602091846001949060ff809160031b9316831b921b19161790565b9601929101610cf1565b634e487b7160e01b600052602160045260246000fd5b6000805b60208110610d70575083820155600101610b98565b949081516005811015610d4157610d9b602091886001949060ff809160031b9316831b921b19161790565b92019501610d5b565b610dd0908660005283600020601f80870160051c82019281881680610dd6575b500160051c0190611b08565b87610b88565b60001990818601918254918a0360031b1c1690558c610dc4565b823560058110156101ff57815260209283019201610b31565b60405162461bcd60e51b815260206004820152602360248201527f456e68616e63656453776170526f757465723a20656d7074792070726f76696460448201526265727360e81b6064820152608490fd5b60405162461bcd60e51b815260206004820152602960248201527f456e68616e63656453776170526f757465723a20696e76616c69642073697a656044820152682063617465676f727960b81b6064820152608490fd5b346101ff5760003660031901126101ff57602060405169021e19e0c9bab24000008152f35b346101ff5760003660031901126101ff576040517f000000000000000000000000a356867fdcea8e71aeaf87805808803806231fdc6001600160a01b03168152602090f35b346101ff5760403660031901126101ff57610f946020610f39611621565b60405163137dbaf360e01b81526001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc28116600483015290911660248083019190915235604482015291829081906064820190565b03817f000000000000000000000000a356867fdcea8e71aeaf87805808803806231fdc6001600160a01b03165afa801561100d57600090610fdb575b602090604051908152f35b506020813d8211611005575b81610ff460209383611705565b810103126101ff5760209051610fd0565b3d9150610fe7565b6040513d6000823e3d90fd5b346101ff5760403660031901126101ff57611032611621565b61103a611637565b9060018060a01b038091166000526004602052604060002091166000526020526020604060002054604051908152f35b346101ff5760003660031901126101ff576006546040516001600160a01b039091168152602090f35b346101ff5760003660031901126101ff576040517f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b03168152602090f35b346101ff5760803660031901126101ff576110f1611621565b6110f9611637565b9060443591606435611109613627565b8315611389576001600160a01b039283168015801561137f575b61136d578060005260209460058652846040600020941693846000528652846040600020541691611155831515611b1f565b6040516323b872dd60e01b888201523360248201523060448201526064808201849052815261118f90611189608482611705565b82613552565b60405163095ea7b360e01b81527f000000000000000000000000a356867fdcea8e71aeaf87805808803806231fdc6001600160a01b038116600483015260248201849052919088816044816000865af1801561100d57611340575b50604051936111f8856116b4565b6001855288368187013761120b85611735565b5261012c420180421161132a578894611273946040519361122b8561167d565b8452888785015260408401528660608401526080830152600060a0830152600060c083015260e08201526000604051978880958194630b5e801360e01b835260048301611b9a565b0393165af192831561100d576000936112fb575b5082106112a6578161129a91339061350f565b60018055604051908152f35b60405162461bcd60e51b815260048101849052602760248201527f456e68616e63656453776170526f757465723a20696e73756666696369656e74604482015266081bdd5d1c1d5d60ca1b6064820152608490fd5b9092508381813d8311611323575b6113138183611705565b810103126101ff57519184611287565b503d611309565b634e487b7160e01b600052601160045260246000fd5b61135f90893d8b11611366575b6113578183611705565b810190611b82565b50886111ea565b503d61134d565b60405163d92e233d60e01b8152600490fd5b5083831615611123565b604051631f2a200560e01b8152600490fd5b346101ff5760003660031901126101ff576040517f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b03168152602090f35b346101ff5760403660031901126101ff576113f9611637565b336001600160a01b038216036114155761001b9060043561349a565b60405163334bd91960e11b8152600490fd5b346101ff5760003660031901126101ff576040517f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec76001600160a01b03168152602090f35b346101ff5760403660031901126101ff5761001b60043561148b611637565b908060005260006020526114a66001604060002001546133f6565b61341c565b346101ff5760003660031901126101ff576040517f00000000000000000000000068b3465833fb72a70ecdf485e0e4c7bd8665fc456001600160a01b03168152602090f35b346101ff5760203660031901126101ff57611509611621565b61151161337c565b600680546001600160a01b0319166001600160a01b0392909216919091179055005b346101ff5760203660031901126101ff5760043560005260006020526020600160406000200154604051908152f35b346101ff5760403660031901126101ff5760206106de611580611621565b60243590612e63565b346101ff5760003660031901126101ff576040517f000000000000000000000000ba12222222228d8ba445958a75a0704d566bf2c86001600160a01b03168152602090f35b346101ff5760203660031901126101ff576004359063ffffffff60e01b82168092036101ff57602091637965db0b60e01b8114908115611610575b5015158152f35b6301ffc9a760e01b14905083611609565b600435906001600160a01b03821682036101ff57565b602435906001600160a01b03821682036101ff57565b6005811015610d41576000526002602052604060002090565b906005821015610d415752565b60021115610d4157565b61010081019081106001600160401b03821117610cd457604052565b606081019081106001600160401b03821117610cd457604052565b604081019081106001600160401b03821117610cd457604052565b602081019081106001600160401b03821117610cd457604052565b60c081019081106001600160401b03821117610cd457604052565b90601f801991011681019081106001600160401b03821117610cd457604052565b600019811461132a5760010190565b8051156117425760200190565b634e487b7160e01b600052603260045260246000fd5b80518210156117425760209160051b010190565b516005811015610d415790565b94929493919360008515611389576001600160a01b039383851693841561136d576117a3906132e5565b15611a5f576117b183611673565b8215611972575b6117c29087612560565b93815b85518110156119605760ff6117e56117e06103a0848a611758565b61164d565b541615611957576117f96103a08288611758565b60408051635c56a98760e11b815291600491906118199083850190611666565b602488818501528b60448501528c606485015260209081856084818b305af1889581611928575b5061185857505050505061185390611726565b6117c5565b8d85101561186e57505050505061185390611726565b9091939c506118838d9c93959b9c338b61350f565b6118906103a08c8c611758565b965a9560058910156119185750505093611915999795938c7f471477f254242ea7aad26ea1f3bd0deca99d48aa097615152bf8f64ec41f3bf2946080948a986118dc6103a09e9c611673565b82519a8b528a015288015260608701527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21694a4611758565b90565b634e487b7160e01b825260219052fd5b9095508281813d8311611950575b6119408183611705565b810103126101ff57519438611840565b503d611936565b61185390611726565b60405163081ceff360e41b8152600490fd5b90863403611a0a57847f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216803b15611a0657818891600460405180948193630d0e30db60e41b83525af180156119fb576119ce575b50906117b8565b6001600160401b0381116119e7576040526117c26119c7565b634e487b7160e01b82526041600452602482fd5b6040513d84823e3d90fd5b5080fd5b60405162461bcd60e51b815260206004820152602760248201527f456e68616e63656453776170526f757465723a2045544820616d6f756e74206d6044820152660d2e6dac2e8c6d60cb1b6064820152608490fd5b60405162461bcd60e51b815260206004820152602660248201527f456e68616e63656453776170526f757465723a20696e76616c696420737461626044820152653632b1b7b4b760d11b6064820152608490fd5b6001600160401b038111610cd45760051b60200190565b90611ad482611ab3565b611ae16040519182611705565b8281528092611af2601f1991611ab3565b0190602036910137565b6005821015610d415752565b818110611b13575050565b60008155600101611b08565b15611b2657565b60405162461bcd60e51b815260206004820152602e60248201527f456e68616e63656453776170526f757465723a20446f646f657820706f6f6c2060448201526d1b9bdd0818dbdb999a59dd5c995960921b6064820152608490fd5b908160209103126101ff575180151581036101ff5790565b602080825261012082019260018060a01b03808251168385015280838301511660408501526040820151606085015260608201516080850152608082015194610100938460a087015286518092528061014087019701926000905b838210611c215750505050508060a060e092015160c085015260c0810151151582850152015191015290565b8451811689529782019793820193600190910190611bf5565b92919092303303612511576005811015610d415780611e3e575060405163095ea7b360e01b81526001600160a01b037f00000000000000000000000068b3465833fb72a70ecdf485e0e4c7bd8665fc45166004820152602481018290526020818060448101038160007f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b03165af1801561100d57611e1f575b5061012c4201421161132a5760405192611cf38461167d565b6001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2811685529081166020808601918252610bb86040808801918252306060890190815261012c420160808a0190815260a08a0197885260c08a01988952600060e08b01818152935163414bf38960e01b81529a51881660048c01529551871660248b0152925162ffffff1660448a0152518516606489015290516084880152935160a4870152935160c48601529151811660e48501528391610104918391907f00000000000000000000000068b3465833fb72a70ecdf485e0e4c7bd8665fc45165af190811561100d57600091611df0575090565b90506020813d602011611e17575b81611e0b60209383611705565b810103126101ff575190565b3d9150611dfe565b611e379060203d602011611366576113578183611705565b5038611cda565b91929160028103612017575060018060a01b0391827f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216916000928084526020926005845260409686888720921691828752855286888720541690611ea4821515611b1f565b885163095ea7b360e01b81527f000000000000000000000000a356867fdcea8e71aeaf87805808803806231fdc6001600160a01b038116600483015260248201879052959087816044818c8a5af1801561200d57611ff0575b50895192611f0a846116b4565b60018452873681860137611f1d84611735565b5261012c420193844211611fdc5791611f83959391889795938c5195611f428761167d565b8652888601528b850152606084015260808301528660a08301528660c083015260e0820152858851978880958194630b5e801360e01b835260048301611b9a565b0393165af1938415611fd157508193611f9d575b50505090565b9091809350813d8311611fca575b611fb58183611705565b81010312611fc7575051388080611f97565b80fd5b503d611fab565b51913d9150823e3d90fd5b634e487b7160e01b89526011600452602489fd5b61200690883d8a11611366576113578183611705565b5038611efd565b8b513d8b823e3d90fd5b9092906003810361230a575060018060a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2169283600052600460205260406000209260018060a01b031692836000526020526040600020549283156122b55760405163095ea7b360e01b81527f000000000000000000000000ba12222222228d8ba445958a75a0704d566bf2c86001600160a01b031660048201526024810183905260208160448160008a5af1801561100d57612296575b50604051946001600160401b039460c0870186811188821017610cd457604052865260006020870152604086015260608501526080840152604051612116816116cf565b6000815260a0840152604051916080830190811183821017610cd457604052308252600060208301523060408301526000606083015261012c4201421161132a579160a0926040519384926352bbbe2960e01b845260e06004850152805160e4850152602081015161218781611673565b61010485015260408101516000196001841b019081166101248601526060820151166101448501526080810151610164850152015160c061018484015280516101a48401819052919060005b83811061227d57505060006101c4838501810182905285516001600160a01b039081166024870152602080880151151560448801526040880151821660648801526060909701511515608487015260a486019390935261012c420160c4860152601f909301601f191684018490039092019183917f000000000000000000000000ba12222222228d8ba445958a75a0704d566bf2c8165af190811561100d57600091611df0575090565b60208282018101516101c48984010152879550016121d3565b6122ae9060203d602011611366576113578183611705565b50386120d2565b60405162461bcd60e51b815260206004820152602760248201527f456e68616e63656453776170526f757465723a20706f6f6c206e6f7420636f6e604482015266199a59dd5c995960ca1b6064820152608490fd5b8390600181036123755760405162461bcd60e51b815260206004820152603360248201527f456e68616e63656453776170526f757465723a20437572766520646972656374604482015272081cddd85c081b9bdd081cdd5c1c1bdc9d1959606a1b6064820152608490fd5b600414806124df575b61239457604051633b136dc160e11b8152600490fd5b6001600160a01b03907f0000000000000000000000001111111254eeb25477b68fb85ed929f73a96058290828216156124cd5760405163095ea7b360e01b81526001600160a01b03929092166004830152602482015290602090829060449082906000907f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2165af1801561100d576124af575b60405162461bcd60e51b815260206004820152605460248201527f456e68616e63656453776170526f757465723a2031696e63682072657175697260448201527f657320726f7574652063616c6c646174612066726f6d204150493b207573652060648201527331696e63682061676772656761746f722053444b60601b608482015260a490fd5b6124c69060203d8111611366576113578183611705565b5080612427565b604051631368c7cb60e21b8152600490fd5b507f0000000000000000000000001111111254eeb25477b68fb85ed929f73a9605826001600160a01b0316151561237e565b60405162461bcd60e51b815260206004820152602160248201527f456e68616e63656453776170526f757465723a20696e7465726e616c206f6e6c6044820152607960f81b6064820152608490fd5b906005811015610d415780151580612e11575b612deb575069021e19e0c9bab2400000811015612dcc575060005b6000526020600381526040806000209080516125a981611699565b815180818680875493848152018760005281600020936000905b80601f830110612b58576126df95549184828210612b3e575b828210612b21575b828210612b04575b828210612ae7575b828210612acb575b828210612aae575b828210612a91575b828210612a74575b8a838310612a57575b50828210612a3a575b828210612a1d575b828210612a00575b8282106129e3575b8282106129c6575b8282106129a9575b82821061298c575b82821061296f575b828210612952575b828210612935575b828210612918575b8282106128fb575b8282106128de575b8282106128c1575b8282106128a4575b828210612887575b82821061286a575b82821061284d575b828210612830575b828210612813575b8282106127f6575b8282106127d9575b50106127c3575b5090500382611705565b815260019283810183519081878254918281520191600052876000209060005b888a8383106127b1575050505050918161271f60029360ff950382611705565b8785015201541615158083830152806127a6575b61279e575060a0815193612746856116ea565b600585523690850137600261275a84611735565b52825182101561174257600090830152815160021015611742576003606083015281516003101561174257608082015280516004101561174257600460a082015290565b925050505190565b508051511515612733565b845486529094019392830192016126ff565b816127d09160f81c611666565b018790386126d5565b846127ed6001939660ff8760f01c16611666565b019301846126ce565b8461280a6001939660ff8760e81c16611666565b019301846126c6565b846128276001939660ff8760e01c16611666565b019301846126be565b846128446001939660ff8760d81c16611666565b019301846126b6565b846128616001939660ff8760d01c16611666565b019301846126ae565b8461287e6001939660ff8760c81c16611666565b019301846126a6565b8461289b6001939660ff8760c01c16611666565b0193018461269e565b846128b86001939660ff8760b81c16611666565b01930184612696565b846128d56001939660ff8760b01c16611666565b0193018461268e565b846128f26001939660ff8760a81c16611666565b01930184612686565b8461290f6001939660ff8760a01c16611666565b0193018461267e565b8461292c6001939660ff8760981c16611666565b01930184612676565b846129496001939660ff8760901c16611666565b0193018461266e565b846129666001939660ff8760881c16611666565b01930184612666565b846129836001939660ff8760801c16611666565b0193018461265e565b846129a06001939660ff8760781c16611666565b01930184612656565b846129bd6001939660ff8760701c16611666565b0193018461264e565b846129da6001939660ff8760681c16611666565b01930184612646565b846129f76001939660ff8760601c16611666565b0193018461263e565b84612a146001939660ff8760581c16611666565b01930184612636565b84612a316001939660ff8760501c16611666565b0193018461262e565b84612a4e6001939660ff8760481c16611666565b01930184612626565b94612a6a8160ff87600196991c16611666565b019301848a61261d565b84612a886001939660ff8760381c16611666565b01930184612614565b84612aa56001939660ff8760301c16611666565b0193018461260c565b84612ac26001939660ff8760281c16611666565b01930184612604565b84612ade6001939660ff87851c16611666565b019301846125fc565b84612afb6001939660ff8760181c16611666565b019301846125f4565b84612b186001939660ff8760101c16611666565b019301846125ec565b84612b356001939660ff8760081c16611666565b019301846125e4565b84612b4f6001939660ff8716611666565b019301846125dc565b9291600191945061040090612dbc8a612dae86612d8b612c1a612d438d5495612cfb89612cb360ff97612b8d838a8d16611666565b612b9e8184018a8d60081c16611666565b612baf8584018a8d60101c16611666565b888b610200606095612bc8878201858560181c16611666565b612bdb6080958585888501921c16611666565b612c7160a097612bf2898401878760281c16611666565b612c2960c09b612c098d8601898960301c16611666565b60e09e8f8601898960381c16611666565b87876101008701921c16611666565b612c3c6101208401878760481c16611666565b612c4f6101408401878760501c16611666565b612c626101608401878760581c16611666565b85856101808501921c16611666565b612c846101a08201858560681c16611666565b612c976101c08201858560701c16611666565b612caa6101e08201858560781c16611666565b01921c16611666565b612cc66102208c01888b60881c16611666565b612cd96102408c01888b60901c16611666565b612cec6102608c01888b60981c16611666565b86896102808d01921c16611666565b612d0e6102a08a01868960a81c16611666565b612d216102c08a01868960b01c16611666565b612d346102e08a01868960b81c16611666565b84876103008b01921c16611666565b612d566103208801848760c81c16611666565b612d696103408801848760d01c16611666565b612d7c6103608801848760d81c16611666565b82856103808901921c16611666565b612d9e6103a08601828560e81c16611666565b6103c08501908360f01c16611666565b6103e083019060f81c611666565b01940192019284929389926125c3565b69152d02c7e14af68000001115612de457600161258e565b600261258e565b905061191560405191612dfd836116b4565b60018352602036818501376103af83611735565b5060ff612e1d8261164d565b5416612573565b3d15612e5e573d906001600160401b038211610cd45760405191612e52601f8201601f191660200184611705565b82523d6000602084013e565b606090565b6006546001600160a01b0390811680151580612f86575b612eb0575b5050612e8a906132e5565b612e945750600090565b6126de9081810291818304149015171561132a57612710900490565b60405191602083019063f7729d4360e01b8252807f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216602485015284166044840152610bb860648401528460848401526000928360a482015260a4815260e081018181106001600160401b03821117612f72576040525183928392905afa90612f37612e24565b9180612f66575b15612e7f57602082805181010312611fc757506020015180612f605780612e7f565b91505090565b50602082511015612f3e565b634e487b7160e01b85526041600452602485fd5b50612f90836132e5565b612e7a565b9060018060a01b0391827f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2166000938185526020916004835260409182872091818616928389528552838820549384613032575b505050505050612ff8906132e5565b613000575090565b906126de9182810292818404149015171561301e5750612710900490565b634e487b7160e01b81526011600452602490fd5b805194631f29a8cd60e31b865260048601528885602481867f000000000000000000000000ba12222222228d8ba445958a75a0704d566bf2c8165afa9485156132db5789968a966131c5575b505050600285511015806131b9575b613098575b80612fe9565b9397929691959094600019908198845b8b518110156130fa5789898d8a826130c08684611758565b5116146130f0575b836130d291611758565b5116146130e8575b6130e390611726565b6130a8565b9950896130da565b92955085926130c8565b5094995094509450945094600019841415806131ad575b8061319a575b61312357808394613092565b8161312f929350611758565b5192838102938185041490151715613186579061314b91611758565b519081156131725704906126de9182810292818404149015171561301e5750612710900490565b634e487b7160e01b83526012600452602483fd5b634e487b7160e01b84526011600452602484fd5b506131a58483611758565b511515613117565b50600019811415613111565b5060028451101561308d565b9196509194503d808a843e6131da8184611705565b82016060838203126132d75782516001600160401b03908181116132af5784019382601f860112156132af5784519461321286611ab3565b9561321f8b519788611705565b808752858088019160051b830101918583116132d3578601905b8282106132b757505050838101519182116132af570181601f820112156132b35780519061327261326983611ab3565b9951998a611705565b81895283808a019260051b8201019283116132af578301905b8282106132a05750505050939238808061307e565b8151815290830190830161328b565b8b80fd5b8a80fd5b815189811681036132cf578152908601908601613239565b8f80fd5b8e80fd5b8980fd5b81513d8b823e3d90fd5b6001600160a01b039081167f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec782168114918215613350575b821561332857505090565b7f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f1614919050565b7f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4881168214925061331d565b3360009081527f17e306466f0d09a5f30cdc36b7cbca18c119dc1a4639b791678f67eca9a1571360205260409020547fa842d0039ede86e50de3e76d5357314d987325eb17d7eb32afe0fdec2be0031e9060ff16156133d85750565b6044906040519063e2517d3f60e01b82523360048301526024820152fd5b80600052600060205260406000203360005260205260ff60406000205416156133d85750565b9060009180835282602052604083209160018060a01b03169182845260205260ff6040842054161560001461349557808352826020526040832082845260205260408320600160ff198254161790557f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d339380a4600190565b505090565b9060009180835282602052604083209160018060a01b03169182845260205260ff6040842054166000146134955780835282602052604083208284526020526040832060ff1981541690557ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b339380a4600190565b60405163a9059cbb60e01b60208201526001600160a01b039290921660248301526044808301939093529181526135509161354b606483611705565b613552565b565b60008061357b9260018060a01b03169360208151910182865af1613574612e24565b90836135c4565b80519081151591826135a9575b50506135915750565b60249060405190635274afe760e01b82526004820152fd5b6135bc9250602080918301019101611b82565b153880613588565b906135eb57508051156135d957805190602001fd5b604051630a12f52160e11b8152600490fd5b8151158061361e575b6135fc575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b156135f4565b600260015414613638576002600155565b604051633ee5aeb560e01b8152600490fdfea264697066735822122046a67042375eaf85066a73901de0c3e794f11bf746a06101cf6e17fbf9b9758a64736f6c63430008140033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000068b3465833fb72a70ecdf485e0e4c7bd8665fc45000000000000000000000000bebc44782c7db0a1a60cb6fe97d0b483032ff1c7000000000000000000000000a356867fdcea8e71aeaf87805808803806231fdc000000000000000000000000ba12222222228d8ba445958a75a0704d566bf2c80000000000000000000000001111111254eeb25477b68fb85ed929f73a960582000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000006b175474e89094c44da98b954eedeac495271d0f
-----Decoded View---------------
Arg [0] : _uniswapV3Router (address): 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45
Arg [1] : _curve3Pool (address): 0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7
Arg [2] : _dodoexRouter (address): 0xa356867fDCEa8e71AEaF87805808803806231FdC
Arg [3] : _balancerVault (address): 0xBA12222222228d8Ba445958a75a0704d566BF2C8
Arg [4] : _oneInchRouter (address): 0x1111111254EEB25477B68fb85Ed929f73A960582
Arg [5] : _weth (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
Arg [6] : _usdt (address): 0xdAC17F958D2ee523a2206206994597C13D831ec7
Arg [7] : _usdc (address): 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
Arg [8] : _dai (address): 0x6B175474E89094C44Da98b954EedeAC495271d0F
-----Encoded View---------------
9 Constructor Arguments found :
Arg [0] : 00000000000000000000000068b3465833fb72a70ecdf485e0e4c7bd8665fc45
Arg [1] : 000000000000000000000000bebc44782c7db0a1a60cb6fe97d0b483032ff1c7
Arg [2] : 000000000000000000000000a356867fdcea8e71aeaf87805808803806231fdc
Arg [3] : 000000000000000000000000ba12222222228d8ba445958a75a0704d566bf2c8
Arg [4] : 0000000000000000000000001111111254eeb25477b68fb85ed929f73a960582
Arg [5] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Arg [6] : 000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7
Arg [7] : 000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
Arg [8] : 0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 34 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.