Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
MultiSwapRouter
Compiler Version
v0.8.19+commit.7dd6d404
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { SafeTransferLib } from "solmate/utils/SafeTransferLib.sol";
import {
IAllowanceTransfer
} from "contracts/interfaces/external/IAllowanceTransfer.sol";
import { IRouterAllowlist } from "contracts/interfaces/IRouterAllowlist.sol";
import { IUniswapV2Router01 } from
"contracts/interfaces/external/uniswap/IUniswapV2Router02.sol";
import { IUniversalRouter } from "contracts/interfaces/external/uniswap/v4/IUniversalRouter.sol";
import { TickMath } from "contracts/interfaces/external/uniswap/v3/libraries/TickMath.sol";
import { IWETH9 as IWETH } from "contracts/interfaces/external/IWETH.sol";
import { IUniswapV3Factory } from "contracts/interfaces/external/uniswap/IUniswapV3Factory.sol";
import { IRouter as IAerodromeRouter } from "contracts/interfaces/external/aerodrome/IRouter.sol";
import { IAlgebraFactory } from "contracts/interfaces/external/algebra/IAlgebraFactory.sol";
import { Actions } from "contracts/interfaces/external/uniswap/v4/libraries/Actions.sol";
import { IV4Router } from "contracts/interfaces/external/uniswap/v4/IV4Router.sol";
import { PoolKey } from "contracts/interfaces/external/uniswap/v4/types/PoolKey.sol";
import { IHooks } from "contracts/interfaces/external/uniswap/v4/IHooks.sol";
import { Currency } from "contracts/interfaces/external/uniswap/v4/types/Currency.sol";
import { IUniswapV3Pool, IUniswapV3PoolImmutables } from "contracts/interfaces/external/uniswap/IUniswapV3Pool.sol";
import { ISwapRouter, ISwapRouter02 } from "contracts/interfaces/external/uniswap/ISwapRouter.sol";
import { ICamelotV2Router } from "contracts/interfaces/external/camelot/ICamelotInterfaces.sol";
import { ISolidlyRouter } from "contracts/interfaces/external/ISolidlyRouter.sol";
import { IAlgebraSwapRouter } from "contracts/interfaces/external/algebra/IAlgebraSwapRouter.sol";
import { IAlgebraIntegralSwapRouter } from "contracts/interfaces/external/algebra/IAlgebraIntegralSwapRouter.sol";
import { ISlipstreamSwapRouter } from "contracts/interfaces/external/aerodrome/ISlipstreamSwapRouter.sol";
import { IBlackholeRouter } from "contracts/interfaces/external/blackhole/IRouter.sol";
import { ISlipstreamFactory } from "contracts/interfaces/external/aerodrome/ISlipstreamFactory.sol";
/// @title MultiSwapRouter
/// @notice A router that executes multi-hop swaps across different DEXs
/// @dev Called via AggregatorConnector like Paraswap/Odos
contract MultiSwapRouter {
// ══════════════════════════════════════════════════════════════════════════════
// CONSTANTS
// ══════════════════════════════════════════════════════════════════════════════
address public constant PERMIT2 = 0x000000000022D473030F116dDEE9F6B43aC78BA3;
/// @notice Maximum fee in basis points (1%)
uint256 public constant MAX_FEE_BPS = 100;
/// @notice Basis points denominator
uint256 public constant BPS_DENOMINATOR = 10_000;
// V4 UniversalRouter command
uint8 internal constant V4_SWAP = 0x10;
// ══════════════════════════════════════════════════════════════════════════════
// IMMUTABLES
// ══════════════════════════════════════════════════════════════════════════════
/// @notice Router allowlist for security
IRouterAllowlist public immutable allowlist;
/// @notice Fee collector address
address public immutable feeCollector;
/// @notice Wrapped native token address (WETH/WAVAX/etc.)
address public immutable wrappedNative;
// ══════════════════════════════════════════════════════════════════════════════
// STORAGE
// ══════════════════════════════════════════════════════════════════════════════
/// @notice Admin address for configuration
address public admin;
/// @notice Fee in basis points (default 1 bp = 0.01%)
uint256 public feeBps = 1;
// ══════════════════════════════════════════════════════════════════════════════
// ERRORS
// ══════════════════════════════════════════════════════════════════════════════
error UnknownDexType();
error SwapFailed(bytes error);
error InsufficientOutputAmount(uint256 received, uint256 minRequired);
error InvalidStepsLength();
error InvalidSplitLength();
error InvalidEthInput();
error Expired();
error NotAdmin();
error InvalidAddress();
error FeeTooHigh();
error InvalidPool();
error InvalidTokenIn();
error InsufficientEthBalance();
error InvalidWrappedNative();
// ══════════════════════════════════════════════════════════════════════════════
// EVENTS
// ══════════════════════════════════════════════════════════════════════════════
event MultiSwap(
address indexed sender,
address indexed tokenIn,
address indexed tokenOut,
uint256 amountIn,
uint256 minAmountOut,
uint256 amountOut,
uint256 feeAmount
);
event Sweep(address indexed token, uint256 amount);
event FeeUpdated(uint256 oldFeeBps, uint256 newFeeBps);
event AdminUpdated(address oldAdmin, address newAdmin);
// ══════════════════════════════════════════════════════════════════════════════
// ENUMS
// ══════════════════════════════════════════════════════════════════════════════
enum DexType {
UniswapV2,
UniswapV3Router02,
Solidly,
Algebra,
UniswapV4,
VelodromeUniversalRouter,
UniswapV3Router, // Original SwapRouter with deadline (selector 0x414bf389)
AerodromeRouter, // Aerodrome Router with Route(from,to,stable,factory)
AlgebraPool, // Direct pool swap for Algebra pools (bypasses router)
SlipstreamRouter, // Aerodrome Slipstream CL router (selector 0xa026383e)
BlackholeV2Router, // Blackhole V2 on Avalanche with extended Route struct
UniswapV3Pool, // Direct Uniswap V3/Slipstream pool swap
WrapWETH, // Wrap native ETH into WETH
UnwrapWETH, // Unwrap WETH into native ETH
CamelotV2Router // Camelot V2 router (fee-on-transfer, referrer param)
}
// ══════════════════════════════════════════════════════════════════════════════
// STRUCTS
// ══════════════════════════════════════════════════════════════════════════════
struct SwapStep {
DexType dexType;
address router;
address tokenIn;
address tokenOut;
bytes dexData;
}
// ══════════════════════════════════════════════════════════════════════════════
// CONSTRUCTOR
// ══════════════════════════════════════════════════════════════════════════════
/// @param allowlist_ Router allowlist contract
/// @param admin_ Admin address for configuration
/// @param feeCollector_ Address to receive fees
constructor(
address allowlist_,
address admin_,
address feeCollector_,
address wrappedNative_
) {
if (allowlist_ == address(0)) revert InvalidAddress();
if (admin_ == address(0)) revert InvalidAddress();
if (feeCollector_ == address(0)) revert InvalidAddress();
if (wrappedNative_ == address(0)) revert InvalidWrappedNative();
allowlist = IRouterAllowlist(allowlist_);
admin = admin_;
feeCollector = feeCollector_;
wrappedNative = wrappedNative_;
}
// ══════════════════════════════════════════════════════════════════════════════
// EXTERNAL FUNCTIONS
// ══════════════════════════════════════════════════════════════════════════════
/// @notice Execute a multi-step swap
/// @param steps Array of swap steps to execute
/// @param amountIn Amount of input token
/// @param minAmountOut Minimum output amount
/// @param recipient Address to receive output tokens
/// @param deadline Transaction deadline
/// @return amountOut Actual output amount
function swap(
SwapStep[] calldata steps,
uint256 amountIn,
uint256 minAmountOut,
address recipient,
uint256 deadline
) external payable returns (uint256 amountOut) {
return _swap(steps, amountIn, minAmountOut, recipient, deadline);
}
function _swap(
SwapStep[] calldata steps,
uint256 amountIn,
uint256 minAmountOut,
address recipient,
uint256 deadline
) internal returns (uint256 amountOut) {
if (block.timestamp > deadline) revert Expired();
if (steps.length == 0) revert InvalidStepsLength();
_pullInput(steps[0].tokenIn, amountIn);
// Execute all steps
uint256 currentAmount = amountIn;
uint256 minOutBeforeFee = _requiredOutputBeforeFee(minAmountOut);
for (uint256 i; i < steps.length; i++) {
uint256 stepMinOut;
if (i == steps.length - 1 && steps[i].dexType == DexType.UniswapV4) {
stepMinOut = minOutBeforeFee;
}
currentAmount = _executeStep(steps[i], currentAmount, stepMinOut);
}
// Apply fee and transfer output
address tokenOut = steps[steps.length - 1].tokenOut;
uint256 fee;
(amountOut, fee) = _applyFeeAndTransfer(tokenOut, currentAmount, minAmountOut, recipient);
emit MultiSwap(msg.sender, steps[0].tokenIn, tokenOut, amountIn, minAmountOut, amountOut, fee);
}
/// @notice Execute a split swap across multiple parallel routes
/// @dev All routes must have the same input token and output token
/// @param routes Array of routes, each route is an array of swap steps
/// @param amounts Amount of input token for each route
/// @param minAmountOut Minimum total output amount
/// @param recipient Address to receive output tokens
/// @param deadline Transaction deadline
/// @return amountOut Total output amount after fees
function swapSplit(
SwapStep[][] calldata routes,
uint256[] calldata amounts,
uint256 minAmountOut,
address recipient,
uint256 deadline
) external payable returns (uint256 amountOut) {
if (block.timestamp > deadline) revert Expired();
if (routes.length == 0 || routes.length != amounts.length) revert InvalidSplitLength();
// All routes must have same input and output token
address tokenIn = routes[0][0].tokenIn;
address tokenOut = routes[0][routes[0].length - 1].tokenOut;
// Calculate total input and validate routes
uint256 totalAmountIn = _validateAndSumAmounts(routes, amounts, tokenIn, tokenOut);
_pullInput(tokenIn, totalAmountIn);
// Execute all routes and sum outputs
uint256 totalOutput = _executeRoutes(routes, amounts);
// Apply fee and transfer
uint256 fee;
(amountOut, fee) = _applyFeeAndTransfer(tokenOut, totalOutput, minAmountOut, recipient);
emit MultiSwap(msg.sender, tokenIn, tokenOut, totalAmountIn, minAmountOut, amountOut, fee);
}
function _validateAndSumAmounts(
SwapStep[][] calldata routes,
uint256[] calldata amounts,
address tokenIn,
address tokenOut
) internal pure returns (uint256 total) {
for (uint256 i; i < amounts.length; i++) {
total += amounts[i];
if (routes[i].length == 0) revert InvalidStepsLength();
if (routes[i][0].tokenIn != tokenIn) revert InvalidStepsLength();
if (routes[i][routes[i].length - 1].tokenOut != tokenOut) revert InvalidStepsLength();
}
}
function _executeRoutes(
SwapStep[][] calldata routes,
uint256[] calldata amounts
) internal returns (uint256 totalOutput) {
for (uint256 r; r < routes.length; r++) {
totalOutput += _executeSingleRoute(routes[r], amounts[r]);
}
}
function _executeSingleRoute(
SwapStep[] calldata steps,
uint256 amountIn
) internal returns (uint256 currentAmount) {
currentAmount = amountIn;
for (uint256 s; s < steps.length; s++) {
currentAmount = _executeStep(steps[s], currentAmount, 0);
}
}
function _applyFeeAndTransfer(
address tokenOut,
uint256 totalOutput,
uint256 minAmountOut,
address recipient
) internal returns (uint256 amountAfterFee, uint256 fee) {
fee = (totalOutput * feeBps) / BPS_DENOMINATOR;
amountAfterFee = totalOutput - fee;
if (amountAfterFee < minAmountOut) {
revert InsufficientOutputAmount(amountAfterFee, minAmountOut);
}
if (fee > 0) {
if (tokenOut == address(0)) {
SafeTransferLib.safeTransferETH(feeCollector, fee);
} else {
SafeTransferLib.safeTransfer(tokenOut, feeCollector, fee);
}
}
if (tokenOut == address(0)) {
SafeTransferLib.safeTransferETH(recipient, amountAfterFee);
} else {
SafeTransferLib.safeTransfer(tokenOut, recipient, amountAfterFee);
}
}
/// @notice Sweep stuck ERC20 tokens to fee collector
/// @param token Token to sweep
function sweep(address token) external {
if (msg.sender != admin) revert NotAdmin();
uint256 balance = IERC20(token).balanceOf(address(this));
if (balance > 0) {
SafeTransferLib.safeTransfer(token, feeCollector, balance);
emit Sweep(token, balance);
}
}
/// @notice Sweep stuck ETH to fee collector
function sweepETH() external {
if (msg.sender != admin) revert NotAdmin();
uint256 balance = address(this).balance;
if (balance > 0) {
SafeTransferLib.safeTransferETH(feeCollector, balance);
emit Sweep(address(0), balance);
}
}
/// @notice Set a new admin
/// @param newAdmin Address of the new admin
function setAdmin(address newAdmin) external {
if (msg.sender != admin) revert NotAdmin();
if (newAdmin == address(0)) revert InvalidAddress();
emit AdminUpdated(admin, newAdmin);
admin = newAdmin;
}
/// @notice Set the swap fee
/// @param newFeeBps New fee in basis points
function setFee(uint256 newFeeBps) external {
if (msg.sender != admin) revert NotAdmin();
if (newFeeBps > MAX_FEE_BPS) revert FeeTooHigh();
uint256 oldFeeBps = feeBps;
feeBps = newFeeBps;
emit FeeUpdated(oldFeeBps, newFeeBps);
}
// ══════════════════════════════════════════════════════════════════════════════
// INTERNAL FUNCTIONS
// ══════════════════════════════════════════════════════════════════════════════
function _pullInput(address tokenIn, uint256 amountIn) internal {
if (msg.value > 0) {
if (amountIn != msg.value) revert InvalidEthInput();
if (tokenIn != address(0)) revert InvalidEthInput();
} else {
if (tokenIn == address(0)) revert InvalidEthInput();
SafeTransferLib.safeTransferFrom(tokenIn, msg.sender, address(this), amountIn);
}
}
function _executeStep(
SwapStep calldata step,
uint256 amountIn,
uint256 minAmountOut
) internal returns (uint256) {
// Router allowlist check (all except direct pool swaps and wrap/unwrap)
if (step.dexType != DexType.UniswapV3Pool
&& step.dexType != DexType.AlgebraPool
&& step.dexType != DexType.WrapWETH
&& step.dexType != DexType.UnwrapWETH
) {
allowlist.requireAllowed(step.router);
}
// Router-based swaps require ERC20 tokenIn (not native ETH)
if (step.dexType != DexType.WrapWETH
&& step.dexType != DexType.UnwrapWETH
&& step.dexType != DexType.UniswapV4
&& step.dexType != DexType.AlgebraPool
&& step.dexType != DexType.UniswapV3Pool
) {
if (step.tokenIn == address(0)) revert InvalidAddress();
}
// Router-based swaps
if (step.dexType == DexType.UniswapV2) {
return _swapUniswapV2(step, amountIn);
} else if (step.dexType == DexType.UniswapV3Router02) {
return _swapUniswapV3Router02(step, amountIn);
} else if (step.dexType == DexType.UniswapV3Router) {
return _swapUniswapV3Router(step, amountIn);
} else if (step.dexType == DexType.Solidly) {
return _swapSolidly(step, amountIn);
} else if (step.dexType == DexType.AerodromeRouter) {
return _swapAerodromeRouter(step, amountIn);
} else if (step.dexType == DexType.Algebra) {
return _swapAlgebra(step, amountIn);
} else if (step.dexType == DexType.SlipstreamRouter) {
return _swapSlipstreamRouter(step, amountIn);
} else if (step.dexType == DexType.BlackholeV2Router) {
return _swapBlackholeV2(step, amountIn);
} else if (step.dexType == DexType.CamelotV2Router) {
return _swapCamelotV2Router(step, amountIn);
} else if (step.dexType == DexType.VelodromeUniversalRouter) {
return _swapVelodromeUniversalRouter(step, amountIn);
// Direct pool swaps
} else if (step.dexType == DexType.AlgebraPool) {
return _swapAlgebraPool(step, amountIn);
} else if (step.dexType == DexType.UniswapV3Pool) {
return _swapUniswapV3Pool(step, amountIn);
// V4
} else if (step.dexType == DexType.UniswapV4) {
return _swapUniswapV4(step, amountIn, minAmountOut);
// Wrap/Unwrap
} else if (step.dexType == DexType.WrapWETH) {
return _wrapWETH(step, amountIn);
} else if (step.dexType == DexType.UnwrapWETH) {
return _unwrapWETH(step, amountIn);
}
revert UnknownDexType();
}
function _swapViaRouter(
SwapStep calldata step,
uint256 amountIn,
bytes memory data
) internal returns (uint256) {
uint256 balanceBefore = _balanceOf(step.tokenOut);
_callRouterWithApproval(step.tokenIn, step.router, amountIn, data, 0);
return _balanceDelta(step.tokenOut, balanceBefore);
}
function _swapUniswapV2(
SwapStep calldata step,
uint256 amountIn
) internal returns (uint256) {
address[] memory path = new address[](2);
path[0] = step.tokenIn;
path[1] = step.tokenOut;
return _swapViaRouter(step, amountIn, _encodeSwapExactTokensForTokens(amountIn, path));
}
/// @dev SwapRouter02 / PancakeV3 interface (no deadline in struct)
function _swapUniswapV3Router02(
SwapStep calldata step,
uint256 amountIn
) internal returns (uint256) {
uint24 fee = abi.decode(step.dexData, (uint24));
return _swapViaRouter(step, amountIn, _encodeExactInputSingleRouter02(step.tokenIn, step.tokenOut, fee, amountIn));
}
/// @dev Original SwapRouter interface (with deadline in struct)
/// @notice Used on chains like Monad that don't have SwapRouter02
function _swapUniswapV3Router(
SwapStep calldata step,
uint256 amountIn
) internal returns (uint256) {
uint24 fee = abi.decode(step.dexData, (uint24));
return _swapViaRouter(step, amountIn, _encodeExactInputSingleRouter(step.tokenIn, step.tokenOut, fee, amountIn));
}
/// @dev Velodrome/Aerodrome UniversalRouter - handles both V2 and CL pools
/// @param step.dexData encodes (bool isCL, int24 poolParam)
/// - CL: (true, tickSpacing)
/// - V2: (false, stable ? 1 : 0)
function _swapVelodromeUniversalRouter(
SwapStep calldata step,
uint256 amountIn
) internal returns (uint256) {
(bool isCL, int24 poolParam) = abi.decode(step.dexData, (bool, int24));
uint256 balanceBefore = _balanceOf(step.tokenOut);
// Build path and command based on pool type
bytes memory path;
uint8 command;
if (isCL) {
// CL/Slipstream: V3_SWAP_EXACT_IN (0x00)
command = 0x00;
path = abi.encodePacked(
step.tokenIn,
poolParam, // int24 tickSpacing (3 bytes)
step.tokenOut
);
} else {
// V2: V2_SWAP_EXACT_IN (0x08)
// Path: tokenIn(20) + stable(1) + tokenOut(20)
command = 0x08;
path = abi.encodePacked(
step.tokenIn,
poolParam == 1 ? bytes1(0x01) : bytes1(0x00), // stable flag
step.tokenOut
);
}
bytes memory commands;
bytes[] memory inputs;
commands = abi.encodePacked(command);
inputs = new bytes[](1);
inputs[0] = abi.encode(
address(this), // recipient
amountIn,
0, // amountOutMin (we check after)
path,
false, // payerIsUser = false (tokens already in router)
false // isUni = false (use Velodrome/Aerodrome factory)
);
// UniversalRouter expects tokens to be in the router when payerIsUser=false
SafeTransferLib.safeTransfer(step.tokenIn, step.router, amountIn);
_callRouter(step.router, _encodeUniversalRouterExecute(commands, inputs), 0);
return _balanceDelta(step.tokenOut, balanceBefore);
}
/// @dev Legacy Solidly router - Thena, Ramses, Pharaoh, Shadow, Equalizer
/// @param step.dexData encodes (bool stable)
function _swapSolidly(
SwapStep calldata step,
uint256 amountIn
) internal returns (uint256) {
bool stable = abi.decode(step.dexData, (bool));
ISolidlyRouter.Route[] memory routes = new ISolidlyRouter.Route[](1);
routes[0] = ISolidlyRouter.Route({
from: step.tokenIn,
to: step.tokenOut,
stable: stable
});
return _swapViaRouter(step, amountIn, _encodeSolidlySwap(routes, amountIn));
}
/// @dev Aerodrome Router on Base - uses Route(from,to,stable,factory) struct
/// @param step.dexData encodes (bool stable, address factory)
function _swapAerodromeRouter(
SwapStep calldata step,
uint256 amountIn
) internal returns (uint256) {
(bool stable, address factory) = abi.decode(step.dexData, (bool, address));
IAerodromeRouter.Route[] memory routes = new IAerodromeRouter.Route[](1);
routes[0] = IAerodromeRouter.Route({
from: step.tokenIn,
to: step.tokenOut,
stable: stable,
factory: factory
});
return _swapViaRouter(step, amountIn, _encodeAerodromeSwap(routes, amountIn));
}
/// @dev Algebra swap - supports both classic (QuickSwap V3) and Algebra Integral
/// @notice For classic Algebra (QuickSwap V3), dexData should be empty
/// @notice For Algebra Integral, dexData should encode (address deployer)
function _swapAlgebra(
SwapStep calldata step,
uint256 amountIn
) internal returns (uint256) {
bytes memory data;
if (step.dexData.length == 32) {
// Algebra Integral: 8-param version with deployer
address deployer = abi.decode(step.dexData, (address));
data = _encodeAlgebraIntegralSwap(step, deployer, amountIn);
} else {
// Classic Algebra (QuickSwap V3): struct-based interface
data = _encodeAlgebraSwap(step, amountIn);
}
return _swapViaRouter(step, amountIn, data);
}
function _swapUniswapV4(
SwapStep calldata step,
uint256 amountIn,
uint256 minAmountOut
) internal returns (uint256) {
uint256 balanceBefore = _balanceOf(step.tokenOut);
PoolKey memory poolKey = abi.decode(step.dexData, (PoolKey));
if (poolKey.hooks != IHooks(address(0))) {
allowlist.requireAllowedHook(address(poolKey.hooks));
}
if (step.tokenIn != address(0)) {
// For V4, we need Permit2 approval
_approve(step.tokenIn, PERMIT2, amountIn);
IAllowanceTransfer(PERMIT2).approve(
step.tokenIn,
step.router,
// forge-lint: disable-next-line(unsafe-typecast)
uint160(amountIn),
uint48(block.timestamp)
);
}
// Build and execute V4 swap
{
bytes memory input = _buildV4Input(step, poolKey, amountIn, minAmountOut);
bytes[] memory inputs = new bytes[](1);
inputs[0] = input;
_callRouter(
step.router,
_encodeUniversalRouterExecute(abi.encodePacked(V4_SWAP), inputs),
step.tokenIn == address(0) ? amountIn : 0
);
}
// Revoke Permit2 approval
if (step.tokenIn != address(0)) {
_approve(step.tokenIn, PERMIT2, 0);
IAllowanceTransfer(PERMIT2).approve(step.tokenIn, step.router, 0, 0);
}
return _balanceDelta(step.tokenOut, balanceBefore);
}
/// @notice Direct Algebra pool swap - bypasses the router for custom pools
/// @dev dexData encodes (address pool, address customDeployer) for custom pools,
/// or just (address pool) for standard pools. Custom deployers are validated
/// via factory.customPoolByPair.
function _swapAlgebraPool(
SwapStep calldata step,
uint256 amountIn
) internal returns (uint256) {
address pool = _decodePoolAddress(step);
address customDeployer;
if (step.dexData.length >= 64) {
(, customDeployer) = abi.decode(step.dexData, (address, address));
}
bool zeroForOne = _validateAlgebraPoolAndDirection(
pool,
step.tokenIn,
step.tokenOut,
customDeployer
);
// Encode callback data: tokenIn, amountIn, payer (this contract)
bytes memory callbackData = abi.encode(step.tokenIn, amountIn, address(this), customDeployer);
// Execute swap - the pool will call algebraSwapCallback
(int256 amount0, int256 amount1) = IUniswapV3Pool(pool).swap(
address(this), // recipient
zeroForOne, // zeroForOne
// forge-lint: disable-next-line(unsafe-typecast)
int256(amountIn), // amountSpecified (positive = exactInput)
zeroForOne ? TickMath.MIN_SQRT_RATIO + 1 : TickMath.MAX_SQRT_RATIO - 1, // sqrtPriceLimitX96
callbackData
);
// Calculate output amount (negative delta = tokens received)
// forge-lint: disable-next-line(unsafe-typecast)
uint256 amountOut = zeroForOne ? uint256(-amount1) : uint256(-amount0);
return amountOut;
}
/// @dev Slipstream SwapRouter (Aerodrome CL on Base)
/// @notice Uses exactInputSingle with tickSpacing instead of fee
/// @param step.dexData encodes (int24 tickSpacing)
function _swapSlipstreamRouter(
SwapStep calldata step,
uint256 amountIn
) internal returns (uint256) {
int24 tickSpacing = abi.decode(step.dexData, (int24));
return _swapViaRouter(step, amountIn, _encodeSlipstreamSwap(step, tickSpacing, amountIn));
}
/// @dev Route struct for Blackhole V2 Router on Avalanche
/// Uses extended route struct: (pair, from, to, stable, concentrated, receiver)
struct BlackholeRoute {
address pair;
address from;
address to;
bool stable;
bool concentrated; // false for V2 pools
address receiver; // receiver for this hop (used in multi-hop)
}
/// @dev Blackhole V2 Router on Avalanche
/// @notice Uses extended Route struct with pair address and concentrated flag
/// @param step.dexData encodes (address pair, bool stable)
function _swapBlackholeV2(
SwapStep calldata step,
uint256 amountIn
) internal returns (uint256) {
(address pair, bool stable) = abi.decode(step.dexData, (address, bool));
BlackholeRoute[] memory routes = new BlackholeRoute[](1);
routes[0] = BlackholeRoute({
pair: pair,
from: step.tokenIn,
to: step.tokenOut,
stable: stable,
concentrated: false, // V2 pools are not concentrated
receiver: address(this) // MSR receives then sends to recipient
});
return _swapViaRouter(step, amountIn, _encodeBlackholeSwap(routes, amountIn));
}
function _wrapWETH(
SwapStep calldata step,
uint256 amountIn
) internal returns (uint256) {
if (
step.router != wrappedNative || step.tokenOut != wrappedNative
|| step.tokenIn != address(0)
) {
revert InvalidWrappedNative();
}
if (address(this).balance < amountIn) {
revert InsufficientEthBalance();
}
IWETH(step.router).deposit{ value: amountIn }();
return amountIn;
}
function _unwrapWETH(
SwapStep calldata step,
uint256 amountIn
) internal returns (uint256) {
if (
step.router != wrappedNative || step.tokenIn != wrappedNative
|| step.tokenOut != address(0)
) {
revert InvalidWrappedNative();
}
IWETH(step.router).withdraw(amountIn);
return amountIn;
}
function _swapCamelotV2Router(
SwapStep calldata step,
uint256 amountIn
) internal returns (uint256) {
address[] memory path = new address[](2);
path[0] = step.tokenIn;
path[1] = step.tokenOut;
address referrer = step.dexData.length >= 32
? abi.decode(step.dexData, (address))
: address(0);
return _swapViaRouter(
step,
amountIn,
abi.encodeCall(
ICamelotV2Router.swapExactTokensForTokensSupportingFeeOnTransferTokens,
(amountIn, 0, path, address(this), referrer, block.timestamp)
)
);
}
function _swapUniswapV3Pool(
SwapStep calldata step,
uint256 amountIn
) internal returns (uint256) {
address pool = _decodePoolAddress(step);
if (pool == address(0)) revert InvalidAddress();
bool zeroForOne = _validateV3PoolAndDirection(pool, step.tokenIn);
(int256 amount0, int256 amount1) = IUniswapV3Pool(pool).swap(
address(this),
zeroForOne,
// forge-lint: disable-next-line(unsafe-typecast)
int256(amountIn),
zeroForOne ? TickMath.MIN_SQRT_RATIO + 1 : TickMath.MAX_SQRT_RATIO - 1,
abi.encode(address(this))
);
// forge-lint: disable-next-line(unsafe-typecast)
uint256 amountOut = zeroForOne ? uint256(-amount1) : uint256(-amount0);
return amountOut;
}
function _decodePoolAddress(SwapStep calldata step) internal pure returns (address pool) {
if (step.dexData.length >= 32) {
pool = abi.decode(step.dexData, (address));
} else {
pool = step.router;
}
}
function _buildV4Input(
SwapStep calldata step,
PoolKey memory poolKey,
uint256 amountIn,
uint256 minAmountOut
) internal pure returns (bytes memory) {
// Sort currencies for PoolKey (V4 requires currency0 < currency1)
(address currency0, address currency1) = step.tokenIn < step.tokenOut
? (step.tokenIn, step.tokenOut)
: (step.tokenOut, step.tokenIn);
bool zeroForOne = step.tokenIn == currency0;
// Actions: SWAP_EXACT_IN_SINGLE, SETTLE_ALL, TAKE_ALL
bytes memory actions = abi.encodePacked(
uint8(Actions.SWAP_EXACT_IN_SINGLE),
uint8(Actions.SETTLE_ALL),
uint8(Actions.TAKE_ALL)
);
bytes[] memory params = new bytes[](3);
// ExactInputSingleParams: ABI encode struct (dynamic due to hookData)
IV4Router.ExactInputSingleParams memory swapParams = IV4Router.ExactInputSingleParams({
poolKey: PoolKey({
currency0: Currency.wrap(currency0),
currency1: Currency.wrap(currency1),
fee: poolKey.fee,
hooks: poolKey.hooks,
tickSpacing: poolKey.tickSpacing
}),
zeroForOne: zeroForOne,
// forge-lint: disable-next-line(unsafe-typecast)
amountIn: uint128(amountIn),
amountOutMinimum: 0,
hookData: new bytes(0)
});
params[0] = abi.encode(swapParams);
// SETTLE_ALL params: (currency, maxAmount)
params[1] = abi.encode(step.tokenIn, amountIn);
// TAKE_ALL params: (currency, minAmount)
params[2] = abi.encode(step.tokenOut, minAmountOut);
return abi.encode(actions, params);
}
function _requiredOutputBeforeFee(uint256 minAmountOut) internal view returns (uint256) {
if (minAmountOut == 0) return 0;
uint256 denom = BPS_DENOMINATOR - feeBps;
// ceil(minAmountOut * BPS_DENOMINATOR / denom)
return (minAmountOut * BPS_DENOMINATOR + denom - 1) / denom;
}
function _balanceOf(address token) internal view returns (uint256) {
if (token == address(0)) {
return address(this).balance;
}
return IERC20(token).balanceOf(address(this));
}
function _balanceDelta(address token, uint256 balanceBefore) internal view returns (uint256) {
return _balanceOf(token) - balanceBefore;
}
function _callRouter(
address router,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
(bool success, bytes memory result) = router.call{ value: value }(data);
if (!success) revert SwapFailed(result);
return result;
}
function _callRouterWithApproval(
address token,
address router,
uint256 amount,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
_approve(token, router, amount);
bytes memory result = _callRouter(router, data, value);
_revokeApproval(token, router);
return result;
}
function _encodeSwapExactTokensForTokens(
uint256 amountIn,
address[] memory path
) internal view returns (bytes memory) {
return abi.encodeCall(
IUniswapV2Router01.swapExactTokensForTokens,
(
amountIn,
0,
path,
address(this),
block.timestamp
)
);
}
function _encodeExactInputSingleRouter02(
address tokenIn,
address tokenOut,
uint24 fee,
uint256 amountIn
) internal view returns (bytes memory) {
return abi.encodeWithSelector(
ISwapRouter02.exactInputSingle.selector,
tokenIn,
tokenOut,
fee,
address(this),
amountIn,
0,
0
);
}
function _encodeExactInputSingleRouter(
address tokenIn,
address tokenOut,
uint24 fee,
uint256 amountIn
) internal view returns (bytes memory) {
return abi.encodeWithSelector(
ISwapRouter.exactInputSingle.selector,
tokenIn,
tokenOut,
fee,
address(this),
block.timestamp,
amountIn,
0,
0
);
}
function _encodeUniversalRouterExecute(
bytes memory commands,
bytes[] memory inputs
) internal view returns (bytes memory) {
return abi.encodeCall(
IUniversalRouter.execute,
(commands, inputs, block.timestamp)
);
}
function _encodeSolidlySwap(
ISolidlyRouter.Route[] memory routes,
uint256 amountIn
) internal view returns (bytes memory) {
return abi.encodeWithSelector(
ISolidlyRouter.swapExactTokensForTokens.selector,
amountIn,
0,
routes,
address(this),
block.timestamp
);
}
function _encodeAerodromeSwap(
IAerodromeRouter.Route[] memory routes,
uint256 amountIn
) internal view returns (bytes memory) {
return abi.encodeCall(
IAerodromeRouter.swapExactTokensForTokens,
(
amountIn,
0,
routes,
address(this),
block.timestamp
)
);
}
function _encodeAlgebraIntegralSwap(
SwapStep calldata step,
address deployer,
uint256 amountIn
) internal view returns (bytes memory) {
return abi.encodeWithSelector(
IAlgebraIntegralSwapRouter.exactInputSingle.selector,
step.tokenIn,
step.tokenOut,
deployer,
address(this),
block.timestamp,
amountIn,
0,
0
);
}
function _encodeAlgebraSwap(
SwapStep calldata step,
uint256 amountIn
) internal view returns (bytes memory) {
return abi.encodeWithSelector(
IAlgebraSwapRouter.exactInputSingle.selector,
step.tokenIn,
step.tokenOut,
address(this),
block.timestamp,
amountIn,
0,
0
);
}
function _encodeSlipstreamSwap(
SwapStep calldata step,
int24 tickSpacing,
uint256 amountIn
) internal view returns (bytes memory) {
return abi.encodeWithSelector(
ISlipstreamSwapRouter.exactInputSingle.selector,
step.tokenIn,
step.tokenOut,
tickSpacing,
address(this),
block.timestamp,
amountIn,
0,
0
);
}
function _encodeBlackholeSwap(
BlackholeRoute[] memory routes,
uint256 amountIn
) internal view returns (bytes memory) {
return abi.encodeWithSelector(
IBlackholeRouter.swapExactTokensForTokens.selector,
amountIn,
0,
routes,
address(this),
block.timestamp
);
}
function _approve(address token, address spender, uint256 amount) internal {
SafeTransferLib.safeApprove(token, spender, 0);
SafeTransferLib.safeApprove(token, spender, amount);
}
function _revokeApproval(address token, address spender) internal {
SafeTransferLib.safeApprove(token, spender, 0);
}
function _validateV3PoolAndDirection(
address pool,
address tokenIn
) internal view returns (bool zeroForOne) {
IUniswapV3Pool v3pool = IUniswapV3Pool(pool);
address token0 = v3pool.token0();
address token1 = v3pool.token1();
address factory = v3pool.factory();
allowlist.requireAllowedFactory(factory);
(uint24 fee, int24 tickSpacing) = _readFeeAndTickSpacing(pool);
if (!_isPoolFromFactory(factory, token0, token1, fee, tickSpacing, pool)) {
revert InvalidPool();
}
if (tokenIn == token0) {
return true;
}
if (tokenIn == token1) {
return false;
}
revert InvalidTokenIn();
}
function _readFeeAndTickSpacing(address pool) internal view returns (uint24 fee, int24 tickSpacing) {
(bool ok, bytes memory data) = pool.staticcall(
abi.encodeWithSelector(IUniswapV3PoolImmutables.fee.selector)
);
if (ok && data.length >= 32) {
fee = abi.decode(data, (uint24));
}
(ok, data) = pool.staticcall(
abi.encodeWithSelector(IUniswapV3PoolImmutables.tickSpacing.selector)
);
if (ok && data.length >= 32) {
tickSpacing = abi.decode(data, (int24));
}
}
function _isPoolFromFactory(
address factory,
address token0,
address token1,
uint24 fee,
int24 tickSpacing,
address pool
) internal view returns (bool) {
(bool ok, address expected) = _tryGetV3Pool(factory, token0, token1, fee);
if (ok && expected == pool) return true;
(ok, expected) = _tryGetSlipstreamPool(factory, token0, token1, tickSpacing);
if (ok && expected == pool) return true;
return false;
}
function _tryGetV3Pool(
address factory,
address token0,
address token1,
uint24 fee
) internal view returns (bool, address) {
(bool success, bytes memory data) = factory.staticcall(
abi.encodeWithSelector(IUniswapV3Factory.getPool.selector, token0, token1, fee)
);
if (!success || data.length < 32) {
return (false, address(0));
}
return (true, abi.decode(data, (address)));
}
function _tryGetSlipstreamPool(
address factory,
address token0,
address token1,
int24 tickSpacing
) internal view returns (bool, address) {
(bool success, bytes memory data) = factory.staticcall(
abi.encodeWithSelector(ISlipstreamFactory.getPool.selector, token0, token1, tickSpacing)
);
if (!success || data.length < 32) {
return (false, address(0));
}
return (true, abi.decode(data, (address)));
}
function _validateAlgebraPoolAndDirection(
address pool,
address tokenIn,
address tokenOut,
address customDeployer
) internal view returns (bool zeroForOne) {
(address token0, address token1, address factory) =
_readAlgebraPoolTokensAndFactory(pool);
allowlist.requireAllowedFactory(factory);
if (!_isAlgebraPoolFromFactory(factory, token0, token1, pool, customDeployer)) {
revert InvalidPool();
}
if (tokenIn == token0 && tokenOut == token1) {
return true;
}
if (tokenIn == token1 && tokenOut == token0) {
return false;
}
revert InvalidTokenIn();
}
function _validateAlgebraPoolTokenIn(
address pool,
address tokenIn,
address customDeployer
) internal view {
(address token0, address token1, address factory) =
_readAlgebraPoolTokensAndFactory(pool);
allowlist.requireAllowedFactory(factory);
if (!_isAlgebraPoolFromFactory(factory, token0, token1, pool, customDeployer)) {
revert InvalidPool();
}
if (tokenIn != token0 && tokenIn != token1) {
revert InvalidTokenIn();
}
}
function _readAlgebraPoolTokensAndFactory(
address pool
) internal view returns (address token0, address token1, address factory) {
IUniswapV3Pool algebraPool = IUniswapV3Pool(pool);
token0 = algebraPool.token0();
token1 = algebraPool.token1();
factory = algebraPool.factory();
}
function _isAlgebraPoolFromFactory(
address factory,
address token0,
address token1,
address pool,
address customDeployer
) internal view returns (bool) {
(bool ok, address expected) = _tryGetAlgebraPoolByPair(factory, token0, token1);
if (ok) {
if (expected == pool) return true;
if (expected != address(0) && customDeployer == address(0)) return false;
}
(ok, expected) = _tryComputeAlgebraPoolAddress(factory, token0, token1);
if (ok && expected == pool) return true;
if (customDeployer != address(0)) {
allowlist.requireAllowedCustomDeployer(factory, customDeployer);
(ok, expected) = _tryGetAlgebraCustomPoolByPair(factory, customDeployer, token0, token1);
if (ok && expected == pool) return true;
}
return false;
}
function _tryGetAlgebraPoolByPair(
address factory,
address token0,
address token1
) internal view returns (bool, address) {
(bool success, bytes memory data) = factory.staticcall(
abi.encodeWithSelector(IAlgebraFactory.poolByPair.selector, token0, token1)
);
if (!success || data.length < 32) {
return (false, address(0));
}
return (true, abi.decode(data, (address)));
}
function _tryComputeAlgebraPoolAddress(
address factory,
address token0,
address token1
) internal view returns (bool, address) {
(bool success, bytes memory data) = factory.staticcall(
abi.encodeWithSelector(IAlgebraFactory.computePoolAddress.selector, token0, token1)
);
if (!success || data.length < 32) {
return (false, address(0));
}
return (true, abi.decode(data, (address)));
}
function _tryGetAlgebraCustomPoolByPair(
address factory,
address deployer,
address token0,
address token1
) internal view returns (bool, address) {
(bool success, bytes memory data) = factory.staticcall(
abi.encodeWithSelector(
IAlgebraFactory.customPoolByPair.selector,
deployer,
token0,
token1
)
);
if (!success || data.length < 32) {
return (false, address(0));
}
return (true, abi.decode(data, (address)));
}
function uniswapV3SwapCallback(
int256 amount0Delta,
int256 amount1Delta,
bytes calldata data
) external {
if (amount0Delta <= 0 && amount1Delta <= 0) return;
IUniswapV3Pool v3pool = IUniswapV3Pool(msg.sender);
address token0 = v3pool.token0();
address token1 = v3pool.token1();
address factory = v3pool.factory();
allowlist.requireAllowedFactory(factory);
(uint24 fee, int24 tickSpacing) = _readFeeAndTickSpacing(msg.sender);
if (!_isPoolFromFactory(factory, token0, token1, fee, tickSpacing, msg.sender)) {
revert InvalidPool();
}
address payer = abi.decode(data, (address));
// forge-lint: disable-next-line(unsafe-typecast)
uint256 amountToPay = amount0Delta > 0 ? uint256(amount0Delta) : uint256(amount1Delta);
address tokenToPay = amount0Delta > 0 ? token0 : token1;
if (payer == address(this)) {
SafeTransferLib.safeTransfer(tokenToPay, msg.sender, amountToPay);
}
}
/// @notice Callback for Algebra pool swaps
/// @dev Called by the pool during swap to request token payment
function algebraSwapCallback(
int256 amount0Delta,
int256 amount1Delta,
bytes calldata data
) external {
// Decode callback data
(address tokenIn, , address payer, address customDeployer) =
abi.decode(data, (address, uint256, address, address));
_validateAlgebraPoolTokenIn(msg.sender, tokenIn, customDeployer);
// Determine which token to pay (positive delta = tokens owed to pool)
// forge-lint: disable-next-line(unsafe-typecast)
uint256 amountToPay = amount0Delta > 0 ? uint256(amount0Delta) : uint256(amount1Delta);
// Transfer tokens to the pool
if (payer == address(this)) {
SafeTransferLib.safeTransfer(tokenIn, msg.sender, amountToPay);
}
}
receive() external payable {}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @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 amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
import {ERC20} from "../tokens/ERC20.sol";
/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer.
/// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller.
library SafeTransferLib {
/*//////////////////////////////////////////////////////////////
ERRORS
//////////////////////////////////////////////////////////////*/
error ETHTransferFailed();
error TransferFromFailed();
error TransferFailed();
error ApproveFailed();
/*//////////////////////////////////////////////////////////////
ETH OPERATIONS
//////////////////////////////////////////////////////////////*/
function safeTransferETH(address to, uint256 amount) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Transfer the ETH and store if it succeeded or not.
success := call(gas(), to, amount, 0, 0, 0, 0)
}
if (!success) revert ETHTransferFailed();
}
/*//////////////////////////////////////////////////////////////
ERC20 OPERATIONS
//////////////////////////////////////////////////////////////*/
function safeTransferFrom(
address token,
address from,
address to,
uint256 amount
) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Get a pointer to some free memory.
let freeMemoryPointer := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.
mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), from) // Append the "from" argument.
mstore(add(freeMemoryPointer, 36), to) // Append the "to" argument.
mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument.
success := and(
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data.
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
// We use 100 because the length of our calldata totals up like so: 4 + 32 * 3.
// We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
// Counterintuitively, this call must be positioned second to the or() call in the
// surrounding and() call or else returndatasize() will be zero during the computation.
call(gas(), token, 0, freeMemoryPointer, 100, 0, 32)
)
}
if (!success) revert TransferFromFailed();
}
function safeTransfer(
address token,
address to,
uint256 amount
) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Get a pointer to some free memory.
let freeMemoryPointer := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.
mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument.
mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument.
success := and(
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data.
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
// We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
// We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
// Counterintuitively, this call must be positioned second to the or() call in the
// surrounding and() call or else returndatasize() will be zero during the computation.
call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
)
}
if (!success) revert TransferFailed();
}
function safeApprove(
address token,
address to,
uint256 amount
) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Get a pointer to some free memory.
let freeMemoryPointer := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.
mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument.
mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument.
success := and(
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data.
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
// We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
// We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
// Counterintuitively, this call must be positioned second to the or() call in the
// surrounding and() call or else returndatasize() will be zero during the computation.
call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
)
}
if (!success) revert ApproveFailed();
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// import {IEIP712} from "./IEIP712.sol";
/// @title AllowanceTransfer
/// @notice Handles ERC20 token permissions through signature based allowance
/// setting and ERC20 token transfers by checking allowed amounts
/// @dev Requires user's token approval on the Permit2 contract
interface IAllowanceTransfer {
//is IEIP712
/// @notice Thrown when an allowance on a token has expired.
/// @param deadline The timestamp at which the allowed amount is no longer
/// valid
error AllowanceExpired(uint256 deadline);
/// @notice Thrown when an allowance on a token has been depleted.
/// @param amount The maximum amount allowed
error InsufficientAllowance(uint256 amount);
/// @notice Thrown when too many nonces are invalidated.
error ExcessiveInvalidation();
/// @notice Emits an event when the owner successfully invalidates an
/// ordered nonce.
event NonceInvalidation(
address indexed owner,
address indexed token,
address indexed spender,
uint48 newNonce,
uint48 oldNonce
);
/// @notice Emits an event when the owner successfully sets permissions on a
/// token for the spender.
event Approval(
address indexed owner,
address indexed token,
address indexed spender,
uint160 amount,
uint48 expiration
);
/// @notice Emits an event when the owner successfully sets permissions
/// using a permit signature on a token for the spender.
event Permit(
address indexed owner,
address indexed token,
address indexed spender,
uint160 amount,
uint48 expiration,
uint48 nonce
);
/// @notice Emits an event when the owner sets the allowance back to 0 with
/// the lockdown function.
event Lockdown(address indexed owner, address token, address spender);
/// @notice The permit data for a token
struct PermitDetails {
// ERC20 token address
address token;
// the maximum amount allowed to spend
uint160 amount;
// timestamp at which a spender's token allowances become invalid
uint48 expiration;
// an incrementing value indexed per owner,token,and spender for each
// signature
uint48 nonce;
}
/// @notice The permit message signed for a single token allowance
struct PermitSingle {
// the permit data for a single token alownce
PermitDetails details;
// address permissioned on the allowed tokens
address spender;
// deadline on the permit signature
uint256 sigDeadline;
}
/// @notice The permit message signed for multiple token allowances
struct PermitBatch {
// the permit data for multiple token allowances
PermitDetails[] details;
// address permissioned on the allowed tokens
address spender;
// deadline on the permit signature
uint256 sigDeadline;
}
/// @notice The saved permissions
/// @dev This info is saved per owner, per token, per spender and all signed
/// over in the permit message
/// @dev Setting amount to type(uint160).max sets an unlimited approval
struct PackedAllowance {
// amount allowed
uint160 amount;
// permission expiry
uint48 expiration;
// an incrementing value indexed per owner,token,and spender for each
// signature
uint48 nonce;
}
/// @notice A token spender pair.
struct TokenSpenderPair {
// the token the spender is approved
address token;
// the spender address
address spender;
}
/// @notice Details for a token transfer.
struct AllowanceTransferDetails {
// the owner of the token
address from;
// the recipient of the token
address to;
// the amount of the token
uint160 amount;
// the token to be transferred
address token;
}
/// @notice A mapping from owner address to token address to spender address
/// to PackedAllowance struct, which contains details and conditions of the
/// approval.
/// @notice The mapping is indexed in the above order see:
/// allowance[ownerAddress][tokenAddress][spenderAddress]
/// @dev The packed slot holds the allowed amount, expiration at which the
/// allowed amount is no longer valid, and current nonce thats updated on
/// any signature based approvals.
function allowance(
address user,
address token,
address spender
) external view returns (uint160 amount, uint48 expiration, uint48 nonce);
/// @notice Approves the spender to use up to amount of the specified token
/// up until the expiration
/// @param token The token to approve
/// @param spender The spender address to approve
/// @param amount The approved amount of the token
/// @param expiration The timestamp at which the approval is no longer valid
/// @dev The packed allowance also holds a nonce, which will stay unchanged
/// in approve
/// @dev Setting amount to type(uint160).max sets an unlimited approval
function approve(
address token,
address spender,
uint160 amount,
uint48 expiration
) external;
/// @notice Permit a spender to a given amount of the owners token via the
/// owner's EIP-712 signature
/// @dev May fail if the owner's nonce was invalidated in-flight by
/// invalidateNonce
/// @param owner The owner of the tokens being approved
/// @param permitSingle Data signed over by the owner specifying the terms
/// of approval
/// @param signature The owner's signature over the permit data
function permit(
address owner,
PermitSingle memory permitSingle,
bytes calldata signature
) external;
/// @notice Permit a spender to the signed amounts of the owners tokens via
/// the owner's EIP-712 signature
/// @dev May fail if the owner's nonce was invalidated in-flight by
/// invalidateNonce
/// @param owner The owner of the tokens being approved
/// @param permitBatch Data signed over by the owner specifying the terms of
/// approval
/// @param signature The owner's signature over the permit data
function permit(
address owner,
PermitBatch memory permitBatch,
bytes calldata signature
) external;
/// @notice Transfer approved tokens from one address to another
/// @param from The address to transfer from
/// @param to The address of the recipient
/// @param amount The amount of the token to transfer
/// @param token The token address to transfer
/// @dev Requires the from address to have approved at least the desired
/// amount
/// of tokens to msg.sender.
function transferFrom(
address from,
address to,
uint160 amount,
address token
) external;
/// @notice Transfer approved tokens in a batch
/// @param transferDetails Array of owners, recipients, amounts, and tokens
/// for the transfers
/// @dev Requires the from addresses to have approved at least the desired
/// amount
/// of tokens to msg.sender.
function transferFrom(
AllowanceTransferDetails[] calldata transferDetails
) external;
/// @notice Enables performing a "lockdown" of the sender's Permit2 identity
/// by batch revoking approvals
/// @param approvals Array of approvals to revoke.
function lockdown(
TokenSpenderPair[] calldata approvals
) external;
/// @notice Invalidate nonces for a given (token, spender) pair
/// @param token The token to invalidate nonces for
/// @param spender The spender to invalidate nonces for
/// @param newNonce The new nonce to set. Invalidates all nonces less than
/// it.
/// @dev Can't invalidate more than 2**16 nonces per transaction.
function invalidateNonces(
address token,
address spender,
uint48 newNonce
) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
interface IRouterAllowlist {
/// @notice Check if a router is allowed
/// @param router The router address to check
/// @return True if the router is allowed
function isAllowed(address router) external view returns (bool);
/// @notice Revert if the router is not allowed
/// @param router The router address to check
function requireAllowed(address router) external view;
/// @notice Check if a factory is allowed
/// @param factory The factory address to check
/// @return True if the factory is allowed
function isAllowedFactory(address factory) external view returns (bool);
/// @notice Revert if the factory is not allowed
/// @param factory The factory address to check
function requireAllowedFactory(address factory) external view;
/// @notice Check if a custom pool deployer is allowed for a factory
/// @param factory The factory address to check
/// @param deployer The custom pool deployer address to check
/// @return True if the custom deployer is allowed for the factory
function isAllowedCustomDeployer(address factory, address deployer) external view returns (bool);
/// @notice Revert if the custom pool deployer is not allowed for a factory
/// @param factory The factory address to check
/// @param deployer The custom pool deployer address to check
function requireAllowedCustomDeployer(address factory, address deployer) external view;
/// @notice Check if a v4 hook is allowed
/// @param hook The hook address to check
/// @return True if the hook is allowed
function isAllowedHook(address hook) external view returns (bool);
/// @notice Revert if the v4 hook is not allowed
/// @param hook The hook address to check
function requireAllowedHook(address hook) external view;
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.8.9;
interface IUniswapV2Router01 {
function factory() external pure returns (address);
function WETH() external pure returns (address);
function addLiquidity(
address tokenA,
address tokenB,
uint256 amountADesired,
uint256 amountBDesired,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline
) external returns (uint256 amountA, uint256 amountB, uint256 liquidity);
function addLiquidityETH(
address token,
uint256 amountTokenDesired,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
)
external
payable
returns (uint256 amountToken, uint256 amountETH, uint256 liquidity);
function removeLiquidity(
address tokenA,
address tokenB,
uint256 liquidity,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline
) external returns (uint256 amountA, uint256 amountB);
function removeLiquidityETH(
address token,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
) external returns (uint256 amountToken, uint256 amountETH);
function removeLiquidityWithPermit(
address tokenA,
address tokenB,
uint256 liquidity,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline,
bool approveMax,
uint8 v,
bytes32 r,
bytes32 s
) external returns (uint256 amountA, uint256 amountB);
function removeLiquidityETHWithPermit(
address token,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline,
bool approveMax,
uint8 v,
bytes32 r,
bytes32 s
) external returns (uint256 amountToken, uint256 amountETH);
function swapExactTokensForTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
function swapTokensForExactTokens(
uint256 amountOut,
uint256 amountInMax,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
function swapExactETHForTokens(
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external payable returns (uint256[] memory amounts);
function swapTokensForExactETH(
uint256 amountOut,
uint256 amountInMax,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
function swapExactTokensForETH(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
function swapETHForExactTokens(
uint256 amountOut,
address[] calldata path,
address to,
uint256 deadline
) external payable returns (uint256[] memory amounts);
function quote(
uint256 amountA,
uint256 reserveA,
uint256 reserveB
) external pure returns (uint256 amountB);
function getAmountOut(
uint256 amountIn,
uint256 reserveIn,
uint256 reserveOut
) external pure returns (uint256 amountOut);
function getAmountIn(
uint256 amountOut,
uint256 reserveIn,
uint256 reserveOut
) external pure returns (uint256 amountIn);
function getAmountsOut(
uint256 amountIn,
address[] calldata path
) external view returns (uint256[] memory amounts);
function getAmountsIn(
uint256 amountOut,
address[] calldata path
) external view returns (uint256[] memory amounts);
}
interface IUniswapV2Router02 is IUniswapV2Router01 {
function removeLiquidityETHSupportingFeeOnTransferTokens(
address token,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
) external returns (uint256 amountETH);
function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
address token,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline,
bool approveMax,
uint8 v,
bytes32 r,
bytes32 s
) external returns (uint256 amountETH);
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external;
function swapExactETHForTokensSupportingFeeOnTransferTokens(
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external payable;
function swapExactTokensForETHSupportingFeeOnTransferTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external;
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.19;
interface IUniversalRouter {
/// @notice Thrown when a required command has failed
error ExecutionFailed(uint256 commandIndex, bytes message);
/// @notice Thrown when attempting to send ETH directly to the contract
error ETHNotAccepted();
/// @notice Thrown when executing commands with an expired deadline
error TransactionDeadlinePassed();
/// @notice Thrown when attempting to execute commands and an incorrect
/// number of inputs are provided
error LengthMismatch();
// @notice Thrown when an address that isn't WETH tries to send ETH to the
// router without calldata
error InvalidEthSender();
/// @notice Executes encoded commands along with provided inputs. Reverts if
/// deadline has expired.
/// @param commands A set of concatenated commands, each 1 byte in length
/// @param inputs An array of byte strings containing abi encoded inputs for
/// each command
/// @param deadline The deadline by which the transaction must be executed
function execute(
bytes calldata commands,
bytes[] calldata inputs,
uint256 deadline
) external payable;
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;
/// @title Math library for computing sqrt prices from ticks and vice versa
/// @notice Computes sqrt price for ticks of size 1.0001, i.e. sqrt(1.0001^tick)
/// as fixed point Q64.96 numbers. Supports
/// prices between 2**-128 and 2**128
library TickMath {
/// @dev The minimum tick that may be passed to #getSqrtRatioAtTick computed
/// from log base 1.0001 of 2**-128
int24 internal constant MIN_TICK = -887_272;
/// @dev The maximum tick that may be passed to #getSqrtRatioAtTick computed
/// from log base 1.0001 of 2**128
int24 internal constant MAX_TICK = -MIN_TICK;
/// @dev The minimum value that can be returned from #getSqrtRatioAtTick.
/// Equivalent to getSqrtRatioAtTick(MIN_TICK)
uint160 internal constant MIN_SQRT_RATIO = 4_295_128_739;
/// @dev The maximum value that can be returned from #getSqrtRatioAtTick.
/// Equivalent to getSqrtRatioAtTick(MAX_TICK)
uint160 internal constant MAX_SQRT_RATIO =
1_461_446_703_485_210_103_287_273_052_203_988_822_378_723_970_342;
/// @notice Calculates sqrt(1.0001^tick) * 2^96
/// @dev Throws if |tick| > max tick
/// @param tick The input tick for the above formula
/// @return sqrtPriceX96 A Fixed point Q64.96 number representing the sqrt
/// of the ratio of the two assets (token1/token0)
/// at the given tick
function getSqrtRatioAtTick(
int24 tick
) internal pure returns (uint160 sqrtPriceX96) {
uint256 absTick =
tick < 0 ? uint256(uint24(-tick)) : uint256(uint24(tick));
require(absTick <= uint256(int256(MAX_TICK)), "T");
uint256 ratio = absTick & 0x1 != 0
? 0xfffcb933bd6fad37aa2d162d1a594001
: 0x100000000000000000000000000000000;
if (absTick & 0x2 != 0) {
ratio = (ratio * 0xfff97272373d413259a46990580e213a) >> 128;
}
if (absTick & 0x4 != 0) {
ratio = (ratio * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128;
}
if (absTick & 0x8 != 0) {
ratio = (ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128;
}
if (absTick & 0x10 != 0) {
ratio = (ratio * 0xffcb9843d60f6159c9db58835c926644) >> 128;
}
if (absTick & 0x20 != 0) {
ratio = (ratio * 0xff973b41fa98c081472e6896dfb254c0) >> 128;
}
if (absTick & 0x40 != 0) {
ratio = (ratio * 0xff2ea16466c96a3843ec78b326b52861) >> 128;
}
if (absTick & 0x80 != 0) {
ratio = (ratio * 0xfe5dee046a99a2a811c461f1969c3053) >> 128;
}
if (absTick & 0x100 != 0) {
ratio = (ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128;
}
if (absTick & 0x200 != 0) {
ratio = (ratio * 0xf987a7253ac413176f2b074cf7815e54) >> 128;
}
if (absTick & 0x400 != 0) {
ratio = (ratio * 0xf3392b0822b70005940c7a398e4b70f3) >> 128;
}
if (absTick & 0x800 != 0) {
ratio = (ratio * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128;
}
if (absTick & 0x1000 != 0) {
ratio = (ratio * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128;
}
if (absTick & 0x2000 != 0) {
ratio = (ratio * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128;
}
if (absTick & 0x4000 != 0) {
ratio = (ratio * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128;
}
if (absTick & 0x8000 != 0) {
ratio = (ratio * 0x31be135f97d08fd981231505542fcfa6) >> 128;
}
if (absTick & 0x10000 != 0) {
ratio = (ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128;
}
if (absTick & 0x20000 != 0) {
ratio = (ratio * 0x5d6af8dedb81196699c329225ee604) >> 128;
}
if (absTick & 0x40000 != 0) {
ratio = (ratio * 0x2216e584f5fa1ea926041bedfe98) >> 128;
}
if (absTick & 0x80000 != 0) {
ratio = (ratio * 0x48a170391f7dc42444e8fa2) >> 128;
}
if (tick > 0) ratio = type(uint256).max / ratio;
// this divides by 1<<32 rounding up to go from a Q128.128 to a Q128.96.
// we then downcast because we know the result always fits within 160
// bits due to our tick input constraint
// we round up in the division so getTickAtSqrtRatio of the output price
// is always consistent
sqrtPriceX96 = uint160((ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1));
}
/// @notice Calculates the greatest tick value such that
/// getRatioAtTick(tick) <= ratio
/// @dev Throws in case sqrtPriceX96 < MIN_SQRT_RATIO, as MIN_SQRT_RATIO is
/// the lowest value getRatioAtTick may
/// ever return.
/// @param sqrtPriceX96 The sqrt ratio for which to compute the tick as a
/// Q64.96
/// @return tick The greatest tick for which the ratio is less than or equal
/// to the input ratio
function getTickAtSqrtRatio(
uint160 sqrtPriceX96
) internal pure returns (int24 tick) {
// second inequality must be < because the price can never reach the
// price at the max tick
require(
sqrtPriceX96 >= MIN_SQRT_RATIO && sqrtPriceX96 < MAX_SQRT_RATIO, "R"
);
uint256 ratio = uint256(sqrtPriceX96) << 32;
uint256 r = ratio;
uint256 msb = 0;
assembly {
let f := shl(7, gt(r, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := shl(6, gt(r, 0xFFFFFFFFFFFFFFFF))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := shl(5, gt(r, 0xFFFFFFFF))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := shl(4, gt(r, 0xFFFF))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := shl(3, gt(r, 0xFF))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := shl(2, gt(r, 0xF))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := shl(1, gt(r, 0x3))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := gt(r, 0x1)
msb := or(msb, f)
}
if (msb >= 128) r = ratio >> (msb - 127);
else r = ratio << (127 - msb);
int256 log_2 = (int256(msb) - 128) << 64;
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(63, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(62, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(61, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(60, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(59, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(58, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(57, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(56, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(55, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(54, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(53, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(52, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(51, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(50, f))
}
int256 log_sqrt10001 = log_2 * 255_738_958_999_603_826_347_141; // 128.128
// number
int24 tickLow = int24(
(log_sqrt10001 - 3_402_992_956_809_132_418_596_140_100_660_247_210)
>> 128
);
int24 tickHi = int24(
(
log_sqrt10001
+ 291_339_464_771_989_622_907_027_621_153_398_088_495
) >> 128
);
tick = tickLow == tickHi
? tickLow
: getSqrtRatioAtTick(tickHi) <= sqrtPriceX96 ? tickHi : tickLow;
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.9;
interface IWETH9 {
function deposit() external payable;
function withdraw(
uint256 wad
) external;
function approve(address guy, uint256 wad) external returns (bool);
function balanceOf(
address account
) external view returns (uint256);
function allowance(
address account,
address spender
) external view returns (uint256);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
/// @title The interface for the Uniswap V3 Factory
/// @notice The Uniswap V3 Factory facilitates creation of Uniswap V3 pools and
/// control over the protocol fees
interface IUniswapV3Factory {
/// @notice Emitted when the owner of the factory is changed
/// @param oldOwner The owner before the owner was changed
/// @param newOwner The owner after the owner was changed
event OwnerChanged(address indexed oldOwner, address indexed newOwner);
/// @notice Emitted when a pool is created
/// @param token0 The first token of the pool by address sort order
/// @param token1 The second token of the pool by address sort order
/// @param fee The fee collected upon every swap in the pool, denominated in
/// hundredths of a bip
/// @param tickSpacing The minimum number of ticks between initialized ticks
/// @param pool The address of the created pool
event PoolCreated(
address indexed token0,
address indexed token1,
uint24 indexed fee,
int24 tickSpacing,
address pool
);
/// @notice Emitted when a new fee amount is enabled for pool creation via
/// the factory
/// @param fee The enabled fee, denominated in hundredths of a bip
/// @param tickSpacing The minimum number of ticks between initialized ticks
/// for pools created with the given fee
event FeeAmountEnabled(uint24 indexed fee, int24 indexed tickSpacing);
/// @notice Returns the current owner of the factory
/// @dev Can be changed by the current owner via setOwner
/// @return The address of the factory owner
function owner() external view returns (address);
/// @notice Returns the tick spacing for a given fee amount, if enabled, or
/// 0 if not enabled
/// @dev A fee amount can never be removed, so this value should be hard
/// coded or cached in the calling context
/// @param fee The enabled fee, denominated in hundredths of a bip. Returns
/// 0 in case of unenabled fee
/// @return The tick spacing
function feeAmountTickSpacing(
uint24 fee
) external view returns (int24);
/// @notice Returns the pool address for a given pair of tokens and a fee,
/// or address 0 if it does not exist
/// @dev tokenA and tokenB may be passed in either token0/token1 or
/// token1/token0 order
/// @param tokenA The contract address of either token0 or token1
/// @param tokenB The contract address of the other token
/// @param fee The fee collected upon every swap in the pool, denominated in
/// hundredths of a bip
/// @return pool The pool address
function getPool(
address tokenA,
address tokenB,
uint24 fee
) external view returns (address pool);
/// @notice Creates a pool for the given two tokens and fee
/// @param tokenA One of the two tokens in the desired pool
/// @param tokenB The other of the two tokens in the desired pool
/// @param fee The desired fee for the pool
/// @dev tokenA and tokenB may be passed in either order: token0/token1 or
/// token1/token0. tickSpacing is retrieved
/// from the fee. The call will revert if the pool already exists, the fee
/// is invalid, or the token arguments
/// are invalid.
/// @return pool The address of the newly created pool
function createPool(
address tokenA,
address tokenB,
uint24 fee
) external returns (address pool);
/// @notice Updates the owner of the factory
/// @dev Must be called by the current owner
/// @param _owner The new owner of the factory
function setOwner(
address _owner
) external;
/// @notice Enables a fee amount with the given tickSpacing
/// @dev Fee amounts may never be removed once enabled
/// @param fee The fee amount to enable, denominated in hundredths of a bip
/// (i.e. 1e-6)
/// @param tickSpacing The spacing between ticks to be enforced for all
/// pools created with the given fee amount
function enableFeeAmount(uint24 fee, int24 tickSpacing) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { IERC20 } from "@openzeppelin/contracts/interfaces/IERC20.sol";
interface IWETH is IERC20 {
function deposit() external payable;
function withdraw(
uint256
) external;
}
interface IRouter {
struct Route {
address from;
address to;
bool stable;
address factory;
}
error ETHTransferFailed();
error Expired();
error InsufficientAmount();
error InsufficientAmountA();
error InsufficientAmountB();
error InsufficientAmountADesired();
error InsufficientAmountBDesired();
error InsufficientAmountAOptimal();
error InsufficientLiquidity();
error InsufficientOutputAmount();
error InvalidAmountInForETHDeposit();
error InvalidTokenInForETHDeposit();
error InvalidPath();
error InvalidRouteA();
error InvalidRouteB();
error OnlyWETH();
error PoolDoesNotExist();
error PoolFactoryDoesNotExist();
error SameAddresses();
error ZeroAddress();
/// @notice Address of FactoryRegistry.sol
function factoryRegistry() external view returns (address);
/// @notice Address of Protocol PoolFactory.sol
function defaultFactory() external view returns (address);
/// @notice Address of Voter.sol
function voter() external view returns (address);
/// @notice Interface of WETH contract used for WETH => ETH
/// wrapping/unwrapping
function weth() external view returns (IWETH);
/// @dev Represents Ether. Used by zapper to determine whether to return
/// assets as ETH/WETH.
function ETHER() external view returns (address);
/// @dev Struct containing information necessary to zap in and out of pools
/// @param tokenA .
/// @param tokenB .
/// @param stable Stable or volatile pool
/// @param factory factory of pool
/// @param amountOutMinA Minimum amount expected from swap leg of zap via
/// routesA
/// @param amountOutMinB Minimum amount expected from swap leg of zap via
/// routesB
/// @param amountAMin Minimum amount of tokenA expected from liquidity
/// leg of zap
/// @param amountBMin Minimum amount of tokenB expected from liquidity
/// leg of zap
struct Zap {
address tokenA;
address tokenB;
bool stable;
address factory;
uint256 amountOutMinA;
uint256 amountOutMinB;
uint256 amountAMin;
uint256 amountBMin;
}
/// @notice Sort two tokens by which address value is less than the other
/// @param tokenA Address of token to sort
/// @param tokenB Address of token to sort
/// @return token0 Lower address value between tokenA and tokenB
/// @return token1 Higher address value between tokenA and tokenB
function sortTokens(
address tokenA,
address tokenB
) external pure returns (address token0, address token1);
/// @notice Calculate the address of a pool by its' factory.
/// Used by all Router functions containing a `Route[]` or
/// `_factory` argument.
/// Reverts if _factory is not approved by the FactoryRegistry
/// @dev Returns a randomly generated address for a nonexistent pool
/// @param tokenA Address of token to query
/// @param tokenB Address of token to query
/// @param stable True if pool is stable, false if volatile
/// @param _factory Address of factory which created the pool
function poolFor(
address tokenA,
address tokenB,
bool stable,
address _factory
) external view returns (address pool);
/// @notice Fetch and sort the reserves for a pool
/// @param tokenA .
/// @param tokenB .
/// @param stable True if pool is stable, false if volatile
/// @param _factory Address of PoolFactory for tokenA and tokenB
/// @return reserveA Amount of reserves of the sorted token A
/// @return reserveB Amount of reserves of the sorted token B
function getReserves(
address tokenA,
address tokenB,
bool stable,
address _factory
) external view returns (uint256 reserveA, uint256 reserveB);
/// @notice Perform chained getAmountOut calculations on any number of pools
function getAmountsOut(
uint256 amountIn,
Route[] memory routes
) external view returns (uint256[] memory amounts);
// **** ADD LIQUIDITY ****
/// @notice Quote the amount deposited into a Pool
/// @param tokenA .
/// @param tokenB .
/// @param stable True if pool is stable, false if volatile
/// @param _factory Address of PoolFactory for tokenA and tokenB
/// @param amountADesired Amount of tokenA desired to deposit
/// @param amountBDesired Amount of tokenB desired to deposit
/// @return amountA Amount of tokenA to actually deposit
/// @return amountB Amount of tokenB to actually deposit
/// @return liquidity Amount of liquidity token returned from deposit
function quoteAddLiquidity(
address tokenA,
address tokenB,
bool stable,
address _factory,
uint256 amountADesired,
uint256 amountBDesired
)
external
view
returns (uint256 amountA, uint256 amountB, uint256 liquidity);
/// @notice Quote the amount of liquidity removed from a Pool
/// @param tokenA .
/// @param tokenB .
/// @param stable True if pool is stable, false if volatile
/// @param _factory Address of PoolFactory for tokenA and tokenB
/// @param liquidity Amount of liquidity to remove
/// @return amountA Amount of tokenA received
/// @return amountB Amount of tokenB received
function quoteRemoveLiquidity(
address tokenA,
address tokenB,
bool stable,
address _factory,
uint256 liquidity
) external view returns (uint256 amountA, uint256 amountB);
/// @notice Add liquidity of two tokens to a Pool
/// @param tokenA .
/// @param tokenB .
/// @param stable True if pool is stable, false if volatile
/// @param amountADesired Amount of tokenA desired to deposit
/// @param amountBDesired Amount of tokenB desired to deposit
/// @param amountAMin Minimum amount of tokenA to deposit
/// @param amountBMin Minimum amount of tokenB to deposit
/// @param to Recipient of liquidity token
/// @param deadline Deadline to receive liquidity
/// @return amountA Amount of tokenA to actually deposit
/// @return amountB Amount of tokenB to actually deposit
/// @return liquidity Amount of liquidity token returned from deposit
function addLiquidity(
address tokenA,
address tokenB,
bool stable,
uint256 amountADesired,
uint256 amountBDesired,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline
) external returns (uint256 amountA, uint256 amountB, uint256 liquidity);
/// @notice Add liquidity of a token and WETH (transferred as ETH) to a Pool
/// @param token .
/// @param stable True if pool is stable, false if volatile
/// @param amountTokenDesired Amount of token desired to deposit
/// @param amountTokenMin Minimum amount of token to deposit
/// @param amountETHMin Minimum amount of ETH to deposit
/// @param to Recipient of liquidity token
/// @param deadline Deadline to add liquidity
/// @return amountToken Amount of token to actually deposit
/// @return amountETH Amount of tokenETH to actually deposit
/// @return liquidity Amount of liquidity token returned from
/// deposit
function addLiquidityETH(
address token,
bool stable,
uint256 amountTokenDesired,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
)
external
payable
returns (uint256 amountToken, uint256 amountETH, uint256 liquidity);
// **** REMOVE LIQUIDITY ****
/// @notice Remove liquidity of two tokens from a Pool
/// @param tokenA .
/// @param tokenB .
/// @param stable True if pool is stable, false if volatile
/// @param liquidity Amount of liquidity to remove
/// @param amountAMin Minimum amount of tokenA to receive
/// @param amountBMin Minimum amount of tokenB to receive
/// @param to Recipient of tokens received
/// @param deadline Deadline to remove liquidity
/// @return amountA Amount of tokenA received
/// @return amountB Amount of tokenB received
function removeLiquidity(
address tokenA,
address tokenB,
bool stable,
uint256 liquidity,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline
) external returns (uint256 amountA, uint256 amountB);
/// @notice Remove liquidity of a token and WETH (returned as ETH) from a
/// Pool
/// @param token .
/// @param stable True if pool is stable, false if volatile
/// @param liquidity Amount of liquidity to remove
/// @param amountTokenMin Minimum amount of token to receive
/// @param amountETHMin Minimum amount of ETH to receive
/// @param to Recipient of liquidity token
/// @param deadline Deadline to receive liquidity
/// @return amountToken Amount of token received
/// @return amountETH Amount of ETH received
function removeLiquidityETH(
address token,
bool stable,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
) external returns (uint256 amountToken, uint256 amountETH);
/// @notice Remove liquidity of a fee-on-transfer token and WETH (returned
/// as ETH) from a Pool
/// @param token .
/// @param stable True if pool is stable, false if volatile
/// @param liquidity Amount of liquidity to remove
/// @param amountTokenMin Minimum amount of token to receive
/// @param amountETHMin Minimum amount of ETH to receive
/// @param to Recipient of liquidity token
/// @param deadline Deadline to receive liquidity
/// @return amountETH Amount of ETH received
function removeLiquidityETHSupportingFeeOnTransferTokens(
address token,
bool stable,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
) external returns (uint256 amountETH);
// **** SWAP ****
/// @notice Swap one token for another
/// @param amountIn Amount of token in
/// @param amountOutMin Minimum amount of desired token received
/// @param routes Array of trade routes used in the swap
/// @param to Recipient of the tokens received
/// @param deadline Deadline to receive tokens
/// @return amounts Array of amounts returned per route
function swapExactTokensForTokens(
uint256 amountIn,
uint256 amountOutMin,
Route[] calldata routes,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
/// @notice Swap ETH for a token
/// @param amountOutMin Minimum amount of desired token received
/// @param routes Array of trade routes used in the swap
/// @param to Recipient of the tokens received
/// @param deadline Deadline to receive tokens
/// @return amounts Array of amounts returned per route
function swapExactETHForTokens(
uint256 amountOutMin,
Route[] calldata routes,
address to,
uint256 deadline
) external payable returns (uint256[] memory amounts);
/// @notice Swap a token for WETH (returned as ETH)
/// @param amountIn Amount of token in
/// @param amountOutMin Minimum amount of desired ETH
/// @param routes Array of trade routes used in the swap
/// @param to Recipient of the tokens received
/// @param deadline Deadline to receive tokens
/// @return amounts Array of amounts returned per route
function swapExactTokensForETH(
uint256 amountIn,
uint256 amountOutMin,
Route[] calldata routes,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
/// @notice Swap one token for another without slippage protection
/// @return amounts Array of amounts to swap per route
/// @param routes Array of trade routes used in the swap
/// @param to Recipient of the tokens received
/// @param deadline Deadline to receive tokens
function UNSAFE_swapExactTokensForTokens(
uint256[] memory amounts,
Route[] calldata routes,
address to,
uint256 deadline
) external returns (uint256[] memory);
// **** SWAP (supporting fee-on-transfer tokens) ****
/// @notice Swap one token for another supporting fee-on-transfer tokens
/// @param amountIn Amount of token in
/// @param amountOutMin Minimum amount of desired token received
/// @param routes Array of trade routes used in the swap
/// @param to Recipient of the tokens received
/// @param deadline Deadline to receive tokens
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint256 amountIn,
uint256 amountOutMin,
Route[] calldata routes,
address to,
uint256 deadline
) external;
/// @notice Swap ETH for a token supporting fee-on-transfer tokens
/// @param amountOutMin Minimum amount of desired token received
/// @param routes Array of trade routes used in the swap
/// @param to Recipient of the tokens received
/// @param deadline Deadline to receive tokens
function swapExactETHForTokensSupportingFeeOnTransferTokens(
uint256 amountOutMin,
Route[] calldata routes,
address to,
uint256 deadline
) external payable;
/// @notice Swap a token for WETH (returned as ETH) supporting
/// fee-on-transfer tokens
/// @param amountIn Amount of token in
/// @param amountOutMin Minimum amount of desired ETH
/// @param routes Array of trade routes used in the swap
/// @param to Recipient of the tokens received
/// @param deadline Deadline to receive tokens
function swapExactTokensForETHSupportingFeeOnTransferTokens(
uint256 amountIn,
uint256 amountOutMin,
Route[] calldata routes,
address to,
uint256 deadline
) external;
/// @notice Zap a token A into a pool (B, C). (A can be equal to B or C).
/// Supports standard ERC20 tokens only (i.e. not fee-on-transfer
/// tokens etc).
/// Slippage is required for the initial swap.
/// Additional slippage may be required when adding liquidity as the
/// price of the token may have changed.
/// @param tokenIn Token you are zapping in from (i.e. input token).
/// @param amountInA Amount of input token you wish to send down routesA
/// @param amountInB Amount of input token you wish to send down routesB
/// @param zapInPool Contains zap struct information. See Zap struct.
/// @param routesA Route used to convert input token to tokenA
/// @param routesB Route used to convert input token to tokenB
/// @param to Address you wish to mint liquidity to.
/// @param stake Auto-stake liquidity in corresponding gauge.
/// @return liquidity Amount of LP tokens created from zapping in.
function zapIn(
address tokenIn,
uint256 amountInA,
uint256 amountInB,
Zap calldata zapInPool,
Route[] calldata routesA,
Route[] calldata routesB,
address to,
bool stake
) external payable returns (uint256 liquidity);
/// @notice Zap out a pool (B, C) into A.
/// Supports standard ERC20 tokens only (i.e. not fee-on-transfer
/// tokens etc).
/// Slippage is required for the removal of liquidity.
/// Additional slippage may be required on the swap as the
/// price of the token may have changed.
/// @param tokenOut Token you are zapping out to (i.e. output token).
/// @param liquidity Amount of liquidity you wish to remove.
/// @param zapOutPool Contains zap struct information. See Zap struct.
/// @param routesA Route used to convert tokenA into output token.
/// @param routesB Route used to convert tokenB into output token.
function zapOut(
address tokenOut,
uint256 liquidity,
Zap calldata zapOutPool,
Route[] calldata routesA,
Route[] calldata routesB
) external;
/// @notice Used to generate params required for zapping in.
/// Zap in => remove liquidity then swap.
/// Apply slippage to expected swap values to account for changes in
/// reserves in between.
/// @dev Output token refers to the token you want to zap in from.
/// @param tokenA .
/// @param tokenB .
/// @param stable .
/// @param _factory .
/// @param amountInA Amount of input token you wish to send down
/// routesA
/// @param amountInB Amount of input token you wish to send down
/// routesB
/// @param routesA Route used to convert input token to tokenA
/// @param routesB Route used to convert input token to tokenB
/// @return amountOutMinA Minimum output expected from swapping input
/// token to tokenA.
/// @return amountOutMinB Minimum output expected from swapping input
/// token to tokenB.
/// @return amountAMin Minimum amount of tokenA expected from
/// depositing liquidity.
/// @return amountBMin Minimum amount of tokenB expected from
/// depositing liquidity.
function generateZapInParams(
address tokenA,
address tokenB,
bool stable,
address _factory,
uint256 amountInA,
uint256 amountInB,
Route[] calldata routesA,
Route[] calldata routesB
)
external
view
returns (
uint256 amountOutMinA,
uint256 amountOutMinB,
uint256 amountAMin,
uint256 amountBMin
);
/// @notice Used to generate params required for zapping out.
/// Zap out => swap then add liquidity.
/// Apply slippage to expected liquidity values to account for
/// changes in reserves in between.
/// @dev Output token refers to the token you want to zap out of.
/// @param tokenA .
/// @param tokenB .
/// @param stable .
/// @param _factory .
/// @param liquidity Amount of liquidity being zapped out of into a
/// given output token.
/// @param routesA Route used to convert tokenA into output token.
/// @param routesB Route used to convert tokenB into output token.
/// @return amountOutMinA Minimum output expected from swapping tokenA
/// into output token.
/// @return amountOutMinB Minimum output expected from swapping tokenB
/// into output token.
/// @return amountAMin Minimum amount of tokenA expected from
/// withdrawing liquidity.
/// @return amountBMin Minimum amount of tokenB expected from
/// withdrawing liquidity.
function generateZapOutParams(
address tokenA,
address tokenB,
bool stable,
address _factory,
uint256 liquidity,
Route[] calldata routesA,
Route[] calldata routesB
)
external
view
returns (
uint256 amountOutMinA,
uint256 amountOutMinB,
uint256 amountAMin,
uint256 amountBMin
);
/// @notice Used by zapper to determine appropriate ratio of A to B to
/// deposit liquidity. Assumes stable pool.
/// @dev Returns stable liquidity ratio of B to (A + B).
/// E.g. if ratio is 0.4, it means there is more of A than there is of
/// B.
/// Therefore you should deposit more of token A than B.
/// @param tokenA tokenA of stable pool you are zapping into.
/// @param tokenB tokenB of stable pool you are zapping into.
/// @param factory Factory that created stable pool.
/// @return ratio Ratio of token0 to token1 required to deposit into zap.
function quoteStableLiquidityRatio(
address tokenA,
address tokenB,
address factory
) external view returns (uint256 ratio);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
pragma abicoder v2;
enum YieldMode {
AUTOMATIC,
VOID,
CLAIMABLE
}
/// @title The interface for the Algebra Factory
/// @dev Credit to Uniswap Labs under GPL-2.0-or-later license:
/// https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces
interface IAlgebraFactory {
/// @notice Emitted when a process of ownership renounce is started
/// @param timestamp The timestamp of event
/// @param finishTimestamp The timestamp when ownership renounce will be
/// possible to finish
event RenounceOwnershipStart(uint256 timestamp, uint256 finishTimestamp);
/// @notice Emitted when a process of ownership renounce cancelled
/// @param timestamp The timestamp of event
event RenounceOwnershipStop(uint256 timestamp);
/// @notice Emitted when a process of ownership renounce finished
/// @param timestamp The timestamp of ownership renouncement
event RenounceOwnershipFinish(uint256 timestamp);
/// @notice Emitted when a pool is created
/// @param token0 The first token of the pool by address sort order
/// @param token1 The second token of the pool by address sort order
/// @param pool The address of the created pool
event Pool(address indexed token0, address indexed token1, address pool);
/// @notice Emitted when the default community fee is changed
/// @param newDefaultCommunityFee The new default community fee value
event DefaultCommunityFee(uint16 newDefaultCommunityFee);
/// @notice Emitted when the default tickspacing is changed
/// @param newDefaultTickspacing The new default tickspacing value
event DefaultTickspacing(int24 newDefaultTickspacing);
/// @notice Emitted when the default fee is changed
/// @param newDefaultFee The new default fee value
event DefaultFee(uint16 newDefaultFee);
/// @notice Emitted when the defaultPluginFactory address is changed
/// @param defaultPluginFactoryAddress The new defaultPluginFactory address
event DefaultPluginFactory(address defaultPluginFactoryAddress);
/// @notice Emitted when the vaultFactory address is changed
/// @param newVaultFactory The new vaultFactory address
event VaultFactory(address newVaultFactory);
/// @notice Emitted when the pools creation mode is changed
/// @param mode_ The new pools creation mode
event PublicPoolCreationMode(bool mode_);
/// @dev Emitted when set new default blast governor address is changed.
/// @param defaultBlastGovernor The new default blast governor address
event DefaultBlastGovernor(address indexed defaultBlastGovernor);
/// @dev Emitted when set new default blast points address is changed.
/// @param defaultBlastPoints The new default blast points address
event DefaultBlastPoints(address indexed defaultBlastPoints);
/// @dev Emitted when set new default blast points operator address is
/// changed.
/// @param defaultBlastPointsOperator The new default blast points operator
/// address
event DefaultBlastPointsOperator(
address indexed defaultBlastPointsOperator
);
/// @notice Emitted when the rebase configuration for a token is set or
/// updated
/// @param token The address of the token whose rebase configuration has
/// been set or updated
/// @param isRebase Indicates whether the token is set as a rebasing token
/// @param mode The yield mode that has been set for the token, defining its
/// rebasing behavior
event ConfigurationForRebaseToken(
address token, bool isRebase, YieldMode mode
);
/// @dev Emitted when the rebasing tokens governor address is set.
/// @param oldRebasingTokensGovernor The previous address of the rebasing
/// tokens governor.
/// @param newRebasingTokensGovernor The new address of the rebasing tokens
/// governor.
event SetRebasingTokensGovernor(
address indexed oldRebasingTokensGovernor,
address indexed newRebasingTokensGovernor
);
/// @notice role that can change communityFee and tickspacing in pools
/// @return The hash corresponding to this role
function POOLS_ADMINISTRATOR_ROLE() external view returns (bytes32);
/// @notice role that can create pools when public pool creation is disabled
/// @return The hash corresponding to this role
function POOLS_CREATOR_ROLE() external view returns (bytes32);
/// @notice Returns `true` if `account` has been granted `role` or `account`
/// is owner.
/// @param role The hash corresponding to the role
/// @param account The address for which the role is checked
/// @return bool Whether the address has this role or the owner role or not
function hasRoleOrOwner(
bytes32 role,
address account
) external view returns (bool);
/// @notice Returns the current owner of the factory
/// @dev Can be changed by the current owner via transferOwnership(address
/// newOwner)
/// @return The address of the factory owner
function owner() external view returns (address);
/// @notice Returns the current default blast governor
/// @return The address of the default blast governor
function defaultBlastGovernor() external view returns (address);
/// @notice Returns the current default blast points
/// @return The address of the default blast points
function defaultBlastPoints() external view returns (address);
/// @notice Returns the current default blast points operator
/// @return The address of the default blast points operator
function defaultBlastPointsOperator() external view returns (address);
/// @notice Retrieves the yield mode configuration for a specified token
/// @param token The address of the token for which to retrieve the yield
/// mode
/// @return The yield mode (rebasing configuration) set for the given token
function configurationForBlastRebaseTokens(
address token
) external view returns (YieldMode);
/// @notice Return if a token is marked as a rebasing token in the factory
/// configuration
/// @param token The address of the token to check
/// @return True if the token is a rebasing token, false otherwise
function isRebaseToken(
address token
) external view returns (bool);
/// @notice Returns the current poolDeployerAddress
/// @return The address of the poolDeployer
function poolDeployer() external view returns (address);
/// @notice Returns the status of enable public pool creation mode
/// @return bool Whether the public creation mode is enable or not
function isPublicPoolCreationMode() external view returns (bool);
/// @notice Returns the default community fee
/// @return Fee which will be set at the creation of the pool
function defaultCommunityFee() external view returns (uint16);
/// @notice Returns the default fee
/// @return Fee which will be set at the creation of the pool
function defaultFee() external view returns (uint16);
/// @notice Returns the default tickspacing
/// @return Tickspacing which will be set at the creation of the pool
function defaultTickspacing() external view returns (int24);
/// @notice Return the current pluginFactory address
/// @dev This contract is used to automatically set a plugin address in new
/// liquidity pools
/// @return Algebra plugin factory
function defaultPluginFactory() external view returns (address);
/// @notice Address of the rebasing tokens governor
/// @return rebasing tokens governor
function rebasingTokensGovernor() external view returns (address);
/// @notice Return the current vaultFactory address
/// @dev This contract is used to automatically set a vault address in new
/// liquidity pools
/// @return Algebra vault factory
function vaultFactory() external view returns (address);
/// @notice Returns the default communityFee, tickspacing, fee and
/// communityFeeVault for pool
/// @param pool the address of liquidity pool
/// @return communityFee which will be set at the creation of the pool
/// @return tickSpacing which will be set at the creation of the pool
/// @return fee which will be set at the creation of the pool
/// @return communityFeeVault the address of communityFeeVault
function defaultConfigurationForPool(
address pool
)
external
view
returns (
uint16 communityFee,
int24 tickSpacing,
uint16 fee,
address communityFeeVault
);
/// @notice Deterministically computes the pool address given the token0 and
/// token1
/// @dev The method does not check if such a pool has been created
/// @param token0 first token
/// @param token1 second token
/// @return pool The contract address of the Algebra pool
function computePoolAddress(
address token0,
address token1
) external view returns (address pool);
/// @notice Returns the pool address for a given pair of tokens, or address
/// 0 if it does not exist
/// @dev tokenA and tokenB may be passed in either token0/token1 or
/// token1/token0 order
/// @param tokenA The contract address of either token0 or token1
/// @param tokenB The contract address of the other token
/// @return pool The pool address
function poolByPair(
address tokenA,
address tokenB
) external view returns (address pool);
/// @notice Returns the custom pool address for a given deployer and pair
/// @param deployer The custom pool deployer address
/// @param tokenA The contract address of either token0 or token1
/// @param tokenB The contract address of the other token
/// @return customPool The custom pool address
function customPoolByPair(
address deployer,
address tokenA,
address tokenB
) external view returns (address customPool);
/// @notice returns keccak256 of AlgebraPool init bytecode.
/// @dev the hash value changes with any change in the pool bytecode
/// @return Keccak256 hash of AlgebraPool contract init bytecode
function POOL_INIT_CODE_HASH() external view returns (bytes32);
/// @return timestamp The timestamp of the beginning of the
/// renounceOwnership process
function renounceOwnershipStartTimestamp()
external
view
returns (uint256 timestamp);
/// @notice Creates a pool for the given two tokens
/// @param tokenA One of the two tokens in the desired pool
/// @param tokenB The other of the two tokens in the desired pool
/// @dev tokenA and tokenB may be passed in either order: token0/token1 or
/// token1/token0.
/// The call will revert if the pool already exists or the token arguments
/// are invalid.
/// @return pool The address of the newly created pool
function createPool(
address tokenA,
address tokenB
) external returns (address pool);
/// @dev updates pools creation mode
/// @param mode_ the new mode for pools creation proccess
function setIsPublicPoolCreationMode(
bool mode_
) external;
/// @notice Sets the rebase configuration for a specific token
/// @param token_ The address of the token to configure
/// @param isRebase_ A boolean indicating whether the token is a rebasing
/// token or not
/// @param mode_ The yield mode to apply, defining how the rebasing
/// mechanism should operate
function setConfigurationForRebaseToken(
address token_,
bool isRebase_,
YieldMode mode_
) external;
/// @notice Sets the address of the rebasing tokens governor.
/// @dev Updates the address of the rebasing tokens governor. Can only be
/// called by an account with the DEFAULT_ADMIN_ROLE.
/// @param rebasingTokensGovernor_ The new address of the rebasing tokens
/// governor.
/// Emits a {SetRebasingTokensGovernor} event.
function setRebasingTokensGovernor(
address rebasingTokensGovernor_
) external;
/// @dev updates default community fee for new pools
/// @param newDefaultCommunityFee The new community fee, _must_ be <=
/// MAX_COMMUNITY_FEE
function setDefaultCommunityFee(
uint16 newDefaultCommunityFee
) external;
/// @dev updates default fee for new pools
/// @param newDefaultFee The new fee, _must_ be <= MAX_DEFAULT_FEE
function setDefaultFee(
uint16 newDefaultFee
) external;
/// @dev updates default tickspacing for new pools
/// @param newDefaultTickspacing The new tickspacing, _must_ be <=
/// MAX_TICK_SPACING and >= MIN_TICK_SPACING
function setDefaultTickspacing(
int24 newDefaultTickspacing
) external;
/// @dev updates pluginFactory address
/// @param newDefaultPluginFactory address of new plugin factory
function setDefaultPluginFactory(
address newDefaultPluginFactory
) external;
/// @dev updates vaultFactory address
/// @param newVaultFactory address of new vault factory
function setVaultFactory(
address newVaultFactory
) external;
/// @notice Starts process of renounceOwnership. After that, a certain
/// period
/// of time must pass before the ownership renounce can be completed.
function startRenounceOwnership() external;
/// @notice Stops process of renounceOwnership and removes timer.
function stopRenounceOwnership() external;
/// @dev updates default blast governor address on the factory
/// @param defaultBlastGovernor_ The new defautl blast governor address
function setDefaultBlastGovernor(
address defaultBlastGovernor_
) external;
/// @dev updates default blast points address on the factory
/// @param defaultBlastPoints_ The new defautl blast points address
function setDefaultBlastPoints(
address defaultBlastPoints_
) external;
/// @dev updates default blast points operator address on the factory
/// @param defaultBlastPointsOperator_ The new defautl blast points operator
/// address
function setDefaultBlastPointsOperator(
address defaultBlastPointsOperator_
) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @notice Library to define different pool actions.
/// @dev These are suggested common commands, however additional commands should
/// be defined as required
/// Some of these actions are not supported in the Router contracts or Position
/// Manager contracts, but are left as they may be helpful commands for other
/// peripheral contracts.
library Actions {
// pool actions
// liquidity actions
uint256 internal constant INCREASE_LIQUIDITY = 0x00;
uint256 internal constant DECREASE_LIQUIDITY = 0x01;
uint256 internal constant MINT_POSITION = 0x02;
uint256 internal constant BURN_POSITION = 0x03;
uint256 internal constant INCREASE_LIQUIDITY_FROM_DELTAS = 0x04;
uint256 internal constant MINT_POSITION_FROM_DELTAS = 0x05;
// swapping
uint256 internal constant SWAP_EXACT_IN_SINGLE = 0x06;
uint256 internal constant SWAP_EXACT_IN = 0x07;
uint256 internal constant SWAP_EXACT_OUT_SINGLE = 0x08;
uint256 internal constant SWAP_EXACT_OUT = 0x09;
// donate
// note this is not supported in the position manager or router
uint256 internal constant DONATE = 0x0a;
// closing deltas on the pool manager
// settling
uint256 internal constant SETTLE = 0x0b;
uint256 internal constant SETTLE_ALL = 0x0c;
uint256 internal constant SETTLE_PAIR = 0x0d;
// taking
uint256 internal constant TAKE = 0x0e;
uint256 internal constant TAKE_ALL = 0x0f;
uint256 internal constant TAKE_PORTION = 0x10;
uint256 internal constant TAKE_PAIR = 0x11;
uint256 internal constant CLOSE_CURRENCY = 0x12;
uint256 internal constant CLEAR_OR_TAKE = 0x13;
uint256 internal constant SWEEP = 0x14;
uint256 internal constant WRAP = 0x15;
uint256 internal constant UNWRAP = 0x16;
// minting/burning 6909s to close deltas
// note this is not supported in the position manager or router
uint256 internal constant MINT_6909 = 0x17;
uint256 internal constant BURN_6909 = 0x18;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { PoolKey } from "./types/PoolKey.sol";
import { Currency } from "./types/Currency.sol";
import { PathKey } from "./libraries/PathKey.sol";
/// @title IV4Router
/// @notice Interface for the V4Router contract
interface IV4Router {
/// @notice Emitted when an exactInput swap does not receive its
/// minAmountOut
error V4TooLittleReceived(
uint256 minAmountOutReceived, uint256 amountReceived
);
/// @notice Emitted when an exactOutput is asked for more than its
/// maxAmountIn
error V4TooMuchRequested(
uint256 maxAmountInRequested, uint256 amountRequested
);
/// @notice Parameters for a single-hop exact-input swap
struct ExactInputSingleParams {
PoolKey poolKey;
bool zeroForOne;
uint128 amountIn;
uint128 amountOutMinimum;
bytes hookData;
}
/// @notice Parameters for a multi-hop exact-input swap
struct ExactInputParams {
Currency currencyIn;
PathKey[] path;
uint128 amountIn;
uint128 amountOutMinimum;
}
/// @notice Parameters for a single-hop exact-output swap
struct ExactOutputSingleParams {
PoolKey poolKey;
bool zeroForOne;
uint128 amountOut;
uint128 amountInMaximum;
bytes hookData;
}
/// @notice Parameters for a multi-hop exact-output swap
struct ExactOutputParams {
Currency currencyOut;
PathKey[] path;
uint128 amountOut;
uint128 amountInMaximum;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { Currency } from "./Currency.sol";
import { IHooks } from "../IHooks.sol";
import { PoolIdLibrary } from "./PoolId.sol";
using PoolIdLibrary for PoolKey global;
/// @notice Returns the key for identifying a pool
struct PoolKey {
/// @notice The lower currency of the pool, sorted numerically
Currency currency0;
/// @notice The higher currency of the pool, sorted numerically
Currency currency1;
/// @notice The pool LP fee, capped at 1_000_000. If the highest bit is 1,
/// the pool has a dynamic fee and must be exactly equal to 0x800000
uint24 fee;
/// @notice Ticks that involve positions must be a multiple of tick spacing
int24 tickSpacing;
/// @notice The hooks of the pool
IHooks hooks;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { PoolKey } from "./types/PoolKey.sol";
import { BalanceDelta } from "./types/BalanceDelta.sol";
import { IPoolManager } from "./IPoolManager.sol";
import { BeforeSwapDelta } from "./types/BeforeSwapDelta.sol";
/// @notice V4 decides whether to invoke specific hooks by inspecting the least
/// significant bits
/// of the address that the hooks contract is deployed to.
/// For example, a hooks contract deployed to address:
/// 0x0000000000000000000000000000000000002400
/// has the lowest bits '10 0100 0000 0000' which would cause the 'before
/// initialize' and 'after add liquidity' hooks to be used.
/// See the Hooks library for the full spec.
/// @dev Should only be callable by the v4 PoolManager.
interface IHooks {
/// @notice The hook called before the state of a pool is initialized
/// @param sender The initial msg.sender for the initialize call
/// @param key The key for the pool being initialized
/// @param sqrtPriceX96 The sqrt(price) of the pool as a Q64.96
/// @return bytes4 The function selector for the hook
function beforeInitialize(
address sender,
PoolKey calldata key,
uint160 sqrtPriceX96
) external returns (bytes4);
/// @notice The hook called after the state of a pool is initialized
/// @param sender The initial msg.sender for the initialize call
/// @param key The key for the pool being initialized
/// @param sqrtPriceX96 The sqrt(price) of the pool as a Q64.96
/// @param tick The current tick after the state of a pool is initialized
/// @return bytes4 The function selector for the hook
function afterInitialize(
address sender,
PoolKey calldata key,
uint160 sqrtPriceX96,
int24 tick
) external returns (bytes4);
/// @notice The hook called before liquidity is added
/// @param sender The initial msg.sender for the add liquidity call
/// @param key The key for the pool
/// @param params The parameters for adding liquidity
/// @param hookData Arbitrary data handed into the PoolManager by the
/// liquidity provider to be passed on to the hook
/// @return bytes4 The function selector for the hook
function beforeAddLiquidity(
address sender,
PoolKey calldata key,
IPoolManager.ModifyLiquidityParams calldata params,
bytes calldata hookData
) external returns (bytes4);
/// @notice The hook called after liquidity is added
/// @param sender The initial msg.sender for the add liquidity call
/// @param key The key for the pool
/// @param params The parameters for adding liquidity
/// @param delta The caller's balance delta after adding liquidity; the sum
/// of principal delta, fees accrued, and hook delta
/// @param feesAccrued The fees accrued since the last time fees were
/// collected from this position
/// @param hookData Arbitrary data handed into the PoolManager by the
/// liquidity provider to be passed on to the hook
/// @return bytes4 The function selector for the hook
/// @return BalanceDelta The hook's delta in token0 and token1. Positive:
/// the hook is owed/took currency, negative: the hook owes/sent currency
function afterAddLiquidity(
address sender,
PoolKey calldata key,
IPoolManager.ModifyLiquidityParams calldata params,
BalanceDelta delta,
BalanceDelta feesAccrued,
bytes calldata hookData
) external returns (bytes4, BalanceDelta);
/// @notice The hook called before liquidity is removed
/// @param sender The initial msg.sender for the remove liquidity call
/// @param key The key for the pool
/// @param params The parameters for removing liquidity
/// @param hookData Arbitrary data handed into the PoolManager by the
/// liquidity provider to be be passed on to the hook
/// @return bytes4 The function selector for the hook
function beforeRemoveLiquidity(
address sender,
PoolKey calldata key,
IPoolManager.ModifyLiquidityParams calldata params,
bytes calldata hookData
) external returns (bytes4);
/// @notice The hook called after liquidity is removed
/// @param sender The initial msg.sender for the remove liquidity call
/// @param key The key for the pool
/// @param params The parameters for removing liquidity
/// @param delta The caller's balance delta after removing liquidity; the
/// sum of principal delta, fees accrued, and hook delta
/// @param feesAccrued The fees accrued since the last time fees were
/// collected from this position
/// @param hookData Arbitrary data handed into the PoolManager by the
/// liquidity provider to be be passed on to the hook
/// @return bytes4 The function selector for the hook
/// @return BalanceDelta The hook's delta in token0 and token1. Positive:
/// the hook is owed/took currency, negative: the hook owes/sent currency
function afterRemoveLiquidity(
address sender,
PoolKey calldata key,
IPoolManager.ModifyLiquidityParams calldata params,
BalanceDelta delta,
BalanceDelta feesAccrued,
bytes calldata hookData
) external returns (bytes4, BalanceDelta);
/// @notice The hook called before a swap
/// @param sender The initial msg.sender for the swap call
/// @param key The key for the pool
/// @param params The parameters for the swap
/// @param hookData Arbitrary data handed into the PoolManager by the
/// swapper to be be passed on to the hook
/// @return bytes4 The function selector for the hook
/// @return BeforeSwapDelta The hook's delta in specified and unspecified
/// currencies. Positive: the hook is owed/took currency, negative: the hook
/// owes/sent currency
/// @return uint24 Optionally override the lp fee, only used if three
/// conditions are met: 1. the Pool has a dynamic fee, 2. the value's 2nd
/// highest bit is set (23rd bit, 0x400000), and 3. the value is less than
/// or equal to the maximum fee (1 million)
function beforeSwap(
address sender,
PoolKey calldata key,
IPoolManager.SwapParams calldata params,
bytes calldata hookData
) external returns (bytes4, BeforeSwapDelta, uint24);
/// @notice The hook called after a swap
/// @param sender The initial msg.sender for the swap call
/// @param key The key for the pool
/// @param params The parameters for the swap
/// @param delta The amount owed to the caller (positive) or owed to the
/// pool (negative)
/// @param hookData Arbitrary data handed into the PoolManager by the
/// swapper to be be passed on to the hook
/// @return bytes4 The function selector for the hook
/// @return int128 The hook's delta in unspecified currency. Positive: the
/// hook is owed/took currency, negative: the hook owes/sent currency
function afterSwap(
address sender,
PoolKey calldata key,
IPoolManager.SwapParams calldata params,
BalanceDelta delta,
bytes calldata hookData
) external returns (bytes4, int128);
/// @notice The hook called before donate
/// @param sender The initial msg.sender for the donate call
/// @param key The key for the pool
/// @param amount0 The amount of token0 being donated
/// @param amount1 The amount of token1 being donated
/// @param hookData Arbitrary data handed into the PoolManager by the donor
/// to be be passed on to the hook
/// @return bytes4 The function selector for the hook
function beforeDonate(
address sender,
PoolKey calldata key,
uint256 amount0,
uint256 amount1,
bytes calldata hookData
) external returns (bytes4);
/// @notice The hook called after donate
/// @param sender The initial msg.sender for the donate call
/// @param key The key for the pool
/// @param amount0 The amount of token0 being donated
/// @param amount1 The amount of token1 being donated
/// @param hookData Arbitrary data handed into the PoolManager by the donor
/// to be be passed on to the hook
/// @return bytes4 The function selector for the hook
function afterDonate(
address sender,
PoolKey calldata key,
uint256 amount0,
uint256 amount1,
bytes calldata hookData
) external returns (bytes4);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { IERC20Minimal } from "../IERC20Minimal.sol";
import { CustomRevert } from "../libraries/CustomRevert.sol";
type Currency is address;
using {
greaterThan as >,
lessThan as <,
greaterThanOrEqualTo as >=,
equals as ==
} for Currency global;
using CurrencyLibrary for Currency global;
function equals(Currency currency, Currency other) pure returns (bool) {
return Currency.unwrap(currency) == Currency.unwrap(other);
}
function greaterThan(Currency currency, Currency other) pure returns (bool) {
return Currency.unwrap(currency) > Currency.unwrap(other);
}
function lessThan(Currency currency, Currency other) pure returns (bool) {
return Currency.unwrap(currency) < Currency.unwrap(other);
}
function greaterThanOrEqualTo(
Currency currency,
Currency other
) pure returns (bool) {
return Currency.unwrap(currency) >= Currency.unwrap(other);
}
/// @title CurrencyLibrary
/// @dev This library allows for transferring and holding native tokens and
/// ERC20 tokens
library CurrencyLibrary {
/// @notice Additional context for ERC-7751 wrapped error when a native
/// transfer fails
error NativeTransferFailed();
/// @notice Additional context for ERC-7751 wrapped error when an ERC20
/// transfer fails
error ERC20TransferFailed();
/// @notice A constant to represent the native currency
Currency public constant ADDRESS_ZERO = Currency.wrap(address(0));
function transfer(Currency currency, address to, uint256 amount) internal {
// altered from
// https://github.com/transmissions11/solmate/blob/44a9963d4c78111f77caa0e65d677b8b46d6f2e6/src/utils/SafeTransferLib.sol
// modified custom error selectors
bool success;
if (currency.isAddressZero()) {
assembly ("memory-safe") {
// Transfer the ETH and revert if it fails.
success := call(gas(), to, amount, 0, 0, 0, 0)
}
// revert with NativeTransferFailed, containing the bubbled up error
// as an argument
if (!success) {
CustomRevert.bubbleUpAndRevertWith(
to, bytes4(0), NativeTransferFailed.selector
);
}
} else {
assembly ("memory-safe") {
// Get a pointer to some free memory.
let fmp := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with
// the function selector.
mstore(
fmp,
0xa9059cbb00000000000000000000000000000000000000000000000000000000
)
mstore(
add(fmp, 4),
and(to, 0xffffffffffffffffffffffffffffffffffffffff)
) // Append and mask the "to" argument.
mstore(add(fmp, 36), amount) // Append the "amount" argument.
// Masking not required as it's a full 32 byte type.
success :=
and(
// Set success to whether the call reverted, if not we check
// it either
// returned exactly 1 (can't just be non-zero data), or had
// no return data.
or(
and(eq(mload(0), 1), gt(returndatasize(), 31)),
iszero(returndatasize())
),
// We use 68 because the length of our calldata totals up
// like so: 4 + 32 * 2.
// We use 0 and 32 to copy up to 32 bytes of return data
// into the scratch space.
// Counterintuitively, this call must be positioned second
// to the or() call in the
// surrounding and() call or else returndatasize() will be
// zero during the computation.
call(gas(), currency, 0, fmp, 68, 0, 32)
)
// Now clean the memory we used
mstore(fmp, 0) // 4 byte `selector` and 28 bytes of `to` were
// stored here
mstore(add(fmp, 0x20), 0) // 4 bytes of `to` and 28 bytes of
// `amount` were stored here
mstore(add(fmp, 0x40), 0) // 4 bytes of `amount` were stored
// here
}
// revert with ERC20TransferFailed, containing the bubbled up error
// as an argument
if (!success) {
CustomRevert.bubbleUpAndRevertWith(
Currency.unwrap(currency),
IERC20Minimal.transfer.selector,
ERC20TransferFailed.selector
);
}
}
}
function balanceOfSelf(
Currency currency
) internal view returns (uint256) {
if (currency.isAddressZero()) {
return address(this).balance;
} else {
return IERC20Minimal(Currency.unwrap(currency)).balanceOf(
address(this)
);
}
}
function balanceOf(
Currency currency,
address owner
) internal view returns (uint256) {
if (currency.isAddressZero()) {
return owner.balance;
} else {
return IERC20Minimal(Currency.unwrap(currency)).balanceOf(owner);
}
}
function isAddressZero(
Currency currency
) internal pure returns (bool) {
return Currency.unwrap(currency) == Currency.unwrap(ADDRESS_ZERO);
}
function toId(
Currency currency
) internal pure returns (uint256) {
return uint160(Currency.unwrap(currency));
}
// If the upper 12 bytes are non-zero, they will be zero-ed out
// Therefore, fromId() and toId() are not inverses of each other
function fromId(
uint256 id
) internal pure returns (Currency) {
return Currency.wrap(address(uint160(id)));
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
/// @title Pool state that never changes
/// @notice These parameters are fixed for a pool forever, i.e., the methods
/// will always return the same values
interface IUniswapV3PoolImmutables {
/// @notice The contract that deployed the pool, which must adhere to the
/// IUniswapV3Factory interface
/// @return The contract address
function factory() external view returns (address);
/// @notice The first of the two tokens of the pool, sorted by address
/// @return The token contract address
function token0() external view returns (address);
/// @notice The second of the two tokens of the pool, sorted by address
/// @return The token contract address
function token1() external view returns (address);
/// @notice The pool's fee in hundredths of a bip, i.e. 1e-6
/// @return The fee
function fee() external view returns (uint24);
/// @notice The pool tick spacing
/// @dev Ticks can only be used at multiples of this value, minimum of 1 and
/// always positive
/// e.g.: a tickSpacing of 3 means ticks can be initialized every 3rd tick,
/// i.e., ..., -6, -3, 0, 3, 6, ...
/// This value is an int24 to avoid casting even though it is always
/// positive.
/// @return The tick spacing
function tickSpacing() external view returns (int24);
/// @notice The maximum amount of position liquidity that can use any tick
/// in the range
/// @dev This parameter is enforced per tick to prevent liquidity from
/// overflowing a uint128 at any point, and
/// also prevents out-of-range liquidity from being used to prevent adding
/// in-range liquidity to a pool
/// @return The max amount of liquidity per tick
function maxLiquidityPerTick() external view returns (uint128);
}
/// @title Pool state that can change
/// @notice These methods compose the pool's state, and can change with any
/// frequency including multiple times
/// per transaction
interface IUniswapV3PoolState {
/// @notice The 0th storage slot in the pool stores many values, and is
/// exposed as a single method to save gas
/// when accessed externally.
/// @return sqrtPriceX96 The current price of the pool as a
/// sqrt(token1/token0) Q64.96 value
/// @return tick The current tick of the pool, i.e. according to the last
/// tick transition that was run.
/// This value may not always be equal to
/// SqrtTickMath.getTickAtSqrtRatio(sqrtPriceX96) if the price is on a tick
/// boundary.
/// @return observationIndex The index of the last oracle observation that
/// was written,
/// @return observationCardinality The current maximum number of
/// observations stored in the pool,
/// @return observationCardinalityNext The next maximum number of
/// observations, to be updated when the observation.
/// @return feeProtocol The protocol fee for both tokens of the pool.
/// Encoded as two 4 bit values, where the protocol fee of token1 is shifted
/// 4 bits and the protocol fee of token0
/// is the lower 4 bits. Used as the denominator of a fraction of the swap
/// fee, e.g. 4 means 1/4th of the swap fee.
/// unlocked Whether the pool is currently locked to reentrancy
function slot0()
external
view
returns (
uint160 sqrtPriceX96,
int24 tick,
uint16 observationIndex,
uint16 observationCardinality,
uint16 observationCardinalityNext,
uint8 feeProtocol,
bool unlocked
);
/// @notice The fee growth as a Q128.128 fees of token0 collected per unit
/// of liquidity for the entire life of the pool
/// @dev This value can overflow the uint256
function feeGrowthGlobal0X128() external view returns (uint256);
/// @notice The fee growth as a Q128.128 fees of token1 collected per unit
/// of liquidity for the entire life of the pool
/// @dev This value can overflow the uint256
function feeGrowthGlobal1X128() external view returns (uint256);
/// @notice The amounts of token0 and token1 that are owed to the protocol
/// @dev Protocol fees will never exceed uint128 max in either token
function protocolFees()
external
view
returns (uint128 token0, uint128 token1);
/// @notice The currently in range liquidity available to the pool
/// @dev This value has no relationship to the total liquidity across all
/// ticks
/// @return The liquidity at the current price of the pool
function liquidity() external view returns (uint128);
/// @notice Look up information about a specific tick in the pool
/// @param tick The tick to look up
/// @return liquidityGross the total amount of position liquidity that uses
/// the pool either as tick lower or
/// tick upper
/// @return liquidityNet how much liquidity changes when the pool price
/// crosses the tick,
/// @return feeGrowthOutside0X128 the fee growth on the other side of the
/// tick from the current tick in token0,
/// @return feeGrowthOutside1X128 the fee growth on the other side of the
/// tick from the current tick in token1,
/// @return tickCumulativeOutside the cumulative tick value on the other
/// side of the tick from the current tick
/// @return secondsPerLiquidityOutsideX128 the seconds spent per liquidity
/// on the other side of the tick from the current tick,
/// @return secondsOutside the seconds spent on the other side of the tick
/// from the current tick,
/// @return initialized Set to true if the tick is initialized, i.e.
/// liquidityGross is greater than 0, otherwise equal to false.
/// Outside values can only be used if the tick is initialized, i.e. if
/// liquidityGross is greater than 0.
/// In addition, these values are only relative and must be used only in
/// comparison to previous snapshots for
/// a specific position.
function ticks(
int24 tick
)
external
view
returns (
uint128 liquidityGross,
int128 liquidityNet,
uint256 feeGrowthOutside0X128,
uint256 feeGrowthOutside1X128,
int56 tickCumulativeOutside,
uint160 secondsPerLiquidityOutsideX128,
uint32 secondsOutside,
bool initialized
);
/// @notice Returns 256 packed tick initialized boolean values. See
/// TickBitmap for more information
function tickBitmap(
int16 wordPosition
) external view returns (uint256);
/// @notice Returns the information about a position by the position's key
/// @param key The position's key is a hash of a preimage composed by the
/// owner, tickLower and tickUpper
/// @return liquidity The amount of liquidity in the position,
/// @return feeGrowthInside0LastX128 fee growth of token0 inside the tick
/// range as of the last mint/burn/poke,
/// @return feeGrowthInside1LastX128 fee growth of token1 inside the tick
/// range as of the last mint/burn/poke,
/// @return tokensOwed0 the computed amount of token0 owed to the position
/// as of the last mint/burn/poke,
/// @return tokensOwed1 the computed amount of token1 owed to the position
/// as of the last mint/burn/poke
function positions(
bytes32 key
)
external
view
returns (
uint128 liquidity,
uint256 feeGrowthInside0LastX128,
uint256 feeGrowthInside1LastX128,
uint128 tokensOwed0,
uint128 tokensOwed1
);
/// @notice Returns data about a specific observation index
/// @param index The element of the observations array to fetch
/// @dev You most likely want to use #observe() instead of this method to
/// get an observation as of some amount of time
/// ago, rather than at a specific index in the array.
/// @return blockTimestamp The timestamp of the observation,
/// @return tickCumulative the tick multiplied by seconds elapsed for the
/// life of the pool as of the observation timestamp,
/// @return secondsPerLiquidityCumulativeX128 the seconds per in range
/// liquidity for the life of the pool as of the observation timestamp,
/// @return initialized whether the observation has been initialized and the
/// values are safe to use
function observations(
uint256 index
)
external
view
returns (
uint32 blockTimestamp,
int56 tickCumulative,
uint160 secondsPerLiquidityCumulativeX128,
bool initialized
);
}
interface IUniswapV3Pool is IUniswapV3PoolImmutables, IUniswapV3PoolState {
function flash(
address recipient,
uint256 amount0,
uint256 amount1,
bytes calldata data
) external;
function swap(
address recipient,
bool zeroForOne,
int256 amountSpecified,
uint160 sqrtPriceLimitX96,
bytes calldata data
) external returns (int256 amount0, int256 amount1);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.7.5;
interface ISwapRouter02 {
struct ExactInputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 amountIn;
uint256 amountOutMinimum;
uint160 sqrtPriceLimitX96;
}
/// @notice Swaps `amountIn` of one token for as much as possible of another
/// token
/// @param params The parameters necessary for the swap, encoded as
/// `ExactInputSingleParams` in calldata
/// @return amountOut The amount of the received token
function exactInputSingle(
ExactInputSingleParams calldata params
) external payable returns (uint256 amountOut);
}
/// @title Router token swapping functionality
/// @notice Functions for swapping tokens via Uniswap V3
interface ISwapRouter {
struct ExactInputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 deadline;
uint256 amountIn;
uint256 amountOutMinimum;
uint160 sqrtPriceLimitX96;
}
/// @notice Swaps `amountIn` of one token for as much as possible of another
/// token
/// @param params The parameters necessary for the swap, encoded as
/// `ExactInputSingleParams` in calldata
/// @return amountOut The amount of the received token
function exactInputSingle(
ExactInputSingleParams calldata params
) external payable returns (uint256 amountOut);
struct ExactInputParams {
bytes path;
address recipient;
uint256 deadline;
uint256 amountIn;
uint256 amountOutMinimum;
}
/// @notice Swaps `amountIn` of one token for as much as possible of another
/// along the specified path
/// @param params The parameters necessary for the multi-hop swap, encoded
/// as `ExactInputParams` in calldata
/// @return amountOut The amount of the received token
function exactInput(
ExactInputParams calldata params
) external payable returns (uint256 amountOut);
struct ExactOutputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 deadline;
uint256 amountOut;
uint256 amountInMaximum;
uint160 sqrtPriceLimitX96;
}
/// @notice Swaps as little as possible of one token for `amountOut` of
/// another token
/// @param params The parameters necessary for the swap, encoded as
/// `ExactOutputSingleParams` in calldata
/// @return amountIn The amount of the input token
function exactOutputSingle(
ExactOutputSingleParams calldata params
) external payable returns (uint256 amountIn);
struct ExactOutputParams {
bytes path;
address recipient;
uint256 deadline;
uint256 amountOut;
uint256 amountInMaximum;
}
/// @notice Swaps as little as possible of one token for `amountOut` of
/// another along the specified path (reversed)
/// @param params The parameters necessary for the multi-hop swap, encoded
/// as `ExactOutputParams` in calldata
/// @return amountIn The amount of the input token
function exactOutput(
ExactOutputParams calldata params
) external payable returns (uint256 amountIn);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface ICamelotNftPool {
function globalState()
external
view
returns (
uint160 price,
int24 tick,
uint16 feeZto,
uint16 feeOtz,
uint16 timepointIndex,
uint8 communityFeeToken0,
uint8 communityFeeToken1,
bool unlocked
);
function ticks(
int24 tick
)
external
view
returns (
uint128 liquidityTotal,
int128 liquidityDelta,
uint256 outerFeeGrowth0Token,
uint256 outerFeeGrowth1Token,
int56 outerTickCumulative,
uint160 outerSecondsPerLiquidity,
uint32 outerSecondsSpent,
bool initialized
);
}
interface ICamelotV3Factory {
function poolByPair(
address token0,
address token1
) external view returns (address pool);
}
/// @dev Camelot V2 router with referrer param (fee-on-transfer supporting)
interface ICamelotV2Router {
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
address referrer,
uint256 deadline
) external;
function swapExactETHForTokensSupportingFeeOnTransferTokens(
uint256 amountOutMin,
address[] calldata path,
address to,
address referrer,
uint256 deadline
) external payable;
function swapExactTokensForETHSupportingFeeOnTransferTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
address referrer,
uint256 deadline
) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
interface ISolidlyRouter {
/// @dev Route struct for Solidly-style routers (Velodrome, Aerodrome, etc.)
struct Route {
address from;
address to;
bool stable;
}
function swapExactTokensForTokens(
uint256 amountIn,
uint256 amountOutMin,
Route[] calldata routes,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.7.5;
pragma abicoder v2;
/// @title Router token swapping functionality
/// @notice Functions for swapping tokens via Algebra
/// @dev Credit to Uniswap Labs under GPL-2.0-or-later license:
/// https://github.com/Uniswap/v3-periphery
interface IAlgebraSwapRouter {
struct ExactInputSingleParams {
address tokenIn;
address tokenOut;
address recipient;
uint256 deadline;
uint256 amountIn;
uint256 amountOutMinimum;
uint160 limitSqrtPrice;
}
/// @notice Swaps `amountIn` of one token for as much as possible of another token
/// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata
/// @return amountOut The amount of the received token
function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.7.5;
pragma abicoder v2;
/// @title Router token swapping functionality
/// @notice Functions for swapping tokens via Algebra
/// @dev Credit to Uniswap Labs under GPL-2.0-or-later license:
/// https://github.com/Uniswap/v3-periphery
interface IAlgebraIntegralSwapRouter {
struct ExactInputSingleParams {
address tokenIn;
address tokenOut;
address deployer;
address recipient;
uint256 deadline;
uint256 amountIn;
uint256 amountOutMinimum;
uint160 limitSqrtPrice;
}
/// @notice Swaps `amountIn` of one token for as much as possible of another token
/// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata
/// @return amountOut The amount of the received token
function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut);
struct ExactInputParams {
bytes path;
address recipient;
uint256 deadline;
uint256 amountIn;
uint256 amountOutMinimum;
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.7.5;
pragma abicoder v2;
/// @title Router token swapping functionality
/// @notice Functions for swapping tokens via CL
interface ISlipstreamSwapRouter {
struct ExactInputSingleParams {
address tokenIn;
address tokenOut;
int24 tickSpacing;
address recipient;
uint256 deadline;
uint256 amountIn;
uint256 amountOutMinimum;
uint160 sqrtPriceLimitX96;
}
/// @notice Swaps `amountIn` of one token for as much as possible of another token
/// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata
/// @return amountOut The amount of the received token
function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut);
}// SPDX-License-Identifier: MIT OR GPL-3.0-or-later
pragma solidity ^0.8.0;
interface IBlackholeRouter {
struct route {
address pair;
address from;
address to;
bool stable;
bool concentrated;
address receiver;
}
function pairFor(address tokenA, address tokenB, bool stable) external view returns (address pair);
function swapExactTokensForTokens(uint amountIn,uint amountOutMin,route[] calldata routes,address to,uint deadline) external returns (uint[] memory amounts);
function addLiquidity(address tokenA,address tokenB,bool stable,uint amountADesired,uint amountBDesired,uint amountAMin,uint amountBMin,address to,uint deadline) external returns (uint amountA, uint amountB, uint liquidity);
function isPair(address pair) external view returns (bool);
function getReserves(address tokenA, address tokenB, bool stable) external view returns (uint reserveA, uint reserveB);
function getAmountOut(uint amountIn, address tokenIn, address tokenOut) external view returns (uint amount, bool stable);
function getPoolAmountOut(uint amountIn, address tokenIn, address pair) external view returns (uint amount);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface ISlipstreamFactory {
function getPool(address token0, address token1, int24 tickSpacing) external view returns (address);
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
abstract contract ERC20 {
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
event Transfer(address indexed from, address indexed to, uint256 amount);
event Approval(address indexed owner, address indexed spender, uint256 amount);
/*//////////////////////////////////////////////////////////////
METADATA STORAGE
//////////////////////////////////////////////////////////////*/
string public name;
string public symbol;
uint8 public immutable decimals;
/*//////////////////////////////////////////////////////////////
ERC20 STORAGE
//////////////////////////////////////////////////////////////*/
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
/*//////////////////////////////////////////////////////////////
EIP-2612 STORAGE
//////////////////////////////////////////////////////////////*/
uint256 internal immutable INITIAL_CHAIN_ID;
bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;
mapping(address => uint256) public nonces;
/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/
constructor(
string memory _name,
string memory _symbol,
uint8 _decimals
) {
name = _name;
symbol = _symbol;
decimals = _decimals;
INITIAL_CHAIN_ID = block.chainid;
INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
}
/*//////////////////////////////////////////////////////////////
ERC20 LOGIC
//////////////////////////////////////////////////////////////*/
function approve(address spender, uint256 amount) public virtual returns (bool) {
allowance[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
function transfer(address to, uint256 amount) public virtual returns (bool) {
balanceOf[msg.sender] -= amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(msg.sender, to, amount);
return true;
}
function transferFrom(
address from,
address to,
uint256 amount
) public virtual returns (bool) {
uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.
if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;
balanceOf[from] -= amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(from, to, amount);
return true;
}
/*//////////////////////////////////////////////////////////////
EIP-2612 LOGIC
//////////////////////////////////////////////////////////////*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual {
require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");
// Unchecked because the only math done is incrementing
// the owner's nonce which cannot realistically overflow.
unchecked {
address recoveredAddress = ecrecover(
keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR(),
keccak256(
abi.encode(
keccak256(
"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
),
owner,
spender,
value,
nonces[owner]++,
deadline
)
)
)
),
v,
r,
s
);
require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");
allowance[recoveredAddress][spender] = value;
}
emit Approval(owner, spender, value);
}
function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
}
function computeDomainSeparator() internal view virtual returns (bytes32) {
return
keccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes(name)),
keccak256("1"),
block.chainid,
address(this)
)
);
}
/*//////////////////////////////////////////////////////////////
INTERNAL MINT/BURN LOGIC
//////////////////////////////////////////////////////////////*/
function _mint(address to, uint256 amount) internal virtual {
totalSupply += amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(address(0), to, amount);
}
function _burn(address from, uint256 amount) internal virtual {
balanceOf[from] -= amount;
// Cannot underflow because a user's balance
// will never be larger than the total supply.
unchecked {
totalSupply -= amount;
}
emit Transfer(from, address(0), amount);
}
}// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC20.sol) pragma solidity ^0.8.0; import "../token/ERC20/IERC20.sol";
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { Currency } from
"contracts/interfaces/external/uniswap/v4/types/Currency.sol";
import { IHooks } from "contracts/interfaces/external/uniswap/v4/IHooks.sol";
import { PoolKey } from
"contracts/interfaces/external/uniswap/v4/types/PoolKey.sol";
struct PathKey {
Currency intermediateCurrency;
uint24 fee;
int24 tickSpacing;
IHooks hooks;
bytes hookData;
}
using PathKeyLibrary for PathKey global;
/// @title PathKey Library
/// @notice Functions for working with PathKeys
library PathKeyLibrary {
/// @notice Get the pool and swap direction for a given PathKey
/// @param params the given PathKey
/// @param currencyIn the input currency
/// @return poolKey the pool key of the swap
/// @return zeroForOne the direction of the swap, true if currency0 is being
/// swapped for currency1
function getPoolAndSwapDirection(
PathKey calldata params,
Currency currencyIn
) internal pure returns (PoolKey memory poolKey, bool zeroForOne) {
Currency currencyOut = params.intermediateCurrency;
(Currency currency0, Currency currency1) = currencyIn < currencyOut
? (currencyIn, currencyOut)
: (currencyOut, currencyIn);
zeroForOne = currencyIn == currency0;
poolKey = PoolKey(
currency0, currency1, params.fee, params.tickSpacing, params.hooks
);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { PoolKey } from "./PoolKey.sol";
type PoolId is bytes32;
/// @notice Library for computing the ID of a pool
library PoolIdLibrary {
/// @notice Returns value equal to keccak256(abi.encode(poolKey))
function toId(
PoolKey memory poolKey
) internal pure returns (PoolId poolId) {
assembly ("memory-safe") {
// 0xa0 represents the total size of the poolKey struct (5 slots of
// 32 bytes)
poolId := keccak256(poolKey, 0xa0)
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { SafeCast } from "../libraries/SafeCast.sol";
/// @dev Two `int128` values packed into a single `int256` where the upper 128
/// bits represent the amount0
/// and the lower 128 bits represent the amount1.
type BalanceDelta is int256;
using { add as +, sub as -, eq as ==, neq as != } for BalanceDelta global;
using BalanceDeltaLibrary for BalanceDelta global;
using SafeCast for int256;
function toBalanceDelta(
int128 _amount0,
int128 _amount1
) pure returns (BalanceDelta balanceDelta) {
assembly ("memory-safe") {
balanceDelta :=
or(shl(128, _amount0), and(sub(shl(128, 1), 1), _amount1))
}
}
function add(BalanceDelta a, BalanceDelta b) pure returns (BalanceDelta) {
int256 res0;
int256 res1;
assembly ("memory-safe") {
let a0 := sar(128, a)
let a1 := signextend(15, a)
let b0 := sar(128, b)
let b1 := signextend(15, b)
res0 := add(a0, b0)
res1 := add(a1, b1)
}
return toBalanceDelta(res0.toInt128(), res1.toInt128());
}
function sub(BalanceDelta a, BalanceDelta b) pure returns (BalanceDelta) {
int256 res0;
int256 res1;
assembly ("memory-safe") {
let a0 := sar(128, a)
let a1 := signextend(15, a)
let b0 := sar(128, b)
let b1 := signextend(15, b)
res0 := sub(a0, b0)
res1 := sub(a1, b1)
}
return toBalanceDelta(res0.toInt128(), res1.toInt128());
}
function eq(BalanceDelta a, BalanceDelta b) pure returns (bool) {
return BalanceDelta.unwrap(a) == BalanceDelta.unwrap(b);
}
function neq(BalanceDelta a, BalanceDelta b) pure returns (bool) {
return BalanceDelta.unwrap(a) != BalanceDelta.unwrap(b);
}
/// @notice Library for getting the amount0 and amount1 deltas from the
/// BalanceDelta type
library BalanceDeltaLibrary {
/// @notice A BalanceDelta of 0
BalanceDelta public constant ZERO_DELTA = BalanceDelta.wrap(0);
function amount0(
BalanceDelta balanceDelta
) internal pure returns (int128 _amount0) {
assembly ("memory-safe") {
_amount0 := sar(128, balanceDelta)
}
}
function amount1(
BalanceDelta balanceDelta
) internal pure returns (int128 _amount1) {
assembly ("memory-safe") {
_amount1 := signextend(15, balanceDelta)
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import { Currency } from "./types/Currency.sol";
import { PoolKey } from "./types/PoolKey.sol";
import { PoolId } from "./types/PoolId.sol";
import { BalanceDelta } from "./types/BalanceDelta.sol";
import { IHooks } from "./IHooks.sol";
import { IExtsload } from "./IExtsload.sol";
import { IExttload } from "./IExttload.sol";
/// @notice Interface for the PoolManager
interface IPoolManager is IExtsload, IExttload {
/// @notice Thrown when a currency is not netted out after the contract is
/// unlocked
error CurrencyNotSettled();
/// @notice Thrown when trying to interact with a non-initialized pool
error PoolNotInitialized();
/// @notice Thrown when unlock is called, but the contract is already
/// unlocked
error AlreadyUnlocked();
/// @notice Thrown when a function is called that requires the contract to
/// be unlocked, but it is not
error ManagerLocked();
/// @notice Pools are limited to type(int16).max tickSpacing in #initialize,
/// to prevent overflow
error TickSpacingTooLarge(int24 tickSpacing);
/// @notice Pools must have a positive non-zero tickSpacing passed to
/// #initialize
error TickSpacingTooSmall(int24 tickSpacing);
/// @notice PoolKey must have currencies where address(currency0) <
/// address(currency1)
error CurrenciesOutOfOrderOrEqual(address currency0, address currency1);
/// @notice Thrown when a call to updateDynamicLPFee is made by an address
/// that is not the hook,
/// or on a pool that does not have a dynamic swap fee.
error UnauthorizedDynamicLPFeeUpdate();
/// @notice Thrown when trying to swap amount of 0
error SwapAmountCannotBeZero();
///@notice Thrown when native currency is passed to a non native settlement
error NonzeroNativeValue();
/// @notice Thrown when `clear` is called with an amount that is not exactly
/// equal to the open currency delta.
error MustClearExactPositiveDelta();
/// @notice Emitted when a new pool is initialized
/// @param id The abi encoded hash of the pool key struct for the new pool
/// @param currency0 The first currency of the pool by address sort order
/// @param currency1 The second currency of the pool by address sort order
/// @param fee The fee collected upon every swap in the pool, denominated in
/// hundredths of a bip
/// @param tickSpacing The minimum number of ticks between initialized ticks
/// @param hooks The hooks contract address for the pool, or address(0) if
/// none
/// @param sqrtPriceX96 The price of the pool on initialization
/// @param tick The initial tick of the pool corresponding to the
/// initialized price
event Initialize(
PoolId indexed id,
Currency indexed currency0,
Currency indexed currency1,
uint24 fee,
int24 tickSpacing,
IHooks hooks,
uint160 sqrtPriceX96,
int24 tick
);
/// @notice Emitted when a liquidity position is modified
/// @param id The abi encoded hash of the pool key struct for the pool that
/// was modified
/// @param sender The address that modified the pool
/// @param tickLower The lower tick of the position
/// @param tickUpper The upper tick of the position
/// @param liquidityDelta The amount of liquidity that was added or removed
/// @param salt The extra data to make positions unique
event ModifyLiquidity(
PoolId indexed id,
address indexed sender,
int24 tickLower,
int24 tickUpper,
int256 liquidityDelta,
bytes32 salt
);
/// @notice Emitted for swaps between currency0 and currency1
/// @param id The abi encoded hash of the pool key struct for the pool that
/// was modified
/// @param sender The address that initiated the swap call, and that
/// received the callback
/// @param amount0 The delta of the currency0 balance of the pool
/// @param amount1 The delta of the currency1 balance of the pool
/// @param sqrtPriceX96 The sqrt(price) of the pool after the swap, as a
/// Q64.96
/// @param liquidity The liquidity of the pool after the swap
/// @param tick The log base 1.0001 of the price of the pool after the swap
/// @param fee The swap fee in hundredths of a bip
event Swap(
PoolId indexed id,
address indexed sender,
int128 amount0,
int128 amount1,
uint160 sqrtPriceX96,
uint128 liquidity,
int24 tick,
uint24 fee
);
/// @notice Emitted for donations
/// @param id The abi encoded hash of the pool key struct for the pool that
/// was donated to
/// @param sender The address that initiated the donate call
/// @param amount0 The amount donated in currency0
/// @param amount1 The amount donated in currency1
event Donate(
PoolId indexed id,
address indexed sender,
uint256 amount0,
uint256 amount1
);
/// @notice All interactions on the contract that account deltas require
/// unlocking. A caller that calls `unlock` must implement
/// `IUnlockCallback(msg.sender).unlockCallback(data)`, where they interact
/// with the remaining functions on this contract.
/// @dev The only functions callable without an unlocking are `initialize`
/// and `updateDynamicLPFee`
/// @param data Any data to pass to the callback, via
/// `IUnlockCallback(msg.sender).unlockCallback(data)`
/// @return The data returned by the call to
/// `IUnlockCallback(msg.sender).unlockCallback(data)`
function unlock(
bytes calldata data
) external returns (bytes memory);
/// @notice Initialize the state for a given pool ID
/// @dev A swap fee totaling MAX_SWAP_FEE (100%) makes exact output swaps
/// impossible since the input is entirely consumed by the fee
/// @param key The pool key for the pool to initialize
/// @param sqrtPriceX96 The initial square root price
/// @return tick The initial tick of the pool
function initialize(
PoolKey memory key,
uint160 sqrtPriceX96
) external returns (int24 tick);
struct ModifyLiquidityParams {
// the lower and upper tick of the position
int24 tickLower;
int24 tickUpper;
// how to modify the liquidity
int256 liquidityDelta;
// a value to set if you want unique liquidity positions at the same
// range
bytes32 salt;
}
/// @notice Modify the liquidity for the given pool
/// @dev Poke by calling with a zero liquidityDelta
/// @param key The pool to modify liquidity in
/// @param params The parameters for modifying the liquidity
/// @param hookData The data to pass through to the add/removeLiquidity
/// hooks
/// @return callerDelta The balance delta of the caller of modifyLiquidity.
/// This is the total of both principal, fee deltas, and hook deltas if
/// applicable
/// @return feesAccrued The balance delta of the fees generated in the
/// liquidity range. Returned for informational purposes
/// @dev Note that feesAccrued can be artificially inflated by a malicious
/// actor and integrators should be careful using the value
/// For pools with a single liquidity position, actors can donate to
/// themselves to inflate feeGrowthGlobal (and consequently feesAccrued)
/// atomically donating and collecting fees in the same unlockCallback may
/// make the inflated value more extreme
function modifyLiquidity(
PoolKey memory key,
ModifyLiquidityParams memory params,
bytes calldata hookData
) external returns (BalanceDelta callerDelta, BalanceDelta feesAccrued);
struct SwapParams {
/// Whether to swap token0 for token1 or vice versa
bool zeroForOne;
/// The desired input amount if negative (exactIn), or the desired
/// output amount if positive (exactOut)
int256 amountSpecified;
/// The sqrt price at which, if reached, the swap will stop executing
uint160 sqrtPriceLimitX96;
}
/// @notice Swap against the given pool
/// @param key The pool to swap in
/// @param params The parameters for swapping
/// @param hookData The data to pass through to the swap hooks
/// @return swapDelta The balance delta of the address swapping
/// @dev Swapping on low liquidity pools may cause unexpected swap amounts
/// when liquidity available is less than amountSpecified.
/// Additionally note that if interacting with hooks that have the
/// BEFORE_SWAP_RETURNS_DELTA_FLAG or AFTER_SWAP_RETURNS_DELTA_FLAG
/// the hook may alter the swap input/output. Integrators should perform
/// checks on the returned swapDelta.
function swap(
PoolKey memory key,
SwapParams memory params,
bytes calldata hookData
) external returns (BalanceDelta swapDelta);
/// @notice Donate the given currency amounts to the in-range liquidity
/// providers of a pool
/// @dev Calls to donate can be frontrun adding just-in-time liquidity, with
/// the aim of receiving a portion donated funds.
/// Donors should keep this in mind when designing donation mechanisms.
/// @dev This function donates to in-range LPs at slot0.tick. In certain
/// edge-cases of the swap algorithm, the `sqrtPrice` of
/// a pool can be at the lower boundary of tick `n`, but the `slot0.tick` of
/// the pool is already `n - 1`. In this case a call to
/// `donate` would donate to tick `n - 1` (slot0.tick) not tick `n`
/// (getTickAtSqrtPrice(slot0.sqrtPriceX96)).
/// Read the comments in `Pool.swap()` for more information about this.
/// @param key The key of the pool to donate to
/// @param amount0 The amount of currency0 to donate
/// @param amount1 The amount of currency1 to donate
/// @param hookData The data to pass through to the donate hooks
/// @return BalanceDelta The delta of the caller after the donate
function donate(
PoolKey memory key,
uint256 amount0,
uint256 amount1,
bytes calldata hookData
) external returns (BalanceDelta);
/// @notice Writes the current ERC20 balance of the specified currency to
/// transient storage
/// This is used to checkpoint balances for the manager and derive deltas
/// for the caller.
/// @dev This MUST be called before any ERC20 tokens are sent into the
/// contract, but can be skipped
/// for native tokens because the amount to settle is determined by the sent
/// value.
/// However, if an ERC20 token has been synced and not settled, and the
/// caller instead wants to settle
/// native funds, this function can be called with the native currency to
/// then be able to settle the native currency
function sync(
Currency currency
) external;
/// @notice Called by the user to net out some value owed to the user
/// @dev Will revert if the requested amount is not available, consider
/// using `mint` instead
/// @dev Can also be used as a mechanism for free flash loans
/// @param currency The currency to withdraw from the pool manager
/// @param to The address to withdraw to
/// @param amount The amount of currency to withdraw
function take(Currency currency, address to, uint256 amount) external;
/// @notice Called by the user to pay what is owed
/// @return paid The amount of currency settled
function settle() external payable returns (uint256 paid);
/// @notice Called by the user to pay on behalf of another address
/// @param recipient The address to credit for the payment
/// @return paid The amount of currency settled
function settleFor(
address recipient
) external payable returns (uint256 paid);
/// @notice WARNING - Any currency that is cleared, will be non-retrievable,
/// and locked in the contract permanently.
/// A call to clear will zero out a positive balance WITHOUT a corresponding
/// transfer.
/// @dev This could be used to clear a balance that is considered dust.
/// Additionally, the amount must be the exact positive balance. This is to
/// enforce that the caller is aware of the amount being cleared.
function clear(Currency currency, uint256 amount) external;
/// @notice Called by the user to move value into ERC6909 balance
/// @param to The address to mint the tokens to
/// @param id The currency address to mint to ERC6909s, as a uint256
/// @param amount The amount of currency to mint
/// @dev The id is converted to a uint160 to correspond to a currency
/// address
/// If the upper 12 bytes are not 0, they will be 0-ed out
function mint(address to, uint256 id, uint256 amount) external;
/// @notice Called by the user to move value from ERC6909 balance
/// @param from The address to burn the tokens from
/// @param id The currency address to burn from ERC6909s, as a uint256
/// @param amount The amount of currency to burn
/// @dev The id is converted to a uint160 to correspond to a currency
/// address
/// If the upper 12 bytes are not 0, they will be 0-ed out
function burn(address from, uint256 id, uint256 amount) external;
/// @notice Updates the pools lp fees for the a pool that has enabled
/// dynamic lp fees.
/// @dev A swap fee totaling MAX_SWAP_FEE (100%) makes exact output swaps
/// impossible since the input is entirely consumed by the fee
/// @param key The key of the pool to update dynamic LP fees for
/// @param newDynamicLPFee The new dynamic pool LP fee
function updateDynamicLPFee(
PoolKey memory key,
uint24 newDynamicLPFee
) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// Return type of the beforeSwap hook.
// Upper 128 bits is the delta in specified tokens. Lower 128 bits is delta in
// unspecified tokens (to match the afterSwap hook)
type BeforeSwapDelta is int256;
// Creates a BeforeSwapDelta from specified and unspecified
function toBeforeSwapDelta(
int128 deltaSpecified,
int128 deltaUnspecified
) pure returns (BeforeSwapDelta beforeSwapDelta) {
assembly ("memory-safe") {
beforeSwapDelta :=
or(shl(128, deltaSpecified), and(sub(shl(128, 1), 1), deltaUnspecified))
}
}
/// @notice Library for getting the specified and unspecified deltas from the
/// BeforeSwapDelta type
library BeforeSwapDeltaLibrary {
/// @notice A BeforeSwapDelta of 0
BeforeSwapDelta public constant ZERO_DELTA = BeforeSwapDelta.wrap(0);
/// extracts int128 from the upper 128 bits of the BeforeSwapDelta
/// returned by beforeSwap
function getSpecifiedDelta(
BeforeSwapDelta delta
) internal pure returns (int128 deltaSpecified) {
assembly ("memory-safe") {
deltaSpecified := sar(128, delta)
}
}
/// extracts int128 from the lower 128 bits of the BeforeSwapDelta
/// returned by beforeSwap and afterSwap
function getUnspecifiedDelta(
BeforeSwapDelta delta
) internal pure returns (int128 deltaUnspecified) {
assembly ("memory-safe") {
deltaUnspecified := signextend(15, delta)
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @title Minimal ERC20 interface for Uniswap
/// @notice Contains a subset of the full ERC20 interface that is used in
/// Uniswap V3
interface IERC20Minimal {
/// @notice Returns an account's balance in the token
/// @param account The account for which to look up the number of tokens it
/// has, i.e. its balance
/// @return The number of tokens held by the account
function balanceOf(
address account
) external view returns (uint256);
/// @notice Transfers the amount of token from the `msg.sender` to the
/// recipient
/// @param recipient The account that will receive the amount transferred
/// @param amount The number of tokens to send from the sender to the
/// recipient
/// @return Returns true for a successful transfer, false for an
/// unsuccessful transfer
function transfer(
address recipient,
uint256 amount
) external returns (bool);
/// @notice Returns the current allowance given to a spender by an owner
/// @param owner The account of the token owner
/// @param spender The account of the token spender
/// @return The current allowance granted by `owner` to `spender`
function allowance(
address owner,
address spender
) external view returns (uint256);
/// @notice Sets the allowance of a spender from the `msg.sender` to the
/// value `amount`
/// @param spender The account which will be allowed to spend a given amount
/// of the owners tokens
/// @param amount The amount of tokens allowed to be used by `spender`
/// @return Returns true for a successful approval, false for unsuccessful
function approve(address spender, uint256 amount) external returns (bool);
/// @notice Transfers `amount` tokens from `sender` to `recipient` up to the
/// allowance given to the `msg.sender`
/// @param sender The account from which the transfer will be initiated
/// @param recipient The recipient of the transfer
/// @param amount The amount of the transfer
/// @return Returns true for a successful transfer, false for unsuccessful
function transferFrom(
address sender,
address recipient,
uint256 amount
) external returns (bool);
/// @notice Event emitted when tokens are transferred from one address to
/// another, either via `#transfer` or `#transferFrom`.
/// @param from The account from which the tokens were sent, i.e. the
/// balance decreased
/// @param to The account to which the tokens were sent, i.e. the balance
/// increased
/// @param value The amount of tokens that were transferred
event Transfer(address indexed from, address indexed to, uint256 value);
/// @notice Event emitted when the approval amount for the spender of a
/// given owner's tokens changes.
/// @param owner The account that approved spending of its tokens
/// @param spender The account for which the spending allowance was modified
/// @param value The new allowance from the owner to the spender
event Approval(
address indexed owner, address indexed spender, uint256 value
);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @title Library for reverting with custom errors efficiently
/// @notice Contains functions for reverting with custom errors with different
/// argument types efficiently
/// @dev To use this library, declare `using CustomRevert for bytes4;` and
/// replace `revert CustomError()` with
/// `CustomError.selector.revertWith()`
/// @dev The functions may tamper with the free memory pointer but it is fine
/// since the call context is exited immediately
library CustomRevert {
/// @dev ERC-7751 error for wrapping bubbled up reverts
error WrappedError(
address target, bytes4 selector, bytes reason, bytes details
);
/// @dev Reverts with the selector of a custom error in the scratch space
function revertWith(
bytes4 selector
) internal pure {
assembly ("memory-safe") {
mstore(0, selector)
revert(0, 0x04)
}
}
/// @dev Reverts with a custom error with an address argument in the scratch
/// space
function revertWith(bytes4 selector, address addr) internal pure {
assembly ("memory-safe") {
mstore(0, selector)
mstore(0x04, and(addr, 0xffffffffffffffffffffffffffffffffffffffff))
revert(0, 0x24)
}
}
/// @dev Reverts with a custom error with an int24 argument in the scratch
/// space
function revertWith(bytes4 selector, int24 value) internal pure {
assembly ("memory-safe") {
mstore(0, selector)
mstore(0x04, signextend(2, value))
revert(0, 0x24)
}
}
/// @dev Reverts with a custom error with a uint160 argument in the scratch
/// space
function revertWith(bytes4 selector, uint160 value) internal pure {
assembly ("memory-safe") {
mstore(0, selector)
mstore(0x04, and(value, 0xffffffffffffffffffffffffffffffffffffffff))
revert(0, 0x24)
}
}
/// @dev Reverts with a custom error with two int24 arguments
function revertWith(
bytes4 selector,
int24 value1,
int24 value2
) internal pure {
assembly ("memory-safe") {
let fmp := mload(0x40)
mstore(fmp, selector)
mstore(add(fmp, 0x04), signextend(2, value1))
mstore(add(fmp, 0x24), signextend(2, value2))
revert(fmp, 0x44)
}
}
/// @dev Reverts with a custom error with two uint160 arguments
function revertWith(
bytes4 selector,
uint160 value1,
uint160 value2
) internal pure {
assembly ("memory-safe") {
let fmp := mload(0x40)
mstore(fmp, selector)
mstore(
add(fmp, 0x04),
and(value1, 0xffffffffffffffffffffffffffffffffffffffff)
)
mstore(
add(fmp, 0x24),
and(value2, 0xffffffffffffffffffffffffffffffffffffffff)
)
revert(fmp, 0x44)
}
}
/// @dev Reverts with a custom error with two address arguments
function revertWith(
bytes4 selector,
address value1,
address value2
) internal pure {
assembly ("memory-safe") {
let fmp := mload(0x40)
mstore(fmp, selector)
mstore(
add(fmp, 0x04),
and(value1, 0xffffffffffffffffffffffffffffffffffffffff)
)
mstore(
add(fmp, 0x24),
and(value2, 0xffffffffffffffffffffffffffffffffffffffff)
)
revert(fmp, 0x44)
}
}
/// @notice bubble up the revert message returned by a call and revert with
/// a wrapped ERC-7751 error
/// @dev this method can be vulnerable to revert data bombs
function bubbleUpAndRevertWith(
address revertingContract,
bytes4 revertingFunctionSelector,
bytes4 additionalContext
) internal pure {
bytes4 wrappedErrorSelector = WrappedError.selector;
assembly ("memory-safe") {
// Ensure the size of the revert data is a multiple of 32 bytes
let encodedDataSize := mul(div(add(returndatasize(), 31), 32), 32)
let fmp := mload(0x40)
// Encode wrapped error selector, address, function selector,
// offset, additional context, size, revert reason
mstore(fmp, wrappedErrorSelector)
mstore(
add(fmp, 0x04),
and(
revertingContract,
0xffffffffffffffffffffffffffffffffffffffff
)
)
mstore(
add(fmp, 0x24),
and(
revertingFunctionSelector,
0xffffffff00000000000000000000000000000000000000000000000000000000
)
)
// offset revert reason
mstore(add(fmp, 0x44), 0x80)
// offset additional context
mstore(add(fmp, 0x64), add(0xa0, encodedDataSize))
// size revert reason
mstore(add(fmp, 0x84), returndatasize())
// revert reason
returndatacopy(add(fmp, 0xa4), 0, returndatasize())
// size additional context
mstore(add(fmp, add(0xa4, encodedDataSize)), 0x04)
// additional context
mstore(
add(fmp, add(0xc4, encodedDataSize)),
and(
additionalContext,
0xffffffff00000000000000000000000000000000000000000000000000000000
)
)
revert(fmp, add(0xe4, encodedDataSize))
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { CustomRevert } from "./CustomRevert.sol";
/// @title Safe casting methods
/// @notice Contains methods for safely casting between types
library SafeCast {
using CustomRevert for bytes4;
error SafeCastOverflow();
/// @notice Cast a uint256 to a uint160, revert on overflow
/// @param x The uint256 to be downcasted
/// @return y The downcasted integer, now type uint160
function toUint160(
uint256 x
) internal pure returns (uint160 y) {
y = uint160(x);
if (y != x) SafeCastOverflow.selector.revertWith();
}
/// @notice Cast a uint256 to a uint128, revert on overflow
/// @param x The uint256 to be downcasted
/// @return y The downcasted integer, now type uint128
function toUint128(
uint256 x
) internal pure returns (uint128 y) {
y = uint128(x);
if (x != y) SafeCastOverflow.selector.revertWith();
}
/// @notice Cast a int128 to a uint128, revert on overflow or underflow
/// @param x The int128 to be casted
/// @return y The casted integer, now type uint128
function toUint128(
int128 x
) internal pure returns (uint128 y) {
if (x < 0) SafeCastOverflow.selector.revertWith();
y = uint128(x);
}
/// @notice Cast a int256 to a int128, revert on overflow or underflow
/// @param x The int256 to be downcasted
/// @return y The downcasted integer, now type int128
function toInt128(
int256 x
) internal pure returns (int128 y) {
y = int128(x);
if (y != x) SafeCastOverflow.selector.revertWith();
}
/// @notice Cast a uint256 to a int256, revert on overflow
/// @param x The uint256 to be casted
/// @return y The casted integer, now type int256
function toInt256(
uint256 x
) internal pure returns (int256 y) {
y = int256(x);
if (y < 0) SafeCastOverflow.selector.revertWith();
}
/// @notice Cast a uint256 to a int128, revert on overflow
/// @param x The uint256 to be downcasted
/// @return The downcasted integer, now type int128
function toInt128(
uint256 x
) internal pure returns (int128) {
if (x >= 1 << 127) SafeCastOverflow.selector.revertWith();
return int128(int256(x));
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @notice Interface for functions to access any storage slot in a contract
interface IExtsload {
/// @notice Called by external contracts to access granular pool state
/// @param slot Key of slot to sload
/// @return value The value of the slot as bytes32
function extsload(
bytes32 slot
) external view returns (bytes32 value);
/// @notice Called by external contracts to access granular pool state
/// @param startSlot Key of slot to start sloading from
/// @param nSlots Number of slots to load into return value
/// @return values List of loaded values.
function extsload(
bytes32 startSlot,
uint256 nSlots
) external view returns (bytes32[] memory values);
/// @notice Called by external contracts to access sparse pool state
/// @param slots List of slots to SLOAD from.
/// @return values List of loaded values.
function extsload(
bytes32[] calldata slots
) external view returns (bytes32[] memory values);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
/// @notice Interface for functions to access any transient storage slot in a
/// contract
interface IExttload {
/// @notice Called by external contracts to access transient storage of the
/// contract
/// @param slot Key of slot to tload
/// @return value The value of the slot as bytes32
function exttload(
bytes32 slot
) external view returns (bytes32 value);
/// @notice Called by external contracts to access sparse transient pool
/// state
/// @param slots List of slots to tload
/// @return values List of loaded values
function exttload(
bytes32[] calldata slots
) external view returns (bytes32[] memory values);
}{
"remappings": [
"solmate/=lib/solmate/src/",
"@openzeppelin/=lib/openzeppelin-contracts/",
"@morpho-blue/=lib/morpho-blue/src/",
"ds-test/=lib/solmate/lib/ds-test/src/",
"forge-std/=lib/forge-std/src/",
"morpho-blue/=lib/morpho-blue/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "paris",
"viaIR": false
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"allowlist_","type":"address"},{"internalType":"address","name":"admin_","type":"address"},{"internalType":"address","name":"feeCollector_","type":"address"},{"internalType":"address","name":"wrappedNative_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ApproveFailed","type":"error"},{"inputs":[],"name":"ETHTransferFailed","type":"error"},{"inputs":[],"name":"Expired","type":"error"},{"inputs":[],"name":"FeeTooHigh","type":"error"},{"inputs":[],"name":"InsufficientEthBalance","type":"error"},{"inputs":[{"internalType":"uint256","name":"received","type":"uint256"},{"internalType":"uint256","name":"minRequired","type":"uint256"}],"name":"InsufficientOutputAmount","type":"error"},{"inputs":[],"name":"InvalidAddress","type":"error"},{"inputs":[],"name":"InvalidEthInput","type":"error"},{"inputs":[],"name":"InvalidPool","type":"error"},{"inputs":[],"name":"InvalidSplitLength","type":"error"},{"inputs":[],"name":"InvalidStepsLength","type":"error"},{"inputs":[],"name":"InvalidTokenIn","type":"error"},{"inputs":[],"name":"InvalidWrappedNative","type":"error"},{"inputs":[],"name":"NotAdmin","type":"error"},{"inputs":[{"internalType":"bytes","name":"error","type":"bytes"}],"name":"SwapFailed","type":"error"},{"inputs":[],"name":"TransferFailed","type":"error"},{"inputs":[],"name":"TransferFromFailed","type":"error"},{"inputs":[],"name":"UnknownDexType","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeeBps","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeeBps","type":"uint256"}],"name":"FeeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"tokenIn","type":"address"},{"indexed":true,"internalType":"address","name":"tokenOut","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOut","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"feeAmount","type":"uint256"}],"name":"MultiSwap","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Sweep","type":"event"},{"inputs":[],"name":"BPS_DENOMINATOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_FEE_BPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERMIT2","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"int256","name":"amount0Delta","type":"int256"},{"internalType":"int256","name":"amount1Delta","type":"int256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"algebraSwapCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"allowlist","outputs":[{"internalType":"contract IRouterAllowlist","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeBps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeCollector","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newAdmin","type":"address"}],"name":"setAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeBps","type":"uint256"}],"name":"setFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"enum MultiSwapRouter.DexType","name":"dexType","type":"uint8"},{"internalType":"address","name":"router","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"bytes","name":"dexData","type":"bytes"}],"internalType":"struct MultiSwapRouter.SwapStep[]","name":"steps","type":"tuple[]"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swap","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"enum MultiSwapRouter.DexType","name":"dexType","type":"uint8"},{"internalType":"address","name":"router","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"bytes","name":"dexData","type":"bytes"}],"internalType":"struct MultiSwapRouter.SwapStep[][]","name":"routes","type":"tuple[][]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapSplit","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"sweep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sweepETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"int256","name":"amount0Delta","type":"int256"},{"internalType":"int256","name":"amount1Delta","type":"int256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"uniswapV3SwapCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"wrappedNative","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60e0604052600180553480156200001557600080fd5b5060405162004cd638038062004cd683398101604081905262000038916200012a565b6001600160a01b038416620000605760405163e6c4247b60e01b815260040160405180910390fd5b6001600160a01b038316620000885760405163e6c4247b60e01b815260040160405180910390fd5b6001600160a01b038216620000b05760405163e6c4247b60e01b815260040160405180910390fd5b6001600160a01b038116620000d857604051635e66e44d60e01b815260040160405180910390fd5b6001600160a01b03938416608052600080546001600160a01b03191693851693909317909255821660a0521660c05262000187565b80516001600160a01b03811681146200012557600080fd5b919050565b600080600080608085870312156200014157600080fd5b6200014c856200010d565b93506200015c602086016200010d565b92506200016c604086016200010d565b91506200017c606086016200010d565b905092959194509250565b60805160a05160c051614ab662000220600039600081816102c901528181612f2d01528181612f780152818161308d01526130d8015260008181610255015281816103cf01528181610818015281816111ca01526111fa015260008181610160015281816109e401528181610b670152818161169c0152818161185101528181612bf7015281816137a80152613a240152614ab66000f3fe6080604052600436106100f75760003560e01c8063b2239bd11161008a578063e1a4521811610059578063e1a45218146102a1578063eb6d3a11146102b7578063f851a440146102eb578063fa461e331461030b57600080fd5b8063b2239bd114610230578063c415b95c14610243578063d47f687714610277578063d55be8c61461028c57600080fd5b806369fe0e2d116100c657806369fe0e2d146101ba5780636afdd850146101da578063704b6c02146101fd578063981a9c551461021d57600080fd5b806301681a621461010357806324a9d853146101255780632b47da521461014e5780632c8958f61461019a57600080fd5b366100fe57005b600080fd5b34801561010f57600080fd5b5061012361011e366004613ed2565b61032b565b005b34801561013157600080fd5b5061013b60015481565b6040519081526020015b60405180910390f35b34801561015a57600080fd5b506101827f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610145565b3480156101a657600080fd5b506101236101b5366004613eef565b61043c565b3480156101c657600080fd5b506101236101d5366004613f6f565b610496565b3480156101e657600080fd5b506101826e22d473030f116ddee9f6b43ac78ba381565b34801561020957600080fd5b50610123610218366004613ed2565b610528565b61013b61022b366004613fd4565b6105e3565b61013b61023e366004614047565b610600565b34801561024f57600080fd5b506101827f000000000000000000000000000000000000000000000000000000000000000081565b34801561028357600080fd5b506101236107e1565b34801561029857600080fd5b5061013b606481565b3480156102ad57600080fd5b5061013b61271081565b3480156102c357600080fd5b506101827f000000000000000000000000000000000000000000000000000000000000000081565b3480156102f757600080fd5b50600054610182906001600160a01b031681565b34801561031757600080fd5b50610123610326366004613eef565b610877565b6000546001600160a01b0316331461035657604051637bfa4b9f60e01b815260040160405180910390fd5b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a0823190602401602060405180830381865afa15801561039d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103c191906140de565b90508015610438576103f4827f000000000000000000000000000000000000000000000000000000000000000083610adb565b816001600160a01b03167fab2246061d7b0dd3631d037e3f6da75782ae489eeb9f6af878a4b25df9b07c778260405161042f91815260200190565b60405180910390a25b5050565b6000808061044c848601866140f7565b9350935050925061045e338483610b32565b600080881361046d578661046f565b875b9050306001600160a01b0384160361048c5761048c843383610adb565b5050505050505050565b6000546001600160a01b031633146104c157604051637bfa4b9f60e01b815260040160405180910390fd5b60648111156104e35760405163cd4e616760e01b815260040160405180910390fd5b600180549082905560408051828152602081018490527f528d9479e9f9889a87a3c30c7f7ba537e5e59c4c85a37733b16e57c62df61302910160405180910390a15050565b6000546001600160a01b0316331461055357604051637bfa4b9f60e01b815260040160405180910390fd5b6001600160a01b03811661057a5760405163e6c4247b60e01b815260040160405180910390fd5b600054604080516001600160a01b03928316815291831660208301527f101b8081ff3b56bbf45deb824d86a3b0fd38b7e3dd42421105cf8abe9106db0b910160405180910390a1600080546001600160a01b0319166001600160a01b0392909216919091179055565b60006105f3878787878787610c46565b90505b9695505050505050565b60008142111561062357604051630407b05b60e31b815260040160405180910390fd5b8615806106305750868514155b1561064e57604051634321556b60e11b815260040160405180910390fd5b6000888860008181106106635761066361414a565b90506020028101906106759190614160565b60008181106106865761068661414a565b905060200281019061069891906141aa565b6106a9906060810190604001613ed2565b90506000898960008181106106c0576106c061414a565b90506020028101906106d29190614160565b60018c8c60008181106106e7576106e761414a565b90506020028101906106f99190614160565b6107049291506141e0565b8181106107135761071361414a565b905060200281019061072591906141aa565b610736906080810190606001613ed2565b905060006107488b8b8b8b8787610e86565b9050610754838261105c565b60006107628c8c8c8c6110dd565b9050600061077284838b8b611155565b60408051868152602081018d90529081018390526060810182905291975091506001600160a01b03808616919087169033907f2fb0748023df976464b18b5e5d1c2f8d79da559ffeb202c8a2ce83737a9469069060800160405180910390a45050505050979650505050505050565b6000546001600160a01b0316331461080c57604051637bfa4b9f60e01b815260040160405180910390fd5b4780156108745761083d7f000000000000000000000000000000000000000000000000000000000000000082611250565b6040518181526000907fab2246061d7b0dd3631d037e3f6da75782ae489eeb9f6af878a4b25df9b07c779060200160405180910390a25b50565b60008413158015610889575060008313155b610ad55760003390506000816001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108f691906141f3565b90506000826001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa158015610938573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061095c91906141f3565b90506000836001600160a01b031663c45a01556040518163ffffffff1660e01b8152600401602060405180830381865afa15801561099e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109c291906141f3565b60405163965106d360e01b81526001600160a01b0380831660048301529192507f00000000000000000000000000000000000000000000000000000000000000009091169063965106d39060240160006040518083038186803b158015610a2857600080fd5b505afa158015610a3c573d6000803e3d6000fd5b50505050600080610a4c33611281565b91509150610a5e8386868585336113ee565b610a7a5760405162820f3560e61b815260040160405180910390fd5b6000610a88888a018a613ed2565b90506000808c13610a99578a610a9b565b8b5b90506000808d13610aac5786610aae565b875b9050306001600160a01b03841603610acb57610acb813384610adb565b5050505050505050505b50505050565b600060405163a9059cbb60e01b8152836004820152826024820152602060006044836000895af13d15601f3d1160016000511416171691505080610ad5576040516312171d8360e31b815260040160405180910390fd5b6000806000610b408661147f565b60405163965106d360e01b81526001600160a01b03828116600483015293965091945092507f00000000000000000000000000000000000000000000000000000000000000009091169063965106d39060240160006040518083038186803b158015610bab57600080fd5b505afa158015610bbf573d6000803e3d6000fd5b50505050610bd081848489886115bb565b610bec5760405162820f3560e61b815260040160405180910390fd5b826001600160a01b0316856001600160a01b031614158015610c205750816001600160a01b0316856001600160a01b031614155b15610c3e57604051636b8794e960e11b815260040160405180910390fd5b505050505050565b600081421115610c6957604051630407b05b60e31b815260040160405180910390fd5b6000869003610c8b576040516366d0212f60e01b815260040160405180910390fd5b610cca87876000818110610ca157610ca161414a565b9050602002810190610cb391906141aa565b610cc4906060810190604001613ed2565b8661105c565b846000610cd686611745565b905060005b88811015610d8c576000610cf060018b6141e0565b82148015610d40575060048b8b84818110610d0d57610d0d61414a565b9050602002810190610d1f91906141aa565b610d2d906020810190614226565b600e811115610d3e57610d3e614210565b145b15610d485750815b610d768b8b84818110610d5d57610d5d61414a565b9050602002810190610d6f91906141aa565b85836117a0565b9350508080610d8490614247565b915050610cdb565b5060008989610d9c6001826141e0565b818110610dab57610dab61414a565b9050602002810190610dbd91906141aa565b610dce906080810190606001613ed2565b90506000610dde82858a8a611155565b90955090506001600160a01b0382168b8b600081610dfe57610dfe61414a565b9050602002810190610e1091906141aa565b610e21906060810190604001613ed2565b604080518c8152602081018c9052908101889052606081018490526001600160a01b03919091169033907f2fb0748023df976464b18b5e5d1c2f8d79da559ffeb202c8a2ce83737a9469069060800160405180910390a4505050509695505050505050565b6000805b8481101561105157858582818110610ea457610ea461414a565b9050602002013582610eb69190614260565b9150878782818110610eca57610eca61414a565b9050602002810190610edc9190614160565b9050600003610efe576040516366d0212f60e01b815260040160405180910390fd5b836001600160a01b0316888883818110610f1a57610f1a61414a565b9050602002810190610f2c9190614160565b6000818110610f3d57610f3d61414a565b9050602002810190610f4f91906141aa565b610f60906060810190604001613ed2565b6001600160a01b031614610f87576040516366d0212f60e01b815260040160405180910390fd5b826001600160a01b0316888883818110610fa357610fa361414a565b9050602002810190610fb59190614160565b60018b8b86818110610fc957610fc961414a565b9050602002810190610fdb9190614160565b610fe69291506141e0565b818110610ff557610ff561414a565b905060200281019061100791906141aa565b611018906080810190606001613ed2565b6001600160a01b03161461103f576040516366d0212f60e01b815260040160405180910390fd5b8061104981614247565b915050610e8a565b509695505050505050565b34156110aa573481146110825760405163b4bb7db760e01b815260040160405180910390fd5b6001600160a01b038216156104385760405163b4bb7db760e01b815260040160405180910390fd5b6001600160a01b0382166110d15760405163b4bb7db760e01b815260040160405180910390fd5b61043882333084611cc8565b6000805b8481101561114c5761112e8686838181106110fe576110fe61414a565b90506020028101906111109190614160565b8686858181106111225761112261414a565b90506020020135611d2c565b6111389083614260565b91508061114481614247565b9150506110e1565b50949350505050565b600080612710600154866111699190614273565b611173919061428a565b905061117f81866141e0565b9150838210156111b15760405163d28d3eb560e01b815260048101839052602481018590526044015b60405180910390fd5b801561121f576001600160a01b0386166111f4576111ef7f000000000000000000000000000000000000000000000000000000000000000082611250565b61121f565b61121f867f000000000000000000000000000000000000000000000000000000000000000083610adb565b6001600160a01b03861661123c576112378383611250565b611247565b611247868484610adb565b94509492505050565b600080600080600085875af190508061127c5760405163b12d13eb60e01b815260040160405180910390fd5b505050565b60408051600481526024810182526020810180516001600160e01b031663ddca3f4360e01b17905290516000918291829182916001600160a01b038716916112c8916142d0565b600060405180830381855afa9150503d8060008114611303576040519150601f19603f3d011682016040523d82523d6000602084013e611308565b606091505b509150915081801561131c57506020815110155b15611338578080602001905181019061133591906142f3565b93505b60408051600481526024810182526020810180516001600160e01b03166334324e9f60e21b17905290516001600160a01b03871691611376916142d0565b600060405180830381855afa9150503d80600081146113b1576040519150601f19603f3d011682016040523d82523d6000602084013e6113b6565b606091505b5090925090508180156113cb57506020815110155b156113e757808060200190518101906113e4919061431f565b92505b5050915091565b60008060006113ff89898989611d83565b915091508180156114215750836001600160a01b0316816001600160a01b0316145b15611431576001925050506105f6565b61143d89898988611e8b565b90925090508180156114605750836001600160a01b0316816001600160a01b0316145b15611470576001925050506105f6565b50600098975050505050505050565b600080600080849050806001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114ea91906141f3565b9350806001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa15801561152a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061154e91906141f3565b9250806001600160a01b031663c45a01556040518163ffffffff1660e01b8152600401602060405180830381865afa15801561158e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115b291906141f3565b93959294505050565b60008060006115cb888888611ecd565b91509150811561162857846001600160a01b0316816001600160a01b0316036115f95760019250505061173c565b6001600160a01b0381161580159061161857506001600160a01b038416155b156116285760009250505061173c565b611633888888611fca565b90925090508180156116565750846001600160a01b0316816001600160a01b0316145b156116665760019250505061173c565b6001600160a01b038416156117355760405163457dc7b760e01b81526001600160a01b03898116600483015285811660248301527f0000000000000000000000000000000000000000000000000000000000000000169063457dc7b79060440160006040518083038186803b1580156116de57600080fd5b505afa1580156116f2573d6000803e3d6000fd5b5050505061170288858989612002565b90925090508180156117255750846001600160a01b0316816001600160a01b0316145b156117355760019250505061173c565b6000925050505b95945050505050565b60008160000361175757506000919050565b600060015461271061176991906141e0565b90508060018161177b61271087614273565b6117859190614260565b61178f91906141e0565b611799919061428a565b9392505050565b6000600b6117b16020860186614226565b600e8111156117c2576117c2614210565b141580156117ee575060086117da6020860186614226565b600e8111156117eb576117eb614210565b14155b80156118185750600c6118046020860186614226565b600e81111561181557611815614210565b14155b80156118425750600d61182e6020860186614226565b600e81111561183f5761183f614210565b14155b156118de576001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016637547dbc36118866040870160208801613ed2565b6040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260240160006040518083038186803b1580156118c557600080fd5b505afa1580156118d9573d6000803e3d6000fd5b505050505b600c6118ed6020860186614226565b600e8111156118fe576118fe614210565b1415801561192a5750600d6119166020860186614226565b600e81111561192757611927614210565b14155b8015611954575060046119406020860186614226565b600e81111561195157611951614210565b14155b801561197e5750600861196a6020860186614226565b600e81111561197b5761197b614210565b14155b80156119a85750600b6119946020860186614226565b600e8111156119a5576119a5614210565b14155b156119e65760006119bf6060860160408701613ed2565b6001600160a01b0316036119e65760405163e6c4247b60e01b815260040160405180910390fd5b60006119f56020860186614226565b600e811115611a0657611a06614210565b03611a1c57611a158484612042565b9050611799565b6001611a2b6020860186614226565b600e811115611a3c57611a3c614210565b03611a4b57611a158484612103565b6006611a5a6020860186614226565b600e811115611a6b57611a6b614210565b03611a7a57611a158484612151565b6002611a896020860186614226565b600e811115611a9a57611a9a614210565b03611aa957611a15848461219f565b6007611ab86020860186614226565b600e811115611ac957611ac9614210565b03611ad857611a158484612283565b6003611ae76020860186614226565b600e811115611af857611af8614210565b03611b0757611a158484612381565b6009611b166020860186614226565b600e811115611b2757611b27614210565b03611b3657611a1584846123e4565b600a611b456020860186614226565b600e811115611b5657611b56614210565b03611b6557611a158484612413565b600e611b746020860186614226565b600e811115611b8557611b85614210565b03611b9457611a158484612537565b6005611ba36020860186614226565b600e811115611bb457611bb4614210565b03611bc357611a15848461265c565b6008611bd26020860186614226565b600e811115611be357611be3614210565b03611bf257611a1584846128ac565b600b611c016020860186614226565b600e811115611c1257611c12614210565b03611c2157611a158484612a3f565b6004611c306020860186614226565b600e811115611c4157611c41614210565b03611c5157611a15848484612b89565b600c611c606020860186614226565b600e811115611c7157611c71614210565b03611c8057611a158484612f21565b600d611c8f6020860186614226565b600e811115611ca057611ca0614210565b03611caf57611a158484613081565b6040516347a8190160e01b815260040160405180910390fd5b60006040516323b872dd60e01b81528460048201528360248201528260448201526020600060648360008a5af13d15601f3d1160016000511416171691505080611d2557604051631e4e7d0960e21b815260040160405180910390fd5b5050505050565b8060005b83811015611d7b57611d67858583818110611d4d57611d4d61414a565b9050602002810190611d5f91906141aa565b8360006117a0565b915080611d7381614247565b915050611d30565b509392505050565b6040516001600160a01b038481166024830152838116604483015262ffffff83166064830152600091829182918291891690630b4c774160e11b906084015b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051611e0091906142d0565b600060405180830381855afa9150503d8060008114611e3b576040519150601f19603f3d011682016040523d82523d6000602084013e611e40565b606091505b5091509150811580611e53575060208151105b15611e6657600080935093505050611247565b600181806020019051810190611e7c91906141f3565b93509350505094509492505050565b6040516001600160a01b0384811660248301528381166044830152600283900b60648301526000918291829182918916906328af8d0b60e01b90608401611dc2565b6040516001600160a01b038381166024830152828116604483015260009182918291829188169063d9a641e160e01b906064015b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051611f3f91906142d0565b600060405180830381855afa9150503d8060008114611f7a576040519150601f19603f3d011682016040523d82523d6000602084013e611f7f565b606091505b5091509150811580611f92575060208151105b15611fa557600080935093505050611fc2565b600181806020019051810190611fbb91906141f3565b9350935050505b935093915050565b6040516001600160a01b038381166024830152828116604483015260009182918291829188169063d8ed224160e01b90606401611f01565b6040516001600160a01b038481166024830152838116604483015282811660648301526000918291829182918916906308f68db360e21b90608401611dc2565b604080516002808252606082018352600092839291906020830190803683370190505090506120776060850160408601613ed2565b8160008151811061208a5761208a61414a565b6001600160a01b03909216602092830291909101909101526120b26080850160608601613ed2565b816001815181106120c5576120c561414a565b60200260200101906001600160a01b031690816001600160a01b0316815250506120f984846120f486856131cc565b61321a565b9150505b92915050565b6000806121136080850185614352565b81019061212091906143a4565b90506120f984846120f461213a6060840160408501613ed2565b61214a60808a0160608b01613ed2565b8689613278565b6000806121616080850185614352565b81019061216e91906143a4565b90506120f984846120f46121886060840160408501613ed2565b61219860808a0160608b01613ed2565b8689613306565b6000806121af6080850185614352565b8101906121bc91906143d1565b60408051600180825281830190925291925060009190816020015b60408051606081018252600080825260208083018290529282015282526000199092019101816121d757905050905060405180606001604052808660400160208101906122249190613ed2565b6001600160a01b031681526020016122426080880160608901613ed2565b6001600160a01b03168152602001831515815250816000815181106122695761226961414a565b602002602001018190525061173c85856120f48488613362565b600080806122946080860186614352565b8101906122a191906143ec565b60408051600180825281830190925292945090925060009190816020015b6040805160808101825260008082526020808301829052928201819052606082015282526000199092019101816122bf57905050905060405180608001604052808760400160208101906123139190613ed2565b6001600160a01b031681526020016123316080890160608a01613ed2565b6001600160a01b031681526020018415158152602001836001600160a01b0316815250816000815181106123675761236761414a565b60200260200101819052506105f686866120f484896133c0565b600060606123926080850185614352565b90506020036123cc5760006123aa6080860186614352565b8101906123b79190613ed2565b90506123c485828661340e565b9150506123d9565b6123d684846134bc565b90505b6120f984848361321a565b6000806123f46080850185614352565b810190612401919061442e565b90506120f984846120f4878588613529565b600080806124246080860186614352565b810190612431919061444b565b60408051600180825281830190925292945090925060009190816020015b6040805160c08101825260008082526020808301829052928201819052606082018190526080820181905260a0820152825260001990920191018161244f5790505090506040518060c00160405280846001600160a01b031681526020018760400160208101906124c09190613ed2565b6001600160a01b031681526020016124de6080890160608a01613ed2565b6001600160a01b031681526020018315158152602001600015158152602001306001600160a01b03168152508160008151811061251d5761251d61414a565b60200260200101819052506105f686866120f484896135a1565b6040805160028082526060820183526000928392919060208301908036833701905050905061256c6060850160408601613ed2565b8160008151811061257f5761257f61414a565b6001600160a01b03909216602092830291909101909101526125a76080850160608601613ed2565b816001815181106125ba576125ba61414a565b6001600160a01b039092166020928302919091018201526000906125e16080870187614352565b905010156125f057600061260a565b6125fd6080860186614352565b81019061260a9190613ed2565b905061173c85858660008630874260405160240161262d969594939291906144c4565b60408051601f198184030181529190526020810180516001600160e01b031663561c49dd60e11b17905261321a565b6000808061266d6080860186614352565b81019061267a9190614508565b909250905060006126996126946080880160608901613ed2565b6135c5565b9050606060008415612712575060006126b86060890160408a01613ed2565b846126c960808b0160608c01613ed2565b6040516bffffffffffffffffffffffff19606094851b8116602083015260e89390931b6034820152921b166037820152604b016040516020818303038152906040529150612798565b5060086127256060890160408a01613ed2565b8460020b60011461273757600061273d565b600160f81b5b61274d60808b0160608c01613ed2565b6040516bffffffffffffffffffffffff19606094851b811660208301526001600160f81b03199093166034820152921b16603582015260490160405160208183030381529060405291505b6040516001600160f81b031960f883901b166020820152606090819060210160408051808303601f1901815260018084528383019092529350816020015b60608152602001906001900390816127d6579050509050308960008660008060405160200161280a96959493929190614560565b6040516020818303038152906040528160008151811061282c5761282c61414a565b602090810291909101015261286061284a60608c0160408d01613ed2565b61285a60408d0160208e01613ed2565b8b610adb565b61288461287360408c0160208d01613ed2565b61287d8484613644565b600061368d565b5061289e61289860808c0160608d01613ed2565b86613715565b9a9950505050505050505050565b6000806128b88461372b565b9050600060406128cb6080870187614352565b9050106128f0576128df6080860186614352565b8101906128ec91906145aa565b9150505b600061291c836129066060890160408a01613ed2565b61291660808a0160608b01613ed2565b85613772565b905060006129306060880160408901613ed2565b604080516001600160a01b039283166020820152908101889052306060820152908416608082015260a0016040516020818303038152906040529050600080856001600160a01b031663128acb0830868b886129aa576129a5600173fffd8963efd1fc6a506488495d951d5263988d266145c8565b6129ba565b6129ba6401000276a360016145ef565b886040518663ffffffff1660e01b81526004016129db95949392919061460f565b60408051808303816000875af11580156129f9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a1d919061464a565b91509150600084612a3657612a318361466e565b61289e565b61289e8261466e565b600080612a4b8461372b565b90506001600160a01b038116612a745760405163e6c4247b60e01b815260040160405180910390fd5b6000612a8f82612a8a6060880160408901613ed2565b6138cc565b9050600080836001600160a01b031663128acb0830858987612acf57612aca600173fffd8963efd1fc6a506488495d951d5263988d266145c8565b612adf565b612adf6401000276a360016145ef565b60408051306020820152016040516020818303038152906040526040518663ffffffff1660e01b8152600401612b1995949392919061460f565b60408051808303816000875af1158015612b37573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b5b919061464a565b91509150600083612b7457612b6f8361466e565b612b7d565b612b7d8261466e565b98975050505050505050565b600080612b9f6126946080870160608801613ed2565b90506000612bb06080870187614352565b810190612bbd919061468a565b60808101519091506001600160a01b031615612c545760808101516040516329e899d960e01b81526001600160a01b0391821660048201527f0000000000000000000000000000000000000000000000000000000000000000909116906329e899d99060240160006040518083038186803b158015612c3b57600080fd5b505afa158015612c4f573d6000803e3d6000fd5b505050505b6000612c666060880160408901613ed2565b6001600160a01b031614612d4a57612c9d612c876060880160408901613ed2565b6e22d473030f116ddee9f6b43ac78ba387613b0a565b6e22d473030f116ddee9f6b43ac78ba36387517c45612cc26060890160408a01613ed2565b612cd260408a0160208b01613ed2565b6040516001600160e01b031960e085901b1681526001600160a01b0392831660048201529082166024820152908816604482015265ffffffffffff42166064820152608401600060405180830381600087803b158015612d3157600080fd5b505af1158015612d45573d6000803e3d6000fd5b505050505b6000612d5887838888613b21565b60408051600180825281830190925291925060009190816020015b6060815260200190600190039081612d735790505090508181600081518110612d9e57612d9e61414a565b6020026020010181905250612e15886020016020810190612dbf9190613ed2565b604051600160fc1b6020820152612de89060210160405160208183030381529060405284613644565b6000612dfa60608d0160408e01613ed2565b6001600160a01b031614612e0f57600061368d565b8961368d565b5060009150612e2c90506060880160408901613ed2565b6001600160a01b031614612f0857612e64612e4d6060880160408901613ed2565b6e22d473030f116ddee9f6b43ac78ba36000613b0a565b6e22d473030f116ddee9f6b43ac78ba36387517c45612e896060890160408a01613ed2565b612e9960408a0160208b01613ed2565b6040516001600160e01b031960e085901b1681526001600160a01b039283166004820152911660248201526000604482018190526064820152608401600060405180830381600087803b158015612eef57600080fd5b505af1158015612f03573d6000803e3d6000fd5b505050505b6105f6612f1b6080880160608901613ed2565b83613715565b60006001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016612f5d6040850160208601613ed2565b6001600160a01b0316141580612fb457506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016612fa86080850160608601613ed2565b6001600160a01b031614155b80612fd857506000612fcc6060850160408601613ed2565b6001600160a01b031614155b15612ff657604051635e66e44d60e01b815260040160405180910390fd5b8147101561301757604051635b6b73eb60e11b815260040160405180910390fd5b6130276040840160208501613ed2565b6001600160a01b031663d0e30db0836040518263ffffffff1660e01b81526004016000604051808303818588803b15801561306157600080fd5b505af1158015613075573d6000803e3d6000fd5b50949695505050505050565b60006001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166130bd6040850160208601613ed2565b6001600160a01b031614158061311457506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166131086060850160408601613ed2565b6001600160a01b031614155b806131385750600061312c6080850160608601613ed2565b6001600160a01b031614155b1561315657604051635e66e44d60e01b815260040160405180910390fd5b6131666040840160208501613ed2565b6001600160a01b0316632e1a7d4d836040518263ffffffff1660e01b815260040161319391815260200190565b600060405180830381600087803b1580156131ad57600080fd5b505af11580156131c1573d6000803e3d6000fd5b509395945050505050565b60608260008330426040516024016131e895949392919061472a565b60408051601f198184030181529190526020810180516001600160e01b03166338ed173960e01b179052905092915050565b6000806132306126946080870160608801613ed2565b905061325e6132456060870160408801613ed2565b6132556040880160208901613ed2565b86866000613e29565b5061173c6132726080870160608801613ed2565b82613715565b6040516001600160a01b0380861660248301528416604482015262ffffff8316606482015230608482015260a48101829052600060c4820181905260e48201526060906304e45aaf60e01b90610104015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915290505b949350505050565b6040516001600160a01b0380861660248301528416604482015262ffffff831660648201523060848201524260a482015260c48101829052600060e4820181905261010482015260609063414bf38960e01b90610124016132c9565b606063f41766d860e01b826000853042604051602401613386959493929190614766565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152905092915050565b60608160008430426040516024016133dc9594939291906147fe565b60408051601f198184030181529190526020810180516001600160e01b031663cac88ea960e01b179052905092915050565b6060630b3ce3c960e11b61342785830160408701613ed2565b6134376080870160608801613ed2565b6040516001600160a01b039283166024820152908216604482015290851660648201523060848201524260a482015260c48101849052600060e48201819052610104820152610124015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915290509392505050565b606063178ca23160e31b6134d584830160408601613ed2565b6134e56080860160608701613ed2565b6040516001600160a01b0392831660248201529116604482015230606482015242608482015260a48101849052600060c4820181905260e482015261010401613386565b60606350131c1f60e11b61354285830160408701613ed2565b6135526080870160608801613ed2565b6040516001600160a01b03928316602482015291166044820152600285900b60648201523060848201524260a482015260c48101849052600060e4820181905261010482015261012401613481565b606063204b5c0a60e01b826000853042604051602401613386959493929190614874565b60006001600160a01b0382166135dc575047919050565b6040516370a0823160e01b81523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa158015613620573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120fd91906140de565b606082824260405160240161365b93929190614975565b60408051601f198184030181529190526020810180516001600160e01b0316630d64d59360e21b179052905092915050565b6060600080856001600160a01b031684866040516136ab91906142d0565b60006040518083038185875af1925050503d80600081146136e8576040519150601f19603f3d011682016040523d82523d6000602084013e6136ed565b606091505b50915091508161173c5780604051600162605a6b60e01b031981526004016111a891906149ab565b600081613721846135c5565b61179991906141e0565b6000602061373c6080840184614352565b90501061375d576137506080830183614352565b8101906120fd9190613ed2565b6120fd6040830160208401613ed2565b919050565b6000806000806137818861147f565b60405163965106d360e01b81526001600160a01b03828116600483015293965091945092507f00000000000000000000000000000000000000000000000000000000000000009091169063965106d39060240160006040518083038186803b1580156137ec57600080fd5b505afa158015613800573d6000803e3d6000fd5b505050506138118184848b896115bb565b61382d5760405162820f3560e61b815260040160405180910390fd5b826001600160a01b0316876001600160a01b031614801561385f5750816001600160a01b0316866001600160a01b0316145b1561387057600193505050506132fe565b816001600160a01b0316876001600160a01b03161480156138a25750826001600160a01b0316866001600160a01b0316145b156138b357600093505050506132fe565b604051636b8794e960e11b815260040160405180910390fd5b6000808390506000816001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015613912573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061393691906141f3565b90506000826001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa158015613978573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061399c91906141f3565b90506000836001600160a01b031663c45a01556040518163ffffffff1660e01b8152600401602060405180830381865afa1580156139de573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a0291906141f3565b60405163965106d360e01b81526001600160a01b0380831660048301529192507f00000000000000000000000000000000000000000000000000000000000000009091169063965106d39060240160006040518083038186803b158015613a6857600080fd5b505afa158015613a7c573d6000803e3d6000fd5b50505050600080613a8c89611281565b91509150613a9e83868685858e6113ee565b613aba5760405162820f3560e61b815260040160405180910390fd5b846001600160a01b0316886001600160a01b031603613ae257600196505050505050506120fd565b836001600160a01b0316886001600160a01b0316036138b357600096505050505050506120fd565b613b1683836000613e4f565b61127c838383613e4f565b6060600080613b3560808801888501613ed2565b6001600160a01b0316613b4e6060890160408a01613ed2565b6001600160a01b031610613b8157613b6c6080880160608901613ed2565b613b7c6060890160408a01613ed2565b613ba1565b613b916060880160408901613ed2565b613ba16080890160608a01613ed2565b909250905060006001600160a01b038316613bc260608a0160408b01613ed2565b60408051600360f91b6020820152600360fa1b6021820152600f60f81b602282015281516003818303810182526023830181815260a384019094526001600160a01b0394909416949094149450600092906043015b6060815260200190600190039081613c1757905050905060006040518060a001604052806040518060a00160405280896001600160a01b03168152602001886001600160a01b031681526020018d6040015162ffffff1681526020018d6060015160020b81526020018d608001516001600160a01b0316815250815260200185151581526020018a6001600160801b0316815260200160006001600160801b03168152602001600067ffffffffffffffff811115613cd757613cd761433c565b6040519080825280601f01601f191660200182016040528015613d01576020820181803683370190505b50815250905080604051602001613d1891906149be565b60405160208183030381529060405282600081518110613d3a57613d3a61414a565b6020908102919091010152613d5560608c0160408d01613ed2565b604080516001600160a01b03909216602083015281018a905260600160405160208183030381529060405282600181518110613d9357613d9361414a565b6020908102919091010152613dae60808c0160608d01613ed2565b604080516001600160a01b039092166020830152810189905260600160405160208183030381529060405282600281518110613dec57613dec61414a565b60200260200101819052508282604051602001613e0a929190614a5b565b6040516020818303038152906040529650505050505050949350505050565b6060613e36868686613b0a565b6000613e4386858561368d565b90506105f68787613ea6565b600060405163095ea7b360e01b8152836004820152826024820152602060006044836000895af13d15601f3d1160016000511416171691505080610ad557604051633e3f8f7360e01b815260040160405180910390fd5b61043882826000613e4f565b6001600160a01b038116811461087457600080fd5b803561376d81613eb2565b600060208284031215613ee457600080fd5b813561179981613eb2565b60008060008060608587031215613f0557600080fd5b8435935060208501359250604085013567ffffffffffffffff80821115613f2b57600080fd5b818701915087601f830112613f3f57600080fd5b813581811115613f4e57600080fd5b886020828501011115613f6057600080fd5b95989497505060200194505050565b600060208284031215613f8157600080fd5b5035919050565b60008083601f840112613f9a57600080fd5b50813567ffffffffffffffff811115613fb257600080fd5b6020830191508360208260051b8501011115613fcd57600080fd5b9250929050565b60008060008060008060a08789031215613fed57600080fd5b863567ffffffffffffffff81111561400457600080fd5b61401089828a01613f88565b9097509550506020870135935060408701359250606087013561403281613eb2565b80925050608087013590509295509295509295565b600080600080600080600060a0888a03121561406257600080fd5b873567ffffffffffffffff8082111561407a57600080fd5b6140868b838c01613f88565b909950975060208a013591508082111561409f57600080fd5b506140ac8a828b01613f88565b9096509450506040880135925060608801356140c781613eb2565b809250506080880135905092959891949750929550565b6000602082840312156140f057600080fd5b5051919050565b6000806000806080858703121561410d57600080fd5b843561411881613eb2565b935060208501359250604085013561412f81613eb2565b9150606085013561413f81613eb2565b939692955090935050565b634e487b7160e01b600052603260045260246000fd5b6000808335601e1984360301811261417757600080fd5b83018035915067ffffffffffffffff82111561419257600080fd5b6020019150600581901b3603821315613fcd57600080fd5b60008235609e198336030181126141c057600080fd5b9190910192915050565b634e487b7160e01b600052601160045260246000fd5b818103818111156120fd576120fd6141ca565b60006020828403121561420557600080fd5b815161179981613eb2565b634e487b7160e01b600052602160045260246000fd5b60006020828403121561423857600080fd5b8135600f811061179957600080fd5b600060018201614259576142596141ca565b5060010190565b808201808211156120fd576120fd6141ca565b80820281158282048414176120fd576120fd6141ca565b6000826142a757634e487b7160e01b600052601260045260246000fd5b500490565b60005b838110156142c75781810151838201526020016142af565b50506000910152565b600082516141c08184602087016142ac565b62ffffff8116811461087457600080fd5b60006020828403121561430557600080fd5b8151611799816142e2565b8060020b811461087457600080fd5b60006020828403121561433157600080fd5b815161179981614310565b634e487b7160e01b600052604160045260246000fd5b6000808335601e1984360301811261436957600080fd5b83018035915067ffffffffffffffff82111561438457600080fd5b602001915036819003821315613fcd57600080fd5b803561376d816142e2565b6000602082840312156143b657600080fd5b8135611799816142e2565b8035801515811461376d57600080fd5b6000602082840312156143e357600080fd5b611799826143c1565b600080604083850312156143ff57600080fd5b614408836143c1565b9150602083013561441881613eb2565b809150509250929050565b803561376d81614310565b60006020828403121561444057600080fd5b813561179981614310565b6000806040838503121561445e57600080fd5b823561446981613eb2565b9150614477602084016143c1565b90509250929050565b600081518084526020808501945080840160005b838110156144b95781516001600160a01b031687529582019590820190600101614494565b509495945050505050565b86815285602082015260c0604082015260006144e360c0830187614480565b6001600160a01b03958616606084015293909416608082015260a00152949350505050565b6000806040838503121561451b57600080fd5b614524836143c1565b9150602083013561441881614310565b6000815180845261454c8160208601602086016142ac565b601f01601f19169290920160200192915050565b60018060a01b038716815285602082015260ff8516604082015260c06060820152600061459060c0830186614534565b93151560808301525090151560a090910152949350505050565b600080604083850312156145bd57600080fd5b823561440881613eb2565b6001600160a01b038281168282160390808211156145e8576145e86141ca565b5092915050565b6001600160a01b038181168382160190808211156145e8576145e86141ca565b6001600160a01b0386811682528515156020830152604082018590528316606082015260a0608082018190526000906105f390830184614534565b6000806040838503121561465d57600080fd5b505080516020909101519092909150565b6000600160ff1b8201614683576146836141ca565b5060000390565b600060a0828403121561469c57600080fd5b60405160a0810181811067ffffffffffffffff821117156146cd57634e487b7160e01b600052604160045260246000fd5b60405282356146db81613eb2565b815260208301356146eb81613eb2565b60208201526146fc60408401614399565b604082015261470d60608401614423565b606082015261471e60808401613ec7565b60808201529392505050565b85815284602082015260a06040820152600061474960a0830186614480565b6001600160a01b0394909416606083015250608001529392505050565b600060a08201878352602060ff881681850152604060a08186015282885180855260c087019150838a01945060005b818110156147d257855180516001600160a01b03908116855286820151168685015284015115158484015294840194606090920191600101614795565b50506001600160a01b038816606087015293506147ee92505050565b8260808301529695505050505050565b600060a0820187835260208781850152604060a08186015282885180855260c087019150838a01945060005b818110156147d257855180516001600160a01b039081168552868201518116878601528582015115158686015260609182015116908401529484019460809092019160010161482a565b600060a0808301888452602060ff8916818601526040838187015282895180855260c094508488019150838b0160005b8281101561490257815180516001600160a01b039081168652878201518116888701528682015181168787015260608083015115159087015260808083015115159087015290890151168885015292860192908501906001016148a4565b5050506001600160a01b038916606088015294506147ee9350505050565b600081518084526020808501808196508360051b8101915082860160005b85811015614968578284038952614956848351614534565b9885019893509084019060010161493e565b5091979650505050505050565b6060815260006149886060830186614534565b828103602084015261499a8186614920565b915050826040830152949350505050565b6020815260006117996020830184614534565b602081526000825160018060a01b0380825116602085015280602083015116604085015262ffffff6040830151166060850152606082015160020b60808501528060808301511660a085015250506020830151614a1f60c084018215159052565b5060408301516001600160801b0390811660e08401526060840151166101008301526080830151610120808401526120f9610140840182614534565b604081526000614a6e6040830185614534565b828103602084015261173c818561492056fea2646970667358221220b10ffdc6ec1523b2a1d5a55d847ca5ba058683697ebe0e015e80331ea312ab5564736f6c634300081300330000000000000000000000003b1ed0694345648a19882f9ed1374a5fb1296bdf000000000000000000000000bde48624f9e1dd4107df324d1ba3c07004640206000000000000000000000000d4627ecb405b64448ee6b07dcf860bf55590c83d000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Deployed Bytecode
0x6080604052600436106100f75760003560e01c8063b2239bd11161008a578063e1a4521811610059578063e1a45218146102a1578063eb6d3a11146102b7578063f851a440146102eb578063fa461e331461030b57600080fd5b8063b2239bd114610230578063c415b95c14610243578063d47f687714610277578063d55be8c61461028c57600080fd5b806369fe0e2d116100c657806369fe0e2d146101ba5780636afdd850146101da578063704b6c02146101fd578063981a9c551461021d57600080fd5b806301681a621461010357806324a9d853146101255780632b47da521461014e5780632c8958f61461019a57600080fd5b366100fe57005b600080fd5b34801561010f57600080fd5b5061012361011e366004613ed2565b61032b565b005b34801561013157600080fd5b5061013b60015481565b6040519081526020015b60405180910390f35b34801561015a57600080fd5b506101827f0000000000000000000000003b1ed0694345648a19882f9ed1374a5fb1296bdf81565b6040516001600160a01b039091168152602001610145565b3480156101a657600080fd5b506101236101b5366004613eef565b61043c565b3480156101c657600080fd5b506101236101d5366004613f6f565b610496565b3480156101e657600080fd5b506101826e22d473030f116ddee9f6b43ac78ba381565b34801561020957600080fd5b50610123610218366004613ed2565b610528565b61013b61022b366004613fd4565b6105e3565b61013b61023e366004614047565b610600565b34801561024f57600080fd5b506101827f000000000000000000000000d4627ecb405b64448ee6b07dcf860bf55590c83d81565b34801561028357600080fd5b506101236107e1565b34801561029857600080fd5b5061013b606481565b3480156102ad57600080fd5b5061013b61271081565b3480156102c357600080fd5b506101827f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b3480156102f757600080fd5b50600054610182906001600160a01b031681565b34801561031757600080fd5b50610123610326366004613eef565b610877565b6000546001600160a01b0316331461035657604051637bfa4b9f60e01b815260040160405180910390fd5b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a0823190602401602060405180830381865afa15801561039d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103c191906140de565b90508015610438576103f4827f000000000000000000000000d4627ecb405b64448ee6b07dcf860bf55590c83d83610adb565b816001600160a01b03167fab2246061d7b0dd3631d037e3f6da75782ae489eeb9f6af878a4b25df9b07c778260405161042f91815260200190565b60405180910390a25b5050565b6000808061044c848601866140f7565b9350935050925061045e338483610b32565b600080881361046d578661046f565b875b9050306001600160a01b0384160361048c5761048c843383610adb565b5050505050505050565b6000546001600160a01b031633146104c157604051637bfa4b9f60e01b815260040160405180910390fd5b60648111156104e35760405163cd4e616760e01b815260040160405180910390fd5b600180549082905560408051828152602081018490527f528d9479e9f9889a87a3c30c7f7ba537e5e59c4c85a37733b16e57c62df61302910160405180910390a15050565b6000546001600160a01b0316331461055357604051637bfa4b9f60e01b815260040160405180910390fd5b6001600160a01b03811661057a5760405163e6c4247b60e01b815260040160405180910390fd5b600054604080516001600160a01b03928316815291831660208301527f101b8081ff3b56bbf45deb824d86a3b0fd38b7e3dd42421105cf8abe9106db0b910160405180910390a1600080546001600160a01b0319166001600160a01b0392909216919091179055565b60006105f3878787878787610c46565b90505b9695505050505050565b60008142111561062357604051630407b05b60e31b815260040160405180910390fd5b8615806106305750868514155b1561064e57604051634321556b60e11b815260040160405180910390fd5b6000888860008181106106635761066361414a565b90506020028101906106759190614160565b60008181106106865761068661414a565b905060200281019061069891906141aa565b6106a9906060810190604001613ed2565b90506000898960008181106106c0576106c061414a565b90506020028101906106d29190614160565b60018c8c60008181106106e7576106e761414a565b90506020028101906106f99190614160565b6107049291506141e0565b8181106107135761071361414a565b905060200281019061072591906141aa565b610736906080810190606001613ed2565b905060006107488b8b8b8b8787610e86565b9050610754838261105c565b60006107628c8c8c8c6110dd565b9050600061077284838b8b611155565b60408051868152602081018d90529081018390526060810182905291975091506001600160a01b03808616919087169033907f2fb0748023df976464b18b5e5d1c2f8d79da559ffeb202c8a2ce83737a9469069060800160405180910390a45050505050979650505050505050565b6000546001600160a01b0316331461080c57604051637bfa4b9f60e01b815260040160405180910390fd5b4780156108745761083d7f000000000000000000000000d4627ecb405b64448ee6b07dcf860bf55590c83d82611250565b6040518181526000907fab2246061d7b0dd3631d037e3f6da75782ae489eeb9f6af878a4b25df9b07c779060200160405180910390a25b50565b60008413158015610889575060008313155b610ad55760003390506000816001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108f691906141f3565b90506000826001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa158015610938573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061095c91906141f3565b90506000836001600160a01b031663c45a01556040518163ffffffff1660e01b8152600401602060405180830381865afa15801561099e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109c291906141f3565b60405163965106d360e01b81526001600160a01b0380831660048301529192507f0000000000000000000000003b1ed0694345648a19882f9ed1374a5fb1296bdf9091169063965106d39060240160006040518083038186803b158015610a2857600080fd5b505afa158015610a3c573d6000803e3d6000fd5b50505050600080610a4c33611281565b91509150610a5e8386868585336113ee565b610a7a5760405162820f3560e61b815260040160405180910390fd5b6000610a88888a018a613ed2565b90506000808c13610a99578a610a9b565b8b5b90506000808d13610aac5786610aae565b875b9050306001600160a01b03841603610acb57610acb813384610adb565b5050505050505050505b50505050565b600060405163a9059cbb60e01b8152836004820152826024820152602060006044836000895af13d15601f3d1160016000511416171691505080610ad5576040516312171d8360e31b815260040160405180910390fd5b6000806000610b408661147f565b60405163965106d360e01b81526001600160a01b03828116600483015293965091945092507f0000000000000000000000003b1ed0694345648a19882f9ed1374a5fb1296bdf9091169063965106d39060240160006040518083038186803b158015610bab57600080fd5b505afa158015610bbf573d6000803e3d6000fd5b50505050610bd081848489886115bb565b610bec5760405162820f3560e61b815260040160405180910390fd5b826001600160a01b0316856001600160a01b031614158015610c205750816001600160a01b0316856001600160a01b031614155b15610c3e57604051636b8794e960e11b815260040160405180910390fd5b505050505050565b600081421115610c6957604051630407b05b60e31b815260040160405180910390fd5b6000869003610c8b576040516366d0212f60e01b815260040160405180910390fd5b610cca87876000818110610ca157610ca161414a565b9050602002810190610cb391906141aa565b610cc4906060810190604001613ed2565b8661105c565b846000610cd686611745565b905060005b88811015610d8c576000610cf060018b6141e0565b82148015610d40575060048b8b84818110610d0d57610d0d61414a565b9050602002810190610d1f91906141aa565b610d2d906020810190614226565b600e811115610d3e57610d3e614210565b145b15610d485750815b610d768b8b84818110610d5d57610d5d61414a565b9050602002810190610d6f91906141aa565b85836117a0565b9350508080610d8490614247565b915050610cdb565b5060008989610d9c6001826141e0565b818110610dab57610dab61414a565b9050602002810190610dbd91906141aa565b610dce906080810190606001613ed2565b90506000610dde82858a8a611155565b90955090506001600160a01b0382168b8b600081610dfe57610dfe61414a565b9050602002810190610e1091906141aa565b610e21906060810190604001613ed2565b604080518c8152602081018c9052908101889052606081018490526001600160a01b03919091169033907f2fb0748023df976464b18b5e5d1c2f8d79da559ffeb202c8a2ce83737a9469069060800160405180910390a4505050509695505050505050565b6000805b8481101561105157858582818110610ea457610ea461414a565b9050602002013582610eb69190614260565b9150878782818110610eca57610eca61414a565b9050602002810190610edc9190614160565b9050600003610efe576040516366d0212f60e01b815260040160405180910390fd5b836001600160a01b0316888883818110610f1a57610f1a61414a565b9050602002810190610f2c9190614160565b6000818110610f3d57610f3d61414a565b9050602002810190610f4f91906141aa565b610f60906060810190604001613ed2565b6001600160a01b031614610f87576040516366d0212f60e01b815260040160405180910390fd5b826001600160a01b0316888883818110610fa357610fa361414a565b9050602002810190610fb59190614160565b60018b8b86818110610fc957610fc961414a565b9050602002810190610fdb9190614160565b610fe69291506141e0565b818110610ff557610ff561414a565b905060200281019061100791906141aa565b611018906080810190606001613ed2565b6001600160a01b03161461103f576040516366d0212f60e01b815260040160405180910390fd5b8061104981614247565b915050610e8a565b509695505050505050565b34156110aa573481146110825760405163b4bb7db760e01b815260040160405180910390fd5b6001600160a01b038216156104385760405163b4bb7db760e01b815260040160405180910390fd5b6001600160a01b0382166110d15760405163b4bb7db760e01b815260040160405180910390fd5b61043882333084611cc8565b6000805b8481101561114c5761112e8686838181106110fe576110fe61414a565b90506020028101906111109190614160565b8686858181106111225761112261414a565b90506020020135611d2c565b6111389083614260565b91508061114481614247565b9150506110e1565b50949350505050565b600080612710600154866111699190614273565b611173919061428a565b905061117f81866141e0565b9150838210156111b15760405163d28d3eb560e01b815260048101839052602481018590526044015b60405180910390fd5b801561121f576001600160a01b0386166111f4576111ef7f000000000000000000000000d4627ecb405b64448ee6b07dcf860bf55590c83d82611250565b61121f565b61121f867f000000000000000000000000d4627ecb405b64448ee6b07dcf860bf55590c83d83610adb565b6001600160a01b03861661123c576112378383611250565b611247565b611247868484610adb565b94509492505050565b600080600080600085875af190508061127c5760405163b12d13eb60e01b815260040160405180910390fd5b505050565b60408051600481526024810182526020810180516001600160e01b031663ddca3f4360e01b17905290516000918291829182916001600160a01b038716916112c8916142d0565b600060405180830381855afa9150503d8060008114611303576040519150601f19603f3d011682016040523d82523d6000602084013e611308565b606091505b509150915081801561131c57506020815110155b15611338578080602001905181019061133591906142f3565b93505b60408051600481526024810182526020810180516001600160e01b03166334324e9f60e21b17905290516001600160a01b03871691611376916142d0565b600060405180830381855afa9150503d80600081146113b1576040519150601f19603f3d011682016040523d82523d6000602084013e6113b6565b606091505b5090925090508180156113cb57506020815110155b156113e757808060200190518101906113e4919061431f565b92505b5050915091565b60008060006113ff89898989611d83565b915091508180156114215750836001600160a01b0316816001600160a01b0316145b15611431576001925050506105f6565b61143d89898988611e8b565b90925090508180156114605750836001600160a01b0316816001600160a01b0316145b15611470576001925050506105f6565b50600098975050505050505050565b600080600080849050806001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114ea91906141f3565b9350806001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa15801561152a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061154e91906141f3565b9250806001600160a01b031663c45a01556040518163ffffffff1660e01b8152600401602060405180830381865afa15801561158e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115b291906141f3565b93959294505050565b60008060006115cb888888611ecd565b91509150811561162857846001600160a01b0316816001600160a01b0316036115f95760019250505061173c565b6001600160a01b0381161580159061161857506001600160a01b038416155b156116285760009250505061173c565b611633888888611fca565b90925090508180156116565750846001600160a01b0316816001600160a01b0316145b156116665760019250505061173c565b6001600160a01b038416156117355760405163457dc7b760e01b81526001600160a01b03898116600483015285811660248301527f0000000000000000000000003b1ed0694345648a19882f9ed1374a5fb1296bdf169063457dc7b79060440160006040518083038186803b1580156116de57600080fd5b505afa1580156116f2573d6000803e3d6000fd5b5050505061170288858989612002565b90925090508180156117255750846001600160a01b0316816001600160a01b0316145b156117355760019250505061173c565b6000925050505b95945050505050565b60008160000361175757506000919050565b600060015461271061176991906141e0565b90508060018161177b61271087614273565b6117859190614260565b61178f91906141e0565b611799919061428a565b9392505050565b6000600b6117b16020860186614226565b600e8111156117c2576117c2614210565b141580156117ee575060086117da6020860186614226565b600e8111156117eb576117eb614210565b14155b80156118185750600c6118046020860186614226565b600e81111561181557611815614210565b14155b80156118425750600d61182e6020860186614226565b600e81111561183f5761183f614210565b14155b156118de576001600160a01b037f0000000000000000000000003b1ed0694345648a19882f9ed1374a5fb1296bdf16637547dbc36118866040870160208801613ed2565b6040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260240160006040518083038186803b1580156118c557600080fd5b505afa1580156118d9573d6000803e3d6000fd5b505050505b600c6118ed6020860186614226565b600e8111156118fe576118fe614210565b1415801561192a5750600d6119166020860186614226565b600e81111561192757611927614210565b14155b8015611954575060046119406020860186614226565b600e81111561195157611951614210565b14155b801561197e5750600861196a6020860186614226565b600e81111561197b5761197b614210565b14155b80156119a85750600b6119946020860186614226565b600e8111156119a5576119a5614210565b14155b156119e65760006119bf6060860160408701613ed2565b6001600160a01b0316036119e65760405163e6c4247b60e01b815260040160405180910390fd5b60006119f56020860186614226565b600e811115611a0657611a06614210565b03611a1c57611a158484612042565b9050611799565b6001611a2b6020860186614226565b600e811115611a3c57611a3c614210565b03611a4b57611a158484612103565b6006611a5a6020860186614226565b600e811115611a6b57611a6b614210565b03611a7a57611a158484612151565b6002611a896020860186614226565b600e811115611a9a57611a9a614210565b03611aa957611a15848461219f565b6007611ab86020860186614226565b600e811115611ac957611ac9614210565b03611ad857611a158484612283565b6003611ae76020860186614226565b600e811115611af857611af8614210565b03611b0757611a158484612381565b6009611b166020860186614226565b600e811115611b2757611b27614210565b03611b3657611a1584846123e4565b600a611b456020860186614226565b600e811115611b5657611b56614210565b03611b6557611a158484612413565b600e611b746020860186614226565b600e811115611b8557611b85614210565b03611b9457611a158484612537565b6005611ba36020860186614226565b600e811115611bb457611bb4614210565b03611bc357611a15848461265c565b6008611bd26020860186614226565b600e811115611be357611be3614210565b03611bf257611a1584846128ac565b600b611c016020860186614226565b600e811115611c1257611c12614210565b03611c2157611a158484612a3f565b6004611c306020860186614226565b600e811115611c4157611c41614210565b03611c5157611a15848484612b89565b600c611c606020860186614226565b600e811115611c7157611c71614210565b03611c8057611a158484612f21565b600d611c8f6020860186614226565b600e811115611ca057611ca0614210565b03611caf57611a158484613081565b6040516347a8190160e01b815260040160405180910390fd5b60006040516323b872dd60e01b81528460048201528360248201528260448201526020600060648360008a5af13d15601f3d1160016000511416171691505080611d2557604051631e4e7d0960e21b815260040160405180910390fd5b5050505050565b8060005b83811015611d7b57611d67858583818110611d4d57611d4d61414a565b9050602002810190611d5f91906141aa565b8360006117a0565b915080611d7381614247565b915050611d30565b509392505050565b6040516001600160a01b038481166024830152838116604483015262ffffff83166064830152600091829182918291891690630b4c774160e11b906084015b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051611e0091906142d0565b600060405180830381855afa9150503d8060008114611e3b576040519150601f19603f3d011682016040523d82523d6000602084013e611e40565b606091505b5091509150811580611e53575060208151105b15611e6657600080935093505050611247565b600181806020019051810190611e7c91906141f3565b93509350505094509492505050565b6040516001600160a01b0384811660248301528381166044830152600283900b60648301526000918291829182918916906328af8d0b60e01b90608401611dc2565b6040516001600160a01b038381166024830152828116604483015260009182918291829188169063d9a641e160e01b906064015b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051611f3f91906142d0565b600060405180830381855afa9150503d8060008114611f7a576040519150601f19603f3d011682016040523d82523d6000602084013e611f7f565b606091505b5091509150811580611f92575060208151105b15611fa557600080935093505050611fc2565b600181806020019051810190611fbb91906141f3565b9350935050505b935093915050565b6040516001600160a01b038381166024830152828116604483015260009182918291829188169063d8ed224160e01b90606401611f01565b6040516001600160a01b038481166024830152838116604483015282811660648301526000918291829182918916906308f68db360e21b90608401611dc2565b604080516002808252606082018352600092839291906020830190803683370190505090506120776060850160408601613ed2565b8160008151811061208a5761208a61414a565b6001600160a01b03909216602092830291909101909101526120b26080850160608601613ed2565b816001815181106120c5576120c561414a565b60200260200101906001600160a01b031690816001600160a01b0316815250506120f984846120f486856131cc565b61321a565b9150505b92915050565b6000806121136080850185614352565b81019061212091906143a4565b90506120f984846120f461213a6060840160408501613ed2565b61214a60808a0160608b01613ed2565b8689613278565b6000806121616080850185614352565b81019061216e91906143a4565b90506120f984846120f46121886060840160408501613ed2565b61219860808a0160608b01613ed2565b8689613306565b6000806121af6080850185614352565b8101906121bc91906143d1565b60408051600180825281830190925291925060009190816020015b60408051606081018252600080825260208083018290529282015282526000199092019101816121d757905050905060405180606001604052808660400160208101906122249190613ed2565b6001600160a01b031681526020016122426080880160608901613ed2565b6001600160a01b03168152602001831515815250816000815181106122695761226961414a565b602002602001018190525061173c85856120f48488613362565b600080806122946080860186614352565b8101906122a191906143ec565b60408051600180825281830190925292945090925060009190816020015b6040805160808101825260008082526020808301829052928201819052606082015282526000199092019101816122bf57905050905060405180608001604052808760400160208101906123139190613ed2565b6001600160a01b031681526020016123316080890160608a01613ed2565b6001600160a01b031681526020018415158152602001836001600160a01b0316815250816000815181106123675761236761414a565b60200260200101819052506105f686866120f484896133c0565b600060606123926080850185614352565b90506020036123cc5760006123aa6080860186614352565b8101906123b79190613ed2565b90506123c485828661340e565b9150506123d9565b6123d684846134bc565b90505b6120f984848361321a565b6000806123f46080850185614352565b810190612401919061442e565b90506120f984846120f4878588613529565b600080806124246080860186614352565b810190612431919061444b565b60408051600180825281830190925292945090925060009190816020015b6040805160c08101825260008082526020808301829052928201819052606082018190526080820181905260a0820152825260001990920191018161244f5790505090506040518060c00160405280846001600160a01b031681526020018760400160208101906124c09190613ed2565b6001600160a01b031681526020016124de6080890160608a01613ed2565b6001600160a01b031681526020018315158152602001600015158152602001306001600160a01b03168152508160008151811061251d5761251d61414a565b60200260200101819052506105f686866120f484896135a1565b6040805160028082526060820183526000928392919060208301908036833701905050905061256c6060850160408601613ed2565b8160008151811061257f5761257f61414a565b6001600160a01b03909216602092830291909101909101526125a76080850160608601613ed2565b816001815181106125ba576125ba61414a565b6001600160a01b039092166020928302919091018201526000906125e16080870187614352565b905010156125f057600061260a565b6125fd6080860186614352565b81019061260a9190613ed2565b905061173c85858660008630874260405160240161262d969594939291906144c4565b60408051601f198184030181529190526020810180516001600160e01b031663561c49dd60e11b17905261321a565b6000808061266d6080860186614352565b81019061267a9190614508565b909250905060006126996126946080880160608901613ed2565b6135c5565b9050606060008415612712575060006126b86060890160408a01613ed2565b846126c960808b0160608c01613ed2565b6040516bffffffffffffffffffffffff19606094851b8116602083015260e89390931b6034820152921b166037820152604b016040516020818303038152906040529150612798565b5060086127256060890160408a01613ed2565b8460020b60011461273757600061273d565b600160f81b5b61274d60808b0160608c01613ed2565b6040516bffffffffffffffffffffffff19606094851b811660208301526001600160f81b03199093166034820152921b16603582015260490160405160208183030381529060405291505b6040516001600160f81b031960f883901b166020820152606090819060210160408051808303601f1901815260018084528383019092529350816020015b60608152602001906001900390816127d6579050509050308960008660008060405160200161280a96959493929190614560565b6040516020818303038152906040528160008151811061282c5761282c61414a565b602090810291909101015261286061284a60608c0160408d01613ed2565b61285a60408d0160208e01613ed2565b8b610adb565b61288461287360408c0160208d01613ed2565b61287d8484613644565b600061368d565b5061289e61289860808c0160608d01613ed2565b86613715565b9a9950505050505050505050565b6000806128b88461372b565b9050600060406128cb6080870187614352565b9050106128f0576128df6080860186614352565b8101906128ec91906145aa565b9150505b600061291c836129066060890160408a01613ed2565b61291660808a0160608b01613ed2565b85613772565b905060006129306060880160408901613ed2565b604080516001600160a01b039283166020820152908101889052306060820152908416608082015260a0016040516020818303038152906040529050600080856001600160a01b031663128acb0830868b886129aa576129a5600173fffd8963efd1fc6a506488495d951d5263988d266145c8565b6129ba565b6129ba6401000276a360016145ef565b886040518663ffffffff1660e01b81526004016129db95949392919061460f565b60408051808303816000875af11580156129f9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a1d919061464a565b91509150600084612a3657612a318361466e565b61289e565b61289e8261466e565b600080612a4b8461372b565b90506001600160a01b038116612a745760405163e6c4247b60e01b815260040160405180910390fd5b6000612a8f82612a8a6060880160408901613ed2565b6138cc565b9050600080836001600160a01b031663128acb0830858987612acf57612aca600173fffd8963efd1fc6a506488495d951d5263988d266145c8565b612adf565b612adf6401000276a360016145ef565b60408051306020820152016040516020818303038152906040526040518663ffffffff1660e01b8152600401612b1995949392919061460f565b60408051808303816000875af1158015612b37573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b5b919061464a565b91509150600083612b7457612b6f8361466e565b612b7d565b612b7d8261466e565b98975050505050505050565b600080612b9f6126946080870160608801613ed2565b90506000612bb06080870187614352565b810190612bbd919061468a565b60808101519091506001600160a01b031615612c545760808101516040516329e899d960e01b81526001600160a01b0391821660048201527f0000000000000000000000003b1ed0694345648a19882f9ed1374a5fb1296bdf909116906329e899d99060240160006040518083038186803b158015612c3b57600080fd5b505afa158015612c4f573d6000803e3d6000fd5b505050505b6000612c666060880160408901613ed2565b6001600160a01b031614612d4a57612c9d612c876060880160408901613ed2565b6e22d473030f116ddee9f6b43ac78ba387613b0a565b6e22d473030f116ddee9f6b43ac78ba36387517c45612cc26060890160408a01613ed2565b612cd260408a0160208b01613ed2565b6040516001600160e01b031960e085901b1681526001600160a01b0392831660048201529082166024820152908816604482015265ffffffffffff42166064820152608401600060405180830381600087803b158015612d3157600080fd5b505af1158015612d45573d6000803e3d6000fd5b505050505b6000612d5887838888613b21565b60408051600180825281830190925291925060009190816020015b6060815260200190600190039081612d735790505090508181600081518110612d9e57612d9e61414a565b6020026020010181905250612e15886020016020810190612dbf9190613ed2565b604051600160fc1b6020820152612de89060210160405160208183030381529060405284613644565b6000612dfa60608d0160408e01613ed2565b6001600160a01b031614612e0f57600061368d565b8961368d565b5060009150612e2c90506060880160408901613ed2565b6001600160a01b031614612f0857612e64612e4d6060880160408901613ed2565b6e22d473030f116ddee9f6b43ac78ba36000613b0a565b6e22d473030f116ddee9f6b43ac78ba36387517c45612e896060890160408a01613ed2565b612e9960408a0160208b01613ed2565b6040516001600160e01b031960e085901b1681526001600160a01b039283166004820152911660248201526000604482018190526064820152608401600060405180830381600087803b158015612eef57600080fd5b505af1158015612f03573d6000803e3d6000fd5b505050505b6105f6612f1b6080880160608901613ed2565b83613715565b60006001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216612f5d6040850160208601613ed2565b6001600160a01b0316141580612fb457506001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216612fa86080850160608601613ed2565b6001600160a01b031614155b80612fd857506000612fcc6060850160408601613ed2565b6001600160a01b031614155b15612ff657604051635e66e44d60e01b815260040160405180910390fd5b8147101561301757604051635b6b73eb60e11b815260040160405180910390fd5b6130276040840160208501613ed2565b6001600160a01b031663d0e30db0836040518263ffffffff1660e01b81526004016000604051808303818588803b15801561306157600080fd5b505af1158015613075573d6000803e3d6000fd5b50949695505050505050565b60006001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2166130bd6040850160208601613ed2565b6001600160a01b031614158061311457506001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2166131086060850160408601613ed2565b6001600160a01b031614155b806131385750600061312c6080850160608601613ed2565b6001600160a01b031614155b1561315657604051635e66e44d60e01b815260040160405180910390fd5b6131666040840160208501613ed2565b6001600160a01b0316632e1a7d4d836040518263ffffffff1660e01b815260040161319391815260200190565b600060405180830381600087803b1580156131ad57600080fd5b505af11580156131c1573d6000803e3d6000fd5b509395945050505050565b60608260008330426040516024016131e895949392919061472a565b60408051601f198184030181529190526020810180516001600160e01b03166338ed173960e01b179052905092915050565b6000806132306126946080870160608801613ed2565b905061325e6132456060870160408801613ed2565b6132556040880160208901613ed2565b86866000613e29565b5061173c6132726080870160608801613ed2565b82613715565b6040516001600160a01b0380861660248301528416604482015262ffffff8316606482015230608482015260a48101829052600060c4820181905260e48201526060906304e45aaf60e01b90610104015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915290505b949350505050565b6040516001600160a01b0380861660248301528416604482015262ffffff831660648201523060848201524260a482015260c48101829052600060e4820181905261010482015260609063414bf38960e01b90610124016132c9565b606063f41766d860e01b826000853042604051602401613386959493929190614766565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152905092915050565b60608160008430426040516024016133dc9594939291906147fe565b60408051601f198184030181529190526020810180516001600160e01b031663cac88ea960e01b179052905092915050565b6060630b3ce3c960e11b61342785830160408701613ed2565b6134376080870160608801613ed2565b6040516001600160a01b039283166024820152908216604482015290851660648201523060848201524260a482015260c48101849052600060e48201819052610104820152610124015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915290509392505050565b606063178ca23160e31b6134d584830160408601613ed2565b6134e56080860160608701613ed2565b6040516001600160a01b0392831660248201529116604482015230606482015242608482015260a48101849052600060c4820181905260e482015261010401613386565b60606350131c1f60e11b61354285830160408701613ed2565b6135526080870160608801613ed2565b6040516001600160a01b03928316602482015291166044820152600285900b60648201523060848201524260a482015260c48101849052600060e4820181905261010482015261012401613481565b606063204b5c0a60e01b826000853042604051602401613386959493929190614874565b60006001600160a01b0382166135dc575047919050565b6040516370a0823160e01b81523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa158015613620573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120fd91906140de565b606082824260405160240161365b93929190614975565b60408051601f198184030181529190526020810180516001600160e01b0316630d64d59360e21b179052905092915050565b6060600080856001600160a01b031684866040516136ab91906142d0565b60006040518083038185875af1925050503d80600081146136e8576040519150601f19603f3d011682016040523d82523d6000602084013e6136ed565b606091505b50915091508161173c5780604051600162605a6b60e01b031981526004016111a891906149ab565b600081613721846135c5565b61179991906141e0565b6000602061373c6080840184614352565b90501061375d576137506080830183614352565b8101906120fd9190613ed2565b6120fd6040830160208401613ed2565b919050565b6000806000806137818861147f565b60405163965106d360e01b81526001600160a01b03828116600483015293965091945092507f0000000000000000000000003b1ed0694345648a19882f9ed1374a5fb1296bdf9091169063965106d39060240160006040518083038186803b1580156137ec57600080fd5b505afa158015613800573d6000803e3d6000fd5b505050506138118184848b896115bb565b61382d5760405162820f3560e61b815260040160405180910390fd5b826001600160a01b0316876001600160a01b031614801561385f5750816001600160a01b0316866001600160a01b0316145b1561387057600193505050506132fe565b816001600160a01b0316876001600160a01b03161480156138a25750826001600160a01b0316866001600160a01b0316145b156138b357600093505050506132fe565b604051636b8794e960e11b815260040160405180910390fd5b6000808390506000816001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015613912573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061393691906141f3565b90506000826001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa158015613978573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061399c91906141f3565b90506000836001600160a01b031663c45a01556040518163ffffffff1660e01b8152600401602060405180830381865afa1580156139de573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a0291906141f3565b60405163965106d360e01b81526001600160a01b0380831660048301529192507f0000000000000000000000003b1ed0694345648a19882f9ed1374a5fb1296bdf9091169063965106d39060240160006040518083038186803b158015613a6857600080fd5b505afa158015613a7c573d6000803e3d6000fd5b50505050600080613a8c89611281565b91509150613a9e83868685858e6113ee565b613aba5760405162820f3560e61b815260040160405180910390fd5b846001600160a01b0316886001600160a01b031603613ae257600196505050505050506120fd565b836001600160a01b0316886001600160a01b0316036138b357600096505050505050506120fd565b613b1683836000613e4f565b61127c838383613e4f565b6060600080613b3560808801888501613ed2565b6001600160a01b0316613b4e6060890160408a01613ed2565b6001600160a01b031610613b8157613b6c6080880160608901613ed2565b613b7c6060890160408a01613ed2565b613ba1565b613b916060880160408901613ed2565b613ba16080890160608a01613ed2565b909250905060006001600160a01b038316613bc260608a0160408b01613ed2565b60408051600360f91b6020820152600360fa1b6021820152600f60f81b602282015281516003818303810182526023830181815260a384019094526001600160a01b0394909416949094149450600092906043015b6060815260200190600190039081613c1757905050905060006040518060a001604052806040518060a00160405280896001600160a01b03168152602001886001600160a01b031681526020018d6040015162ffffff1681526020018d6060015160020b81526020018d608001516001600160a01b0316815250815260200185151581526020018a6001600160801b0316815260200160006001600160801b03168152602001600067ffffffffffffffff811115613cd757613cd761433c565b6040519080825280601f01601f191660200182016040528015613d01576020820181803683370190505b50815250905080604051602001613d1891906149be565b60405160208183030381529060405282600081518110613d3a57613d3a61414a565b6020908102919091010152613d5560608c0160408d01613ed2565b604080516001600160a01b03909216602083015281018a905260600160405160208183030381529060405282600181518110613d9357613d9361414a565b6020908102919091010152613dae60808c0160608d01613ed2565b604080516001600160a01b039092166020830152810189905260600160405160208183030381529060405282600281518110613dec57613dec61414a565b60200260200101819052508282604051602001613e0a929190614a5b565b6040516020818303038152906040529650505050505050949350505050565b6060613e36868686613b0a565b6000613e4386858561368d565b90506105f68787613ea6565b600060405163095ea7b360e01b8152836004820152826024820152602060006044836000895af13d15601f3d1160016000511416171691505080610ad557604051633e3f8f7360e01b815260040160405180910390fd5b61043882826000613e4f565b6001600160a01b038116811461087457600080fd5b803561376d81613eb2565b600060208284031215613ee457600080fd5b813561179981613eb2565b60008060008060608587031215613f0557600080fd5b8435935060208501359250604085013567ffffffffffffffff80821115613f2b57600080fd5b818701915087601f830112613f3f57600080fd5b813581811115613f4e57600080fd5b886020828501011115613f6057600080fd5b95989497505060200194505050565b600060208284031215613f8157600080fd5b5035919050565b60008083601f840112613f9a57600080fd5b50813567ffffffffffffffff811115613fb257600080fd5b6020830191508360208260051b8501011115613fcd57600080fd5b9250929050565b60008060008060008060a08789031215613fed57600080fd5b863567ffffffffffffffff81111561400457600080fd5b61401089828a01613f88565b9097509550506020870135935060408701359250606087013561403281613eb2565b80925050608087013590509295509295509295565b600080600080600080600060a0888a03121561406257600080fd5b873567ffffffffffffffff8082111561407a57600080fd5b6140868b838c01613f88565b909950975060208a013591508082111561409f57600080fd5b506140ac8a828b01613f88565b9096509450506040880135925060608801356140c781613eb2565b809250506080880135905092959891949750929550565b6000602082840312156140f057600080fd5b5051919050565b6000806000806080858703121561410d57600080fd5b843561411881613eb2565b935060208501359250604085013561412f81613eb2565b9150606085013561413f81613eb2565b939692955090935050565b634e487b7160e01b600052603260045260246000fd5b6000808335601e1984360301811261417757600080fd5b83018035915067ffffffffffffffff82111561419257600080fd5b6020019150600581901b3603821315613fcd57600080fd5b60008235609e198336030181126141c057600080fd5b9190910192915050565b634e487b7160e01b600052601160045260246000fd5b818103818111156120fd576120fd6141ca565b60006020828403121561420557600080fd5b815161179981613eb2565b634e487b7160e01b600052602160045260246000fd5b60006020828403121561423857600080fd5b8135600f811061179957600080fd5b600060018201614259576142596141ca565b5060010190565b808201808211156120fd576120fd6141ca565b80820281158282048414176120fd576120fd6141ca565b6000826142a757634e487b7160e01b600052601260045260246000fd5b500490565b60005b838110156142c75781810151838201526020016142af565b50506000910152565b600082516141c08184602087016142ac565b62ffffff8116811461087457600080fd5b60006020828403121561430557600080fd5b8151611799816142e2565b8060020b811461087457600080fd5b60006020828403121561433157600080fd5b815161179981614310565b634e487b7160e01b600052604160045260246000fd5b6000808335601e1984360301811261436957600080fd5b83018035915067ffffffffffffffff82111561438457600080fd5b602001915036819003821315613fcd57600080fd5b803561376d816142e2565b6000602082840312156143b657600080fd5b8135611799816142e2565b8035801515811461376d57600080fd5b6000602082840312156143e357600080fd5b611799826143c1565b600080604083850312156143ff57600080fd5b614408836143c1565b9150602083013561441881613eb2565b809150509250929050565b803561376d81614310565b60006020828403121561444057600080fd5b813561179981614310565b6000806040838503121561445e57600080fd5b823561446981613eb2565b9150614477602084016143c1565b90509250929050565b600081518084526020808501945080840160005b838110156144b95781516001600160a01b031687529582019590820190600101614494565b509495945050505050565b86815285602082015260c0604082015260006144e360c0830187614480565b6001600160a01b03958616606084015293909416608082015260a00152949350505050565b6000806040838503121561451b57600080fd5b614524836143c1565b9150602083013561441881614310565b6000815180845261454c8160208601602086016142ac565b601f01601f19169290920160200192915050565b60018060a01b038716815285602082015260ff8516604082015260c06060820152600061459060c0830186614534565b93151560808301525090151560a090910152949350505050565b600080604083850312156145bd57600080fd5b823561440881613eb2565b6001600160a01b038281168282160390808211156145e8576145e86141ca565b5092915050565b6001600160a01b038181168382160190808211156145e8576145e86141ca565b6001600160a01b0386811682528515156020830152604082018590528316606082015260a0608082018190526000906105f390830184614534565b6000806040838503121561465d57600080fd5b505080516020909101519092909150565b6000600160ff1b8201614683576146836141ca565b5060000390565b600060a0828403121561469c57600080fd5b60405160a0810181811067ffffffffffffffff821117156146cd57634e487b7160e01b600052604160045260246000fd5b60405282356146db81613eb2565b815260208301356146eb81613eb2565b60208201526146fc60408401614399565b604082015261470d60608401614423565b606082015261471e60808401613ec7565b60808201529392505050565b85815284602082015260a06040820152600061474960a0830186614480565b6001600160a01b0394909416606083015250608001529392505050565b600060a08201878352602060ff881681850152604060a08186015282885180855260c087019150838a01945060005b818110156147d257855180516001600160a01b03908116855286820151168685015284015115158484015294840194606090920191600101614795565b50506001600160a01b038816606087015293506147ee92505050565b8260808301529695505050505050565b600060a0820187835260208781850152604060a08186015282885180855260c087019150838a01945060005b818110156147d257855180516001600160a01b039081168552868201518116878601528582015115158686015260609182015116908401529484019460809092019160010161482a565b600060a0808301888452602060ff8916818601526040838187015282895180855260c094508488019150838b0160005b8281101561490257815180516001600160a01b039081168652878201518116888701528682015181168787015260608083015115159087015260808083015115159087015290890151168885015292860192908501906001016148a4565b5050506001600160a01b038916606088015294506147ee9350505050565b600081518084526020808501808196508360051b8101915082860160005b85811015614968578284038952614956848351614534565b9885019893509084019060010161493e565b5091979650505050505050565b6060815260006149886060830186614534565b828103602084015261499a8186614920565b915050826040830152949350505050565b6020815260006117996020830184614534565b602081526000825160018060a01b0380825116602085015280602083015116604085015262ffffff6040830151166060850152606082015160020b60808501528060808301511660a085015250506020830151614a1f60c084018215159052565b5060408301516001600160801b0390811660e08401526060840151166101008301526080830151610120808401526120f9610140840182614534565b604081526000614a6e6040830185614534565b828103602084015261173c818561492056fea2646970667358221220b10ffdc6ec1523b2a1d5a55d847ca5ba058683697ebe0e015e80331ea312ab5564736f6c63430008130033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000003b1ed0694345648a19882f9ed1374a5fb1296bdf000000000000000000000000bde48624f9e1dd4107df324d1ba3c07004640206000000000000000000000000d4627ecb405b64448ee6b07dcf860bf55590c83d000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
-----Decoded View---------------
Arg [0] : allowlist_ (address): 0x3B1Ed0694345648A19882f9ED1374a5FB1296bDF
Arg [1] : admin_ (address): 0xBDE48624F9E1dd4107df324D1BA3C07004640206
Arg [2] : feeCollector_ (address): 0xd4627eCb405B64448EE6B07dcf860BF55590c83D
Arg [3] : wrappedNative_ (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 0000000000000000000000003b1ed0694345648a19882f9ed1374a5fb1296bdf
Arg [1] : 000000000000000000000000bde48624f9e1dd4107df324d1ba3c07004640206
Arg [2] : 000000000000000000000000d4627ecb405b64448ee6b07dcf860bf55590c83d
Arg [3] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
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
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.