Source Code
Latest 25 from a total of 46 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Process Route | 231090423 | 569 days ago | IN | 1.7951 ETH | 0.00000775 | ||||
| Process Route | 221431262 | 597 days ago | IN | 0 ETH | 0.00000423 | ||||
| Process Route | 219990082 | 601 days ago | IN | 0 ETH | 0.00000495 | ||||
| Process Route | 219613847 | 602 days ago | IN | 0 ETH | 0.00000511 | ||||
| Process Route | 219613741 | 602 days ago | IN | 0 ETH | 0.00000297 | ||||
| Process Route | 218192452 | 607 days ago | IN | 0 ETH | 0.00000244 | ||||
| Process Route | 215113204 | 616 days ago | IN | 0 ETH | 0.00000443 | ||||
| Process Route | 213725540 | 620 days ago | IN | 0 ETH | 0.00000244 | ||||
| Process Route | 208982148 | 634 days ago | IN | 0 ETH | 0.00000202 | ||||
| Process Route | 205775317 | 643 days ago | IN | 0.0121 ETH | 0.00000225 | ||||
| Process Route | 205773235 | 643 days ago | IN | 0 ETH | 0.00000315 | ||||
| Process Route | 205767509 | 643 days ago | IN | 0 ETH | 0.00000328 | ||||
| Process Route | 205743368 | 643 days ago | IN | 0 ETH | 0.00000559 | ||||
| Process Route | 199500571 | 661 days ago | IN | 0 ETH | 0.00000225 | ||||
| Process Route | 199428523 | 662 days ago | IN | 0.005 ETH | 0.00000336 | ||||
| Process Route | 196406315 | 670 days ago | IN | 0 ETH | 0.00001614 | ||||
| Process Route | 191922789 | 683 days ago | IN | 0 ETH | 0.00000699 | ||||
| Process Route | 191888109 | 684 days ago | IN | 0 ETH | 0.00003569 | ||||
| Process Route | 190480304 | 688 days ago | IN | 0 ETH | 0.00002855 | ||||
| Process Route | 187278777 | 697 days ago | IN | 0 ETH | 0.00015775 | ||||
| Process Route | 184938169 | 704 days ago | IN | 0 ETH | 0.00018657 | ||||
| Process Route | 184936286 | 704 days ago | IN | 0 ETH | 0.00018089 | ||||
| Process Route | 180939920 | 716 days ago | IN | 0 ETH | 0.00013437 | ||||
| Process Route | 173515573 | 739 days ago | IN | 0 ETH | 0.00011259 | ||||
| Process Route | 173506873 | 739 days ago | IN | 0 ETH | 0.00007509 |
Latest 25 internal transactions (View All)
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 231090423 | 569 days ago | 1.7951 ETH | ||||
| 219990082 | 601 days ago | 0.0038531 ETH | ||||
| 219990082 | 601 days ago | 0.0038531 ETH | ||||
| 219613847 | 602 days ago | 0.00023216 ETH | ||||
| 219613847 | 602 days ago | 0.00023216 ETH | ||||
| 219613741 | 602 days ago | 0.00439281 ETH | ||||
| 219613741 | 602 days ago | 0.00439281 ETH | ||||
| 215113204 | 616 days ago | 0.00343136 ETH | ||||
| 215113204 | 616 days ago | 0.00343136 ETH | ||||
| 213725540 | 620 days ago | 0.00464946 ETH | ||||
| 213725540 | 620 days ago | 0.00464946 ETH | ||||
| 205775317 | 643 days ago | 0.0121 ETH | ||||
| 199428523 | 662 days ago | 0.005 ETH | ||||
| 191922789 | 683 days ago | 0.00416156 ETH | ||||
| 191922789 | 683 days ago | 0.00416156 ETH | ||||
| 191888109 | 684 days ago | 0.00333494 ETH | ||||
| 191888109 | 684 days ago | 0.00333494 ETH | ||||
| 184938169 | 704 days ago | 0.01505302 ETH | ||||
| 184938169 | 704 days ago | 0.01505302 ETH | ||||
| 184936286 | 704 days ago | 0.01549621 ETH | ||||
| 184936286 | 704 days ago | 0.01549621 ETH | ||||
| 180939920 | 716 days ago | 0.00996514 ETH | ||||
| 180939920 | 716 days ago | 0.00996514 ETH | ||||
| 173506873 | 739 days ago | 0.00669874 ETH | ||||
| 173506873 | 739 days ago | 0.00669874 ETH |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
UniversalRouter2
Compiler Version
v0.8.7+commit.e28d00a7
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {InputStream} from './InputStream.sol';
import {ReentrancyGuard} from "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import {SafeTransferLib} from 'lib/solmate/src/utils/SafeTransferLib.sol';
import {IPair} from "../core/interfaces/IPair.sol";
import {IWETH} from "./interfaces/IWETH.sol";
import {IStableSwapDispatcher} from "./interfaces/IStableSwapDispatcher.sol";
import {IFeeSettlement} from "./interfaces/IFeeSettlement.sol";
import {AdminUpgradeable} from "../libraries/AdminUpgradeable.sol";
import {Constants} from "../libraries/Constants.sol";
import {IUniswapV3Pool} from "./interfaces/uniswap/v3/IUniswapV3Pool.sol";
import {IAlgebraPool} from "./interfaces/algebra/IAlgebraPool.sol";
import {IVault} from "./interfaces/gmx/IVault.sol";
import {ILBPair} from "./interfaces/joe/v2/ILBPair.sol";
import {Pausable} from "@openzeppelin/contracts/security/Pausable.sol";
import {ICurveStableDispatcher} from "./interfaces/curve/ICurveStableDispatcher.sol";
contract UniversalRouter2 is ReentrancyGuard, AdminUpgradeable, Pausable {
using SafeERC20 for IERC20;
using SafeTransferLib for address;
using InputStream for uint256;
IStableSwapDispatcher public stableSwapDispatcher;
ICurveStableDispatcher public curveStableDispatcher;
IFeeSettlement public feeSettlement;
address private lastCalledPool;
error UnknownCommandCode(uint8 code);
error UnknownPoolType(uint8 poolType);
error MinimalInputBalanceViolation();
error MinimalOutputBalanceViolation();
error InvalidPool(address pool);
error UnexpectedAddress(address addr);
error UnexpectedUniV3Swap();
error UnexpectedAlgebraSwap();
event SetCurveStableDispatcher(ICurveStableDispatcher curveStableDispatcher);
event SetStableSwapDispatcher(IStableSwapDispatcher stableSwapDispatcher);
event SetFeeSettlement(IFeeSettlement feeSettlement);
constructor(
IStableSwapDispatcher _stableSwapDispatcher,
ICurveStableDispatcher _curveStableDispatcher,
IFeeSettlement _feeSettlement
) {
stableSwapDispatcher = _stableSwapDispatcher;
curveStableDispatcher = _curveStableDispatcher;
feeSettlement = _feeSettlement;
lastCalledPool = Constants.IMPOSSIBLE_POOL_ADDRESS;
_initializeAdmin(msg.sender);
}
/// @notice To receive ETH from WETH
receive() external payable {}
/// @notice Set StableSwapDispatcher by admin
/// @param _stableSwapDispatcher StableSwapDispatcher address
function setStableSwapDispatcher(IStableSwapDispatcher _stableSwapDispatcher) external onlyAdmin {
stableSwapDispatcher = _stableSwapDispatcher;
emit SetStableSwapDispatcher(_stableSwapDispatcher);
}
/// @notice Set CurveStableDispatcher by admin
/// @param _curveStableDispatcher CurveStableDispatcher address
function setCurveStableDispatcher(ICurveStableDispatcher _curveStableDispatcher) external onlyAdmin {
curveStableDispatcher = _curveStableDispatcher;
emit SetCurveStableDispatcher(_curveStableDispatcher);
}
/// @notice Set FeeSettlement by admin
/// @param _feeSettlement FeeSettlement address
function setFeeSettlement(IFeeSettlement _feeSettlement) external onlyAdmin {
feeSettlement = _feeSettlement;
emit SetFeeSettlement(_feeSettlement);
}
/// @notice Decodes and executes the given route
/// @param tokenIn Address of the input token
/// @param amountIn Amount of the input token
/// @param tokenOut Address of the output token
/// @param amountOutMin Minimum amount of the output token
/// @param to Receiver address
/// @param route The encoded route to execute with
/// @return amountOut Actual amount of the output token
function processRoute(
address tokenIn,
uint256 amountIn,
address tokenOut,
uint256 amountOutMin,
address to,
bytes memory route
) external payable nonReentrant whenNotPaused returns (uint256 amountOut) {
return processRouteInternal(tokenIn, amountIn, tokenOut, amountOutMin, to, route);
}
function transferValueAndprocessRoute(
address transferValueTo,
uint256 amountValueTransfer,
address tokenIn,
uint256 amountIn,
address tokenOut,
uint256 amountOutMin,
address to,
bytes memory route
) external payable nonReentrant whenNotPaused returns (uint256 amountOut) {
transferValueTo.safeTransferETH(amountValueTransfer);
return processRouteInternal(tokenIn, amountIn, tokenOut, amountOutMin, to, route);
}
/// @notice Decodes and executes the given route
/// @param tokenIn Address of the input token
/// @param amountIn Amount of the input token
/// @param tokenOut Address of the output token
/// @param amountOutMin Minimum amount of the output token
/// @param to Receiver address
/// @param route The encoded route to execute with
/// @return amountOut Actual amount of the output token
function processRouteInternal(
address tokenIn,
uint256 amountIn,
address tokenOut,
uint256 amountOutMin,
address to,
bytes memory route
) private returns (uint256 amountOut) {
uint256 balanceInInitial = tokenIn == Constants.NATIVE_ADDRESS
? address(this).balance
: IERC20(tokenIn).balanceOf(msg.sender);
uint256 balanceOutInitial = tokenOut == Constants.NATIVE_ADDRESS
? address(to).balance
: IERC20(tokenOut).balanceOf(to);
uint256 stream = InputStream.createStream(route);
while (stream.isNotEmpty()) {
uint8 commandCode = stream.readUint8();
if (commandCode == 1) _processMyERC20(stream);
else if (commandCode == 2) _processUserERC20(stream, amountIn);
else if (commandCode == 3) _processNative(stream);
else if (commandCode == 4) _processOnePool(stream);
else revert UnknownCommandCode(commandCode);
}
uint256 balanceInFinal = tokenIn == Constants.NATIVE_ADDRESS
? address(this).balance
: IERC20(tokenIn).balanceOf(msg.sender);
if (balanceInFinal + amountIn < balanceInInitial) revert MinimalInputBalanceViolation();
feeSettlement.processSettlement(tokenOut, amountOutMin, msg.sender, to);
uint256 balanceOutFinal = tokenOut == Constants.NATIVE_ADDRESS
? address(to).balance
: IERC20(tokenOut).balanceOf(to);
if (balanceOutFinal < balanceOutInitial + amountOutMin) revert MinimalOutputBalanceViolation();
amountOut = balanceOutFinal - balanceOutInitial;
}
/// @notice Processes native coin: call swap for all pools that swap from native coin
/// @param stream Streamed process program
function _processNative(uint256 stream) private {
uint256 amountTotal = address(this).balance;
_distributeAndSwap(stream, address(this), Constants.NATIVE_ADDRESS, amountTotal);
}
/// @notice Processes ERC20 token from this contract balance:
/// @notice Call swap for all pools that swap from this token
/// @param stream Streamed process program
function _processMyERC20(uint256 stream) private {
address token = stream.readAddress();
uint256 amountTotal = IERC20(token).balanceOf(address(this));
unchecked {
if (amountTotal > 0) amountTotal -= 1; // slot undrain protection
}
_distributeAndSwap(stream, address(this), token, amountTotal);
}
/// @notice Processes ERC20 token from msg.sender balance:
/// @notice Call swap for all pools that swap from this token
/// @param stream Streamed process program
/// @param amountTotal Amount of tokens to take from msg.sender
function _processUserERC20(uint256 stream, uint256 amountTotal) private {
address token = stream.readAddress();
_distributeAndSwap(stream, msg.sender, token, amountTotal);
}
/// @notice Distributes amountTotal to several pools according to their shares and calls swap for each pool
/// @param stream Streamed process program
/// @param from Where to take liquidity for swap
/// @param tokenIn Input token
/// @param amountTotal Total amount of tokenIn for swaps
function _distributeAndSwap(
uint256 stream,
address from,
address tokenIn,
uint256 amountTotal
) private {
uint8 num = stream.readUint8();
for (uint256 i = 0; i < num; ++i) {
uint16 share = stream.readUint16();
uint256 amount = (amountTotal * share) / 65535;
amountTotal -= amount;
_swap(stream, from, tokenIn, amount);
}
}
/// @notice Processes ERC20 token for cases when the token has only one output pool
/// @notice In this case liquidity is already at pool balance. This is an optimization
/// @notice Call swap for all pools that swap from this token
/// @param stream Streamed process program
function _processOnePool(uint256 stream) private {
address token = stream.readAddress();
_swap(stream, address(this), token, 0);
}
/// @notice Makes swap
/// @param stream Streamed process program
/// @param from Where to take liquidity for swap
/// @param tokenIn Input token
/// @param amountIn Amount of tokenIn to take for swap
function _swap(uint256 stream, address from, address tokenIn, uint256 amountIn) private {
uint8 poolType = stream.readUint8();
if (poolType == 0) _swapUniV2(stream, from, tokenIn, amountIn);
else if (poolType == 1) _swapUniV3(stream, from, tokenIn, amountIn);
else if (poolType == 2) _wrapNative(stream, from, tokenIn, amountIn);
else if (poolType == 3) _swapStableSwap(stream, from, tokenIn, amountIn);
else if (poolType == 4) _swapGmx(stream, from, tokenIn, amountIn);
else if (poolType == 5) _swapJoeV2(stream, from, tokenIn, amountIn);
else if (poolType == 6) _swapAlgebra(stream, from, tokenIn, amountIn);
else if (poolType == 7) _swapCurveStable(stream, from, tokenIn, amountIn);
else revert UnknownPoolType(poolType);
}
/// @notice UniswapV2 pool swap
/// @param stream [pool, direction, recipient]
/// @param from Where to take liquidity for swap
/// @param tokenIn Input token
/// @param amountIn Amount of tokenIn to take for swap
function _swapUniV2(
uint256 stream,
address from,
address tokenIn,
uint256 amountIn
) private returns (uint256 amountOut) {
address pool = stream.readAddress();
uint8 direction = stream.readUint8();
address to = stream.readAddress();
(uint256 reserve0, uint256 reserve1, ) = IPair(pool).getReserves();
if (reserve0 == 0 || reserve1 == 0) revert InvalidPool(pool);
(uint256 reserveIn, uint256 reserveOut) = direction == 1
? (reserve0, reserve1)
: (reserve1, reserve0);
if (amountIn != 0) {
if (from == address(this)) {
IERC20(tokenIn).safeTransfer(pool, amountIn);
} else {
IERC20(tokenIn).safeTransferFrom(from, pool, amountIn);
}
} else {
amountIn = IERC20(tokenIn).balanceOf(pool) - reserveIn; // tokens already were transferred
}
uint256 amountInWithFee = amountIn * 997;
amountOut = (amountInWithFee * reserveOut) / (reserveIn * 1000 + amountInWithFee);
(uint256 amount0Out, uint256 amount1Out) = direction == 1
? (uint256(0), amountOut)
: (amountOut, uint256(0));
IPair(pool).swap(amount0Out, amount1Out, to, new bytes(0));
}
/// @notice UniswapV3 pool swap
/// @param stream [pool, direction, recipient]
/// @param from Where to take liquidity for swap
/// @param tokenIn Input token
/// @param amountIn Amount of tokenIn to take for swap
function _swapUniV3(
uint256 stream,
address from,
address tokenIn,
uint256 amountIn
) private {
address pool = stream.readAddress();
bool zeroForOne = stream.readUint8() > 0;
address recipient = stream.readAddress();
if (from != address(this)) {
if (from != msg.sender) revert UnexpectedAddress(from);
IERC20(tokenIn).safeTransferFrom(msg.sender, address(this), amountIn);
}
lastCalledPool = pool;
IUniswapV3Pool(pool).swap(
recipient,
zeroForOne,
int256(amountIn),
zeroForOne ? Constants.MIN_SQRT_RATIO + 1 : Constants.MAX_SQRT_RATIO - 1,
abi.encode(tokenIn)
);
if (lastCalledPool != Constants.IMPOSSIBLE_POOL_ADDRESS) revert UnexpectedUniV3Swap();
}
/// @notice Called to `msg.sender` after executing a swap via IUniswapV3Pool#swap.
/// @dev In the implementation you must pay the pool tokens owed for the swap.
/// The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical UniswapV3Factory.
/// amount0Delta and amount1Delta can both be 0 if no tokens were swapped.
/// @param amount0Delta The amount of token0 that was sent (negative) or must be received (positive) by the pool by
/// the end of the swap. If positive, the callback must send that amount of token0 to the pool.
/// @param amount1Delta The amount of token1 that was sent (negative) or must be received (positive) by the pool by
/// the end of the swap. If positive, the callback must send that amount of token1 to the pool.
/// @param data Any data passed through by the caller via the IUniswapV3PoolActions#swap call
function uniswapV3SwapCallback(
int256 amount0Delta,
int256 amount1Delta,
bytes calldata data
) external {
if (msg.sender != lastCalledPool) revert UnexpectedUniV3Swap();
lastCalledPool = Constants.IMPOSSIBLE_POOL_ADDRESS;
(address tokenIn) = abi.decode(data, (address));
int256 amount = amount0Delta > 0 ? amount0Delta : amount1Delta;
if (amount <= 0) revert UnexpectedUniV3Swap();
IERC20(tokenIn).safeTransfer(msg.sender, uint256(amount));
}
/// @notice Algebra pool swap
/// @param stream [pool, direction, recipient]
/// @param from Where to take liquidity for swap
/// @param tokenIn Input token
/// @param amountIn Amount of tokenIn to take for swap
function _swapAlgebra(
uint256 stream,
address from,
address tokenIn,
uint256 amountIn
) private {
address pool = stream.readAddress();
bool zeroForOne = stream.readUint8() > 0;
address recipient = stream.readAddress();
if (from != address(this)) {
if (from != msg.sender) revert UnexpectedAddress(from);
IERC20(tokenIn).safeTransferFrom(msg.sender, address(this), amountIn);
}
lastCalledPool = pool;
IAlgebraPool(pool).swap(
recipient,
zeroForOne,
int256(amountIn),
zeroForOne ? Constants.MIN_SQRT_RATIO + 1 : Constants.MAX_SQRT_RATIO - 1,
abi.encode(tokenIn)
);
if (lastCalledPool != Constants.IMPOSSIBLE_POOL_ADDRESS) revert UnexpectedUniV3Swap();
}
/// @notice Called to `msg.sender` after executing a swap via IAlgebraPool#swap.
/// @dev In the implementation you must pay the pool tokens owed for the swap.
/// The caller of this method must be checked to be an AlgebraPool deployed by the canonical AlgebraFactory.
/// amount0Delta and amount1Delta can both be 0 if no tokens were swapped.
/// @param amount0Delta The amount of token0 that was sent (negative) or must be received (positive) by the pool by
/// the end of the swap. If positive, the callback must send that amount of token0 to the pool.
/// @param amount1Delta The amount of token1 that was sent (negative) or must be received (positive) by the pool by
/// the end of the swap. If positive, the callback must send that amount of token1 to the pool.
/// @param data Any data passed through by the caller via the IAlgebraPoolActions#swap call
function algebraSwapCallback(
int256 amount0Delta,
int256 amount1Delta,
bytes calldata data
) external {
if (msg.sender != lastCalledPool) revert UnexpectedAlgebraSwap();
lastCalledPool = Constants.IMPOSSIBLE_POOL_ADDRESS;
(address tokenIn) = abi.decode(data, (address));
int256 amount = amount0Delta > 0 ? amount0Delta : amount1Delta;
if (amount <= 0) revert UnexpectedAlgebraSwap();
IERC20(tokenIn).safeTransfer(msg.sender, uint256(amount));
}
/// @notice Wraps/unwraps native token
/// @param stream [direction & fake, recipient, wrapToken?]
/// @param from Where to take liquidity for swap
/// @param tokenIn Input token
/// @param amountIn Amount of tokenIn to take for swap
function _wrapNative(
uint256 stream,
address from,
address tokenIn,
uint256 amountIn
) private {
uint8 direction = stream.readUint8();
address to = stream.readAddress();
if (direction & 1 == 1) {
address wrapToken = stream.readAddress();
IWETH(wrapToken).deposit{value: amountIn}();
if (to != address(this)) IERC20(wrapToken).safeTransfer(to, amountIn);
} else {
if (from != address(this)) IERC20(tokenIn).safeTransferFrom(from, address(this), amountIn);
IWETH(tokenIn).withdraw(amountIn);
to.safeTransferETH(address(this).balance);
}
}
/// @notice Performs a Zenlink stable pool swap
/// @param stream [isMetaSwap, To, [Pool, Option(isNativePool), TokenInIndex, TokenOutIndex, TokenOut]]
/// @param from Where to take liquidity for swap
/// @param tokenIn Input token
/// @param amountIn Amount of tokenIn to take for swap
function _swapStableSwap(
uint256 stream,
address from,
address tokenIn,
uint256 amountIn
) private {
uint8 isMetaSwap = stream.readUint8();
address to = stream.readAddress();
bytes memory swapData = stream.readBytes();
if (amountIn != 0) {
if (from == address(this)) {
IERC20(tokenIn).safeTransfer(address(stableSwapDispatcher), amountIn);
} else {
IERC20(tokenIn).safeTransferFrom(from, address(stableSwapDispatcher), amountIn);
}
} else {
amountIn = IERC20(tokenIn).balanceOf(address(stableSwapDispatcher)); // tokens already were transferred
}
if (isMetaSwap == 1) {
(address pool, uint8 tokenInIndex, uint8 tokenOutIndex, address tokenOut) = abi.decode(
swapData,
(address, uint8, uint8, address)
);
stableSwapDispatcher.swapUnderlying(pool, tokenInIndex, tokenOutIndex, tokenIn, tokenOut, to);
} else {
(address pool, bool isNativePool, uint8 tokenInIndex, uint8 tokenOutIndex, address tokenOut) = abi.decode(
swapData,
(address, bool, uint8, uint8, address)
);
stableSwapDispatcher.swap(pool, isNativePool, tokenInIndex, tokenOutIndex, tokenIn, tokenOut, to);
}
}
/// @notice Performs a Curve stable pool swap
/// @param stream [isMetaSwap, To, [Pool, Option(isNativePool), TokenInIndex, TokenOutIndex, TokenOut]]
/// @param from Where to take liquidity for swap
/// @param tokenIn Input token
/// @param amountIn Amount of tokenIn to take for swap
function _swapCurveStable(
uint256 stream,
address from,
address tokenIn,
uint256 amountIn
) private {
uint8 isMetaSwap = stream.readUint8();
address to = stream.readAddress();
bytes memory swapData = stream.readBytes();
if (amountIn != 0) {
if (from == address(this)) {
IERC20(tokenIn).safeTransfer(address(curveStableDispatcher), amountIn);
} else {
IERC20(tokenIn).safeTransferFrom(from, address(curveStableDispatcher), amountIn);
}
} else {
amountIn = IERC20(tokenIn).balanceOf(address(curveStableDispatcher)); // tokens already were transferred
}
if (isMetaSwap == 1) {
(address pool, int128 tokenInIndex, int128 tokenOutIndex, address tokenOut) = abi.decode(
swapData,
(address, int128, int128, address)
);
curveStableDispatcher.exchange_underlying(pool, tokenInIndex, tokenOutIndex, tokenIn, tokenOut, to);
} else {
(address pool, bool isNativePool, int128 tokenInIndex, int128 tokenOutIndex, address tokenOut) = abi.decode(
swapData,
(address, bool, int128, int128, address)
);
curveStableDispatcher.exchange(pool, isNativePool, tokenInIndex, tokenOutIndex, tokenIn, tokenOut, to);
}
}
/// @notice GMX vault swap
/// @param stream [tokenOut, receiver]
/// @param from Where to take liquidity for swap
/// @param tokenIn Input token
/// @param amountIn Amount of tokenIn to take for swap
function _swapGmx(
uint256 stream,
address from,
address tokenIn,
uint256 amountIn
) private {
address vault = stream.readAddress();
address tokenOut = stream.readAddress();
address receiver = stream.readAddress();
if (amountIn != 0) {
if (from == address(this)) {
IERC20(tokenIn).safeTransfer(vault, amountIn);
} else {
IERC20(tokenIn).safeTransferFrom(from, vault, amountIn);
}
} else {
amountIn = IERC20(tokenIn).balanceOf(vault) - IVault(vault).tokenBalances(tokenIn); // tokens already were transferred
}
IVault(vault).swap(tokenIn, tokenOut, receiver);
}
/// @notice Trader Joe V2 swap
/// @param stream [pool, swapForY, receiver]
/// @param from Where to take liquidity for swap
/// @param tokenIn Input token
/// @param amountIn Amount of tokenIn to take for swap
function _swapJoeV2(
uint256 stream,
address from,
address tokenIn,
uint256 amountIn
) private {
address pool = stream.readAddress();
bool swapForY = stream.readUint8() > 0;
address recipient = stream.readAddress();
(uint128 reserveX, uint128 reserveY) = ILBPair(pool).getReserves();
if (reserveX == 0 || reserveY == 0) revert InvalidPool(pool);
(uint256 reserveIn, ) = swapForY
? (reserveX, reserveY)
: (reserveY, reserveX);
if (amountIn != 0) {
if (from == address(this)) {
IERC20(tokenIn).safeTransfer(pool, amountIn);
} else {
IERC20(tokenIn).safeTransferFrom(from, pool, amountIn);
}
} else {
amountIn = IERC20(tokenIn).balanceOf(pool) - reserveIn; // tokens already were transferred
}
ILBPair(pool).swap(swapForY, recipient);
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import {SafeTransferLib} from 'lib/solmate/src/utils/SafeTransferLib.sol';
import {IWETH} from "../interfaces/IWETH.sol";
import {IReferralStorage} from "../../referrals/interfaces/IReferralStorage.sol";
import {AdminUpgradeable} from "../../libraries/AdminUpgradeable.sol";
import {IFeeSettlement} from "../interfaces/IFeeSettlement.sol";
import {Constants} from "../../libraries/Constants.sol";
import {IZLKDiscountReader} from "../interfaces/IZLKDiscountReader.sol";
contract FeeSettlement is IFeeSettlement, ReentrancyGuard, AdminUpgradeable {
using SafeERC20 for IERC20;
using SafeTransferLib for address;
address public immutable weth;
uint256 public constant BASIS_POINTS = 10000;
uint256 public constant MAX_FEE_POINTS = 30; // 0.3%
IReferralStorage public referralStorage;
uint256 public feeShare; // e.g. 10 for 0.1%
uint256 public feeDiscount; // e.g. 2000 for 20%
uint256 public feeRebate; // e.g. 5000 for 50%/50%, 2500 for 75% fee/25% rebate
address public feeTo;
IZLKDiscountReader public zlkDiscountReader;
error InvalidFeeShare();
error InvalidFeeDiscount();
error InvalidFeeRebate();
error InsufficientOutAmount();
event PayRebates(
address trader,
address referrer,
address tokenOut,
uint256 discountAmount,
uint256 rebateAmount
);
event SetReferralStorage(IReferralStorage referralStorage);
event SetZLKDiscountReader(IZLKDiscountReader zlkDiscountReader);
event SetFeeShare(uint256 feeShare);
event SetFeeDiscount(uint256 feeDiscount);
event SetFeeRebate(uint256 feeRebate);
event SetFeeTo(address feeTo);
constructor(
address _weth,
IReferralStorage _referralStorage,
uint256 _feeShare,
uint256 _feeDiscount,
uint256 _feeRebate,
address _feeTo
) {
weth = _weth;
referralStorage = _referralStorage;
if (_feeShare > MAX_FEE_POINTS) revert InvalidFeeShare();
if (_feeDiscount > BASIS_POINTS) revert InvalidFeeDiscount();
if (_feeRebate > BASIS_POINTS) revert InvalidFeeRebate();
feeShare = _feeShare;
feeDiscount = _feeDiscount;
feeRebate = _feeRebate;
feeTo = _feeTo;
_initializeAdmin(msg.sender);
}
/// @notice To receive ETH from router
receive() external payable {}
/// @notice Executes the fee settlement, including pay referrer rebates
/// @param tokenOut Address of the output token
/// @param amountOutMin Minimum amount of the output token
/// @param from Trader address
/// @param to Receiver address
function processSettlement(
address tokenOut,
uint256 amountOutMin,
address from,
address to
) external override nonReentrant {
bool isNative = tokenOut == Constants.NATIVE_ADDRESS;
uint256 amount = isNative
? address(this).balance
: IERC20(tokenOut).balanceOf(address(this));
if (amount < amountOutMin) revert InsufficientOutAmount();
(, address referrer) = referralStorage.getReferralInfo(from);
uint256 basisfee = (amount * feeShare) / BASIS_POINTS;
if (address(zlkDiscountReader) != address(0)) {
(uint256 zlkdiscount, uint256 basis) = zlkDiscountReader.getZLKDiscount(from);
basisfee = (basisfee * (basis - zlkdiscount)) / basis;
}
uint256 fee = referrer == address(0)
? basisfee
: (basisfee * (BASIS_POINTS - feeDiscount)) / BASIS_POINTS;
if (amount - fee < amountOutMin) {
// ensure that fee do not cause the transaction to fail
fee = amount - amountOutMin;
}
if (referrer != address(0)) {
uint256 rebateAmount = (fee * feeRebate) / BASIS_POINTS;
if (isNative) {
IWETH(weth).deposit{value: fee}();
IERC20(weth).safeTransfer(referrer, rebateAmount);
IERC20(weth).safeTransfer(feeTo, IERC20(weth).balanceOf(address(this)));
} else {
IERC20(tokenOut).safeTransfer(referrer, rebateAmount);
IERC20(tokenOut).safeTransfer(feeTo, fee - rebateAmount);
}
emit PayRebates(from, referrer, tokenOut, basisfee - fee, rebateAmount);
} else {
if (isNative) {
IWETH(weth).deposit{value: fee}();
IERC20(weth).safeTransfer(feeTo, IERC20(weth).balanceOf(address(this)));
} else {
IERC20(tokenOut).safeTransfer(feeTo, fee);
}
}
if (isNative) {
to.safeTransferETH(amount - fee);
} else {
IERC20(tokenOut).safeTransfer(to, amount - fee);
}
}
// @notice Set referralStorage by admin
/// @param _referralStorage ReferralStorage address
function setReferralStorage(IReferralStorage _referralStorage) external onlyAdmin {
referralStorage = _referralStorage;
emit SetReferralStorage(_referralStorage);
}
// @notice Set zlkDiscountReader by admin
/// @param _zlkDiscountReader ZLKDiscountReader address
function setZLKDiscountReader(IZLKDiscountReader _zlkDiscountReader) external onlyAdmin {
zlkDiscountReader = _zlkDiscountReader;
emit SetZLKDiscountReader(_zlkDiscountReader);
}
/// @notice Set feeShare by admin
/// @param _feeShare Percent of fee
function setFeeShare(uint256 _feeShare) external onlyAdmin {
if (_feeShare > MAX_FEE_POINTS) revert InvalidFeeShare();
feeShare = _feeShare;
emit SetFeeShare(_feeShare);
}
/// @notice Set feeDicount by admin
/// @param _feeDiscount Percent of feeDiscount
function setFeeDiscount(uint256 _feeDiscount) external onlyAdmin {
if (_feeDiscount > BASIS_POINTS) revert InvalidFeeDiscount();
feeDiscount = _feeDiscount;
emit SetFeeDiscount(_feeDiscount);
}
/// @notice Set feeRebate by admin
/// @param _feeRebate Percent of feeRebate
function setFeeRebate(uint256 _feeRebate) external onlyAdmin {
if (_feeRebate > BASIS_POINTS) revert InvalidFeeRebate();
feeRebate = _feeRebate;
emit SetFeeRebate(_feeRebate);
}
/// @notice Set feeTo by admin
/// @param _feeTo FeeTo address
function setFeeTo(address _feeTo) external onlyAdmin {
feeTo = _feeTo;
emit SetFeeTo(_feeTo);
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
interface IWETH {
function deposit() external payable;
function transfer(address to, uint256 value) external returns (bool);
function withdraw(uint256) external;
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
interface IReferralStorage {
function codeOwners(bytes32 _code) external view returns (address);
function getReferralInfo(address _account) external view returns (bytes32, address);
function getOwnedCodes(address _account) external view returns (bytes32[] memory);
function setReferralCodeByUser(bytes32 _code) external;
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
abstract contract AdminUpgradeable {
address public admin;
address public adminCandidate;
function _initializeAdmin(address _admin) internal {
require(admin == address(0), "admin already set");
admin = _admin;
}
function candidateConfirm() external {
require(msg.sender == adminCandidate, "not Candidate");
emit AdminChanged(admin, adminCandidate);
admin = adminCandidate;
adminCandidate = address(0);
}
function setAdminCandidate(address _candidate) external onlyAdmin {
adminCandidate = _candidate;
emit Candidate(_candidate);
}
modifier onlyAdmin {
require(msg.sender == admin, "not admin");
_;
}
event Candidate(address indexed newAdmin);
event AdminChanged(address indexed oldAdmin, address indexed newAdmin);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
interface IFeeSettlement {
function processSettlement(address tokenOut, uint256 amountOutMin, address from, address to) external;
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
library Constants {
/// @dev Used as a flag for identifying the transfer of ETH instead of a token
address internal constant NATIVE_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
/// @dev Used as a impossible pool address
address internal constant IMPOSSIBLE_POOL_ADDRESS = 0x0000000000000000000000000000000000000001;
/// @dev The minimum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MIN_TICK)
uint160 internal constant MIN_SQRT_RATIO = 4295128739;
/// @dev The maximum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MAX_TICK)
uint160 internal constant MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342;
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
interface IZLKDiscountReader {
function getZLKDiscount(address user) external view returns (uint256 discount, uint256 basis);
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
import {ERC20} from "../tokens/ERC20.sol";
/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer.
/// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller.
library SafeTransferLib {
/*//////////////////////////////////////////////////////////////
ETH OPERATIONS
//////////////////////////////////////////////////////////////*/
function safeTransferETH(address to, uint256 amount) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Transfer the ETH and store if it succeeded or not.
success := call(gas(), to, amount, 0, 0, 0, 0)
}
require(success, "ETH_TRANSFER_FAILED");
}
/*//////////////////////////////////////////////////////////////
ERC20 OPERATIONS
//////////////////////////////////////////////////////////////*/
function safeTransferFrom(
ERC20 token,
address from,
address to,
uint256 amount
) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Get a pointer to some free memory.
let freeMemoryPointer := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.
mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), from) // Append the "from" argument.
mstore(add(freeMemoryPointer, 36), to) // Append the "to" argument.
mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument.
success := and(
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data.
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
// We use 100 because the length of our calldata totals up like so: 4 + 32 * 3.
// We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
// Counterintuitively, this call must be positioned second to the or() call in the
// surrounding and() call or else returndatasize() will be zero during the computation.
call(gas(), token, 0, freeMemoryPointer, 100, 0, 32)
)
}
require(success, "TRANSFER_FROM_FAILED");
}
function safeTransfer(
ERC20 token,
address to,
uint256 amount
) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Get a pointer to some free memory.
let freeMemoryPointer := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.
mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument.
mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument.
success := and(
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data.
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
// We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
// We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
// Counterintuitively, this call must be positioned second to the or() call in the
// surrounding and() call or else returndatasize() will be zero during the computation.
call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
)
}
require(success, "TRANSFER_FAILED");
}
function safeApprove(
ERC20 token,
address to,
uint256 amount
) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Get a pointer to some free memory.
let freeMemoryPointer := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.
mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument.
mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument.
success := and(
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data.
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
// We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
// We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
// Counterintuitively, this call must be positioned second to the or() call in the
// surrounding and() call or else returndatasize() will be zero during the computation.
call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
)
}
require(success, "APPROVE_FAILED");
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
// On the first call to nonReentrant, _notEntered will be true
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
_;
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
}// 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: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/draft-IERC20Permit.sol";
import "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(
IERC20 token,
address spender,
uint256 value
) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
// Return data is optional
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}// SPDX-License-Identifier: 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 (last updated v4.7.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
library InputStream {
function createStream(bytes memory data) internal pure returns (uint256 stream) {
assembly {
stream := mload(0x40)
mstore(0x40, add(stream, 64))
mstore(stream, data)
let length := mload(data)
mstore(add(stream, 32), add(data, length))
}
}
function isNotEmpty(uint256 stream) internal pure returns (bool) {
uint256 pos;
uint256 finish;
assembly {
pos := mload(stream)
finish := mload(add(stream, 32))
}
return pos < finish;
}
function readUint8(uint256 stream) internal pure returns (uint8 res) {
assembly {
let pos := mload(stream)
pos := add(pos, 1)
res := mload(pos)
mstore(stream, pos)
}
}
function readUint16(uint256 stream) internal pure returns (uint16 res) {
assembly {
let pos := mload(stream)
pos := add(pos, 2)
res := mload(pos)
mstore(stream, pos)
}
}
function readUint32(uint256 stream) internal pure returns (uint32 res) {
assembly {
let pos := mload(stream)
pos := add(pos, 4)
res := mload(pos)
mstore(stream, pos)
}
}
function readUint(uint256 stream) internal pure returns (uint256 res) {
assembly {
let pos := mload(stream)
pos := add(pos, 32)
res := mload(pos)
mstore(stream, pos)
}
}
function readAddress(uint256 stream) internal pure returns (address res) {
assembly {
let pos := mload(stream)
pos := add(pos, 20)
res := mload(pos)
mstore(stream, pos)
}
}
function readBytes(uint256 stream) internal pure returns (bytes memory res) {
assembly {
let pos := mload(stream)
res := add(pos, 32)
let length := mload(res)
mstore(stream, add(res, length))
}
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
interface IPair {
event Mint(address indexed sender, uint256 amount0, uint256 amount1);
event Burn(
address indexed sender,
uint256 amount0,
uint256 amount1,
address indexed to
);
event Swap(
address indexed sender,
uint256 amount0In,
uint256 amount1In,
uint256 amount0Out,
uint256 amount1Out,
address indexed to
);
event Sync(uint112 reserve0, uint112 reserve1);
function MINIMUM_LIQUIDITY() external pure returns (uint256);
function factory() external view returns (address);
function token0() external view returns (address);
function token1() external view returns (address);
function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
function price0CumulativeLast() external view returns (uint256);
function price1CumulativeLast() external view returns (uint256);
function kLast() external view returns (uint256);
function mint(address to) external returns (uint256 liquidity);
function burn(address to)
external
returns (uint256 amount0, uint256 amount1);
function swap(uint256 amount0Out, uint256 amount1Out, address to, bytes calldata data) external;
function skim(address to) external;
function sync() external;
function initialize(address, address) external;
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
interface IStableSwapDispatcher {
function swap(
address pool,
bool isNativePool,
uint8 tokenInIndex,
uint8 tokenOutIndex,
address tokenIn,
address tokenOut,
address to
) external;
function swapUnderlying(
address pool,
uint8 tokenInIndex,
uint8 tokenOutIndex,
address tokenIn,
address tokenOut,
address to
) external;
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
import {IUniswapV3PoolImmutables} from "./IUniswapV3PoolImmutables.sol";
import {IUniswapV3PoolState} from "./IUniswapV3PoolState.sol";
import {IUniswapV3PoolActions} from "./IUniswapV3PoolActions.sol";
/// @title The interface for a Uniswap V3 Pool
/// @notice A Uniswap pool facilitates swapping and automated market making between any two assets that strictly conform
/// to the ERC20 specification
/// @dev The pool interface is broken up into many smaller pieces
// solhint-disable-next-line no-empty-blocks
interface IUniswapV3Pool is
IUniswapV3PoolImmutables,
IUniswapV3PoolState,
IUniswapV3PoolActions
{
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
import {IAlgebraPoolState} from './IAlgebraPoolState.sol';
import {IAlgebraPoolActions} from './IAlgebraPoolActions.sol';
import {IAlgebraPoolImmutables} from "./IAlgebraPoolImmutables.sol";
/**
* @title The interface for a Algebra Pool
* @dev The pool interface is broken up into many smaller pieces.
* Credit to Uniswap Labs under GPL-2.0-or-later license:
* https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces
*/
interface IAlgebraPool is
IAlgebraPoolState,
IAlgebraPoolActions,
IAlgebraPoolImmutables
{
// used only for combining interfaces
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
import {IVaultUtils} from "./IVaultUtils.sol";
interface IVault {
function isInitialized() external view returns (bool);
function isSwapEnabled() external view returns (bool);
function isLeverageEnabled() external view returns (bool);
function setVaultUtils(IVaultUtils _vaultUtils) external;
function setError(uint256 _errorCode, string calldata _error) external;
function router() external view returns (address);
function usdg() external view returns (address);
function gov() external view returns (address);
function whitelistedTokenCount() external view returns (uint256);
function maxLeverage() external view returns (uint256);
function minProfitTime() external view returns (uint256);
function hasDynamicFees() external view returns (bool);
function fundingInterval() external view returns (uint256);
function totalTokenWeights() external view returns (uint256);
function getTargetUsdgAmount(address _token) external view returns (uint256);
function inManagerMode() external view returns (bool);
function inPrivateLiquidationMode() external view returns (bool);
function maxGasPrice() external view returns (uint256);
function approvedRouters(address _account, address _router) external view returns (bool);
function isLiquidator(address _account) external view returns (bool);
function isManager(address _account) external view returns (bool);
function minProfitBasisPoints(address _token) external view returns (uint256);
function tokenBalances(address _token) external view returns (uint256);
function lastFundingTimes(address _token) external view returns (uint256);
function setMaxLeverage(uint256 _maxLeverage) external;
function setInManagerMode(bool _inManagerMode) external;
function setManager(address _manager, bool _isManager) external;
function setIsSwapEnabled(bool _isSwapEnabled) external;
function setIsLeverageEnabled(bool _isLeverageEnabled) external;
function setMaxGasPrice(uint256 _maxGasPrice) external;
function setUsdgAmount(address _token, uint256 _amount) external;
function setBufferAmount(address _token, uint256 _amount) external;
function setMaxGlobalShortSize(address _token, uint256 _amount) external;
function setInPrivateLiquidationMode(bool _inPrivateLiquidationMode) external;
function setLiquidator(address _liquidator, bool _isActive) external;
function setFundingRate(uint256 _fundingInterval, uint256 _fundingRateFactor, uint256 _stableFundingRateFactor) external;
function setFees(
uint256 _taxBasisPoints,
uint256 _stableTaxBasisPoints,
uint256 _mintBurnFeeBasisPoints,
uint256 _swapFeeBasisPoints,
uint256 _stableSwapFeeBasisPoints,
uint256 _marginFeeBasisPoints,
uint256 _liquidationFeeUsd,
uint256 _minProfitTime,
bool _hasDynamicFees
) external;
function setTokenConfig(
address _token,
uint256 _tokenDecimals,
uint256 _redemptionBps,
uint256 _minProfitBps,
uint256 _maxUsdgAmount,
bool _isStable,
bool _isShortable
) external;
function setPriceFeed(address _priceFeed) external;
function withdrawFees(address _token, address _receiver) external returns (uint256);
function directPoolDeposit(address _token) external;
function buyUSDG(address _token, address _receiver) external returns (uint256);
function sellUSDG(address _token, address _receiver) external returns (uint256);
function swap(address _tokenIn, address _tokenOut, address _receiver) external returns (uint256);
function increasePosition(address _account, address _collateralToken, address _indexToken, uint256 _sizeDelta, bool _isLong) external;
function decreasePosition(address _account, address _collateralToken, address _indexToken, uint256 _collateralDelta, uint256 _sizeDelta, bool _isLong, address _receiver) external returns (uint256);
function validateLiquidation(address _account, address _collateralToken, address _indexToken, bool _isLong, bool _raise) external view returns (uint256, uint256);
function liquidatePosition(address _account, address _collateralToken, address _indexToken, bool _isLong, address _feeReceiver) external;
function tokenToUsdMin(address _token, uint256 _tokenAmount) external view returns (uint256);
function priceFeed() external view returns (address);
function fundingRateFactor() external view returns (uint256);
function stableFundingRateFactor() external view returns (uint256);
function cumulativeFundingRates(address _token) external view returns (uint256);
function getNextFundingRate(address _token) external view returns (uint256);
function getFeeBasisPoints(address _token, uint256 _usdgDelta, uint256 _feeBasisPoints, uint256 _taxBasisPoints, bool _increment) external view returns (uint256);
function liquidationFeeUsd() external view returns (uint256);
function taxBasisPoints() external view returns (uint256);
function stableTaxBasisPoints() external view returns (uint256);
function mintBurnFeeBasisPoints() external view returns (uint256);
function swapFeeBasisPoints() external view returns (uint256);
function stableSwapFeeBasisPoints() external view returns (uint256);
function marginFeeBasisPoints() external view returns (uint256);
function allWhitelistedTokensLength() external view returns (uint256);
function allWhitelistedTokens(uint256) external view returns (address);
function whitelistedTokens(address _token) external view returns (bool);
function stableTokens(address _token) external view returns (bool);
function shortableTokens(address _token) external view returns (bool);
function feeReserves(address _token) external view returns (uint256);
function globalShortSizes(address _token) external view returns (uint256);
function globalShortAveragePrices(address _token) external view returns (uint256);
function maxGlobalShortSizes(address _token) external view returns (uint256);
function tokenDecimals(address _token) external view returns (uint256);
function tokenWeights(address _token) external view returns (uint256);
function guaranteedUsd(address _token) external view returns (uint256);
function poolAmounts(address _token) external view returns (uint256);
function bufferAmounts(address _token) external view returns (uint256);
function reservedAmounts(address _token) external view returns (uint256);
function usdgAmounts(address _token) external view returns (uint256);
function maxUsdgAmounts(address _token) external view returns (uint256);
function getRedemptionAmount(address _token, uint256 _usdgAmount) external view returns (uint256);
function getMaxPrice(address _token) external view returns (uint256);
function getMinPrice(address _token) external view returns (uint256);
function getDelta(address _indexToken, uint256 _size, uint256 _averagePrice, bool _isLong, uint256 _lastIncreasedTime) external view returns (bool, uint256);
function getPosition(address _account, address _collateralToken, address _indexToken, bool _isLong) external view returns (uint256, uint256, uint256, uint256, uint256, uint256, bool, uint256);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {ILBFactory} from "./ILBFactory.sol";
import {ILBFlashLoanCallback} from "./ILBFlashLoanCallback.sol";
import {ILBToken} from "./ILBToken.sol";
interface ILBPair is ILBToken {
error LBPair__ZeroBorrowAmount();
error LBPair__AddressZero();
error LBPair__AlreadyInitialized();
error LBPair__EmptyMarketConfigs();
error LBPair__FlashLoanCallbackFailed();
error LBPair__FlashLoanInsufficientAmount();
error LBPair__InsufficientAmountIn();
error LBPair__InsufficientAmountOut();
error LBPair__InvalidInput();
error LBPair__InvalidStaticFeeParameters();
error LBPair__OnlyFactory();
error LBPair__OnlyProtocolFeeRecipient();
error LBPair__OutOfLiquidity();
error LBPair__TokenNotSupported();
error LBPair__ZeroAmount(uint24 id);
error LBPair__ZeroAmountsOut(uint24 id);
error LBPair__ZeroShares(uint24 id);
error LBPair__MaxTotalFeeExceeded();
struct MintArrays {
uint256[] ids;
bytes32[] amounts;
uint256[] liquidityMinted;
}
event DepositedToBins(address indexed sender, address indexed to, uint256[] ids, bytes32[] amounts);
event WithdrawnFromBins(address indexed sender, address indexed to, uint256[] ids, bytes32[] amounts);
event CompositionFees(address indexed sender, uint24 id, bytes32 totalFees, bytes32 protocolFees);
event CollectedProtocolFees(address indexed feeRecipient, bytes32 protocolFees);
event Swap(
address indexed sender,
address indexed to,
uint24 id,
bytes32 amountsIn,
bytes32 amountsOut,
uint24 volatilityAccumulator,
bytes32 totalFees,
bytes32 protocolFees
);
event StaticFeeParametersSet(
address indexed sender,
uint16 baseFactor,
uint16 filterPeriod,
uint16 decayPeriod,
uint16 reductionFactor,
uint24 variableFeeControl,
uint16 protocolShare,
uint24 maxVolatilityAccumulator
);
event FlashLoan(
address indexed sender,
ILBFlashLoanCallback indexed receiver,
uint24 activeId,
bytes32 amounts,
bytes32 totalFees,
bytes32 protocolFees
);
event OracleLengthIncreased(address indexed sender, uint16 oracleLength);
event ForcedDecay(address indexed sender, uint24 idReference, uint24 volatilityReference);
function initialize(
uint16 baseFactor,
uint16 filterPeriod,
uint16 decayPeriod,
uint16 reductionFactor,
uint24 variableFeeControl,
uint16 protocolShare,
uint24 maxVolatilityAccumulator,
uint24 activeId
) external;
function getFactory() external view returns (ILBFactory factory);
function getTokenX() external view returns (IERC20 tokenX);
function getTokenY() external view returns (IERC20 tokenY);
function getBinStep() external view returns (uint16 binStep);
function getReserves() external view returns (uint128 reserveX, uint128 reserveY);
function getActiveId() external view returns (uint24 activeId);
function getBin(uint24 id) external view returns (uint128 binReserveX, uint128 binReserveY);
function getNextNonEmptyBin(bool swapForY, uint24 id) external view returns (uint24 nextId);
function getProtocolFees() external view returns (uint128 protocolFeeX, uint128 protocolFeeY);
function getStaticFeeParameters()
external
view
returns (
uint16 baseFactor,
uint16 filterPeriod,
uint16 decayPeriod,
uint16 reductionFactor,
uint24 variableFeeControl,
uint16 protocolShare,
uint24 maxVolatilityAccumulator
);
function getVariableFeeParameters()
external
view
returns (uint24 volatilityAccumulator, uint24 volatilityReference, uint24 idReference, uint40 timeOfLastUpdate);
function getOracleParameters()
external
view
returns (uint8 sampleLifetime, uint16 size, uint16 activeSize, uint40 lastUpdated, uint40 firstTimestamp);
function getOracleSampleAt(uint40 lookupTimestamp)
external
view
returns (uint64 cumulativeId, uint64 cumulativeVolatility, uint64 cumulativeBinCrossed);
function getPriceFromId(uint24 id) external view returns (uint256 price);
function getIdFromPrice(uint256 price) external view returns (uint24 id);
function getSwapIn(uint128 amountOut, bool swapForY)
external
view
returns (uint128 amountIn, uint128 amountOutLeft, uint128 fee);
function getSwapOut(uint128 amountIn, bool swapForY)
external
view
returns (uint128 amountInLeft, uint128 amountOut, uint128 fee);
function swap(bool swapForY, address to) external returns (bytes32 amountsOut);
function flashLoan(ILBFlashLoanCallback receiver, bytes32 amounts, bytes calldata data) external;
function mint(address to, bytes32[] calldata liquidityConfigs, address refundTo)
external
returns (bytes32 amountsReceived, bytes32 amountsLeft, uint256[] memory liquidityMinted);
function burn(address from, address to, uint256[] calldata ids, uint256[] calldata amountsToBurn)
external
returns (bytes32[] memory amounts);
function collectProtocolFees() external returns (bytes32 collectedProtocolFees);
function increaseOracleLength(uint16 newLength) external;
function setStaticFeeParameters(
uint16 baseFactor,
uint16 filterPeriod,
uint16 decayPeriod,
uint16 reductionFactor,
uint24 variableFeeControl,
uint16 protocolShare,
uint24 maxVolatilityAccumulator
) external;
function forceDecay() external;
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
interface ICurveStableDispatcher {
function exchange(
address pool,
bool isNativePool,
int128 tokenInIndex,
int128 tokenOutIndex,
address tokenIn,
address tokenOut,
address to
) external;
function exchange_underlying(
address pool,
int128 tokenInIndex,
int128 tokenOutIndex,
address tokenIn,
address tokenOut,
address to
) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract Pausable is Context {
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
bool private _paused;
/**
* @dev Initializes the contract in unpaused state.
*/
constructor() {
_paused = false;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
_requirePaused();
_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
return _paused;
}
/**
* @dev Throws if the contract is paused.
*/
function _requireNotPaused() internal view virtual {
require(!paused(), "Pausable: paused");
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
require(paused(), "Pausable: not paused");
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.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);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
/// @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
/// 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.
/// observationIndex The index of the last oracle observation that was written,
/// observationCardinality The current maximum number of observations stored in the pool,
/// observationCardinalityNext The next maximum number of observations, to be updated when the observation.
/// 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
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,
/// liquidityNet how much liquidity changes when the pool price crosses the tick,
/// feeGrowthOutside0X128 the fee growth on the other side of the tick from the current tick in token0,
/// feeGrowthOutside1X128 the fee growth on the other side of the tick from the current tick in token1,
/// tickCumulativeOutside the cumulative tick value on the other side of the tick from the current tick
/// secondsPerLiquidityOutsideX128 the seconds spent per liquidity on the other side of the tick from the current tick,
/// secondsOutside the seconds spent on the other side of the tick from the current tick,
/// 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,
/// Returns feeGrowthInside0LastX128 fee growth of token0 inside the tick range as of the last mint/burn/poke,
/// Returns feeGrowthInside1LastX128 fee growth of token1 inside the tick range as of the last mint/burn/poke,
/// Returns tokensOwed0 the computed amount of token0 owed to the position as of the last mint/burn/poke,
/// Returns 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,
/// Returns tickCumulative the tick multiplied by seconds elapsed for the life of the pool as of the observation timestamp,
/// Returns secondsPerLiquidityCumulativeX128 the seconds per in range liquidity for the life of the pool as of the observation timestamp,
/// Returns 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
);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
/// @title Permissionless pool actions
/// @notice Contains pool methods that can be called by anyone
interface IUniswapV3PoolActions {
/// @notice Sets the initial price for the pool
/// @dev Price is represented as a sqrt(amountToken1/amountToken0) Q64.96 value
/// @param sqrtPriceX96 the initial sqrt price of the pool as a Q64.96
function initialize(uint160 sqrtPriceX96) external;
/// @notice Adds liquidity for the given recipient/tickLower/tickUpper position
/// @dev The caller of this method receives a callback in the form of IUniswapV3MintCallback#uniswapV3MintCallback
/// in which they must pay any token0 or token1 owed for the liquidity. The amount of token0/token1 due depends
/// on tickLower, tickUpper, the amount of liquidity, and the current price.
/// @param recipient The address for which the liquidity will be created
/// @param tickLower The lower tick of the position in which to add liquidity
/// @param tickUpper The upper tick of the position in which to add liquidity
/// @param amount The amount of liquidity to mint
/// @param data Any data that should be passed through to the callback
/// @return amount0 The amount of token0 that was paid to mint the given amount of liquidity. Matches the value in the callback
/// @return amount1 The amount of token1 that was paid to mint the given amount of liquidity. Matches the value in the callback
function mint(
address recipient,
int24 tickLower,
int24 tickUpper,
uint128 amount,
bytes calldata data
) external returns (uint256 amount0, uint256 amount1);
/// @notice Collects tokens owed to a position
/// @dev Does not recompute fees earned, which must be done either via mint or burn of any amount of liquidity.
/// Collect must be called by the position owner. To withdraw only token0 or only token1, amount0Requested or
/// amount1Requested may be set to zero. To withdraw all tokens owed, caller may pass any value greater than the
/// actual tokens owed, e.g. type(uint128).max. Tokens owed may be from accumulated swap fees or burned liquidity.
/// @param recipient The address which should receive the fees collected
/// @param tickLower The lower tick of the position for which to collect fees
/// @param tickUpper The upper tick of the position for which to collect fees
/// @param amount0Requested How much token0 should be withdrawn from the fees owed
/// @param amount1Requested How much token1 should be withdrawn from the fees owed
/// @return amount0 The amount of fees collected in token0
/// @return amount1 The amount of fees collected in token1
function collect(
address recipient,
int24 tickLower,
int24 tickUpper,
uint128 amount0Requested,
uint128 amount1Requested
) external returns (uint128 amount0, uint128 amount1);
/// @notice Burn liquidity from the sender and account tokens owed for the liquidity to the position
/// @dev Can be used to trigger a recalculation of fees owed to a position by calling with an amount of 0
/// @dev Fees must be collected separately via a call to #collect
/// @param tickLower The lower tick of the position for which to burn liquidity
/// @param tickUpper The upper tick of the position for which to burn liquidity
/// @param amount How much liquidity to burn
/// @return amount0 The amount of token0 sent to the recipient
/// @return amount1 The amount of token1 sent to the recipient
function burn(
int24 tickLower,
int24 tickUpper,
uint128 amount
) external returns (uint256 amount0, uint256 amount1);
/// @notice Swap token0 for token1, or token1 for token0
/// @dev The caller of this method receives a callback in the form of IUniswapV3SwapCallback#uniswapV3SwapCallback
/// @param recipient The address to receive the output of the swap
/// @param zeroForOne The direction of the swap, true for token0 to token1, false for token1 to token0
/// @param amountSpecified The amount of the swap, which implicitly configures the swap as exact input (positive), or exact output (negative)
/// @param sqrtPriceLimitX96 The Q64.96 sqrt price limit. If zero for one, the price cannot be less than this
/// value after the swap. If one for zero, the price cannot be greater than this value after the swap
/// @param data Any data to be passed through to the callback
/// @return amount0 The delta of the balance of token0 of the pool, exact when negative, minimum when positive
/// @return amount1 The delta of the balance of token1 of the pool, exact when negative, minimum when positive
function swap(
address recipient,
bool zeroForOne,
int256 amountSpecified,
uint160 sqrtPriceLimitX96,
bytes calldata data
) external returns (int256 amount0, int256 amount1);
/// @notice Receive token0 and/or token1 and pay it back, plus a fee, in the callback
/// @dev The caller of this method receives a callback in the form of IUniswapV3FlashCallback#uniswapV3FlashCallback
/// @dev Can be used to donate underlying tokens pro-rata to currently in-range liquidity providers by calling
/// with 0 amount{0,1} and sending the donation amount(s) from the callback
/// @param recipient The address which will receive the token0 and token1 amounts
/// @param amount0 The amount of token0 to send
/// @param amount1 The amount of token1 to send
/// @param data Any data to be passed through to the callback
function flash(
address recipient,
uint256 amount0,
uint256 amount1,
bytes calldata data
) external;
/// @notice Increase the maximum number of price and liquidity observations that this pool will store
/// @dev This method is no-op if the pool already has an observationCardinalityNext greater than or equal to
/// the input observationCardinalityNext.
/// @param observationCardinalityNext The desired minimum number of observations for the pool to store
function increaseObservationCardinalityNext(uint16 observationCardinalityNext) external;
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
/// @title Pool state that can change
interface IAlgebraPoolState {
/**
* @notice The globalState structure in the pool stores many values but requires only one slot
* and is exposed as a single method to save gas when accessed externally.
* @return price The current price of the pool as a sqrt(token1/token0) Q64.96 value;
* Returns tick The current tick of the pool, i.e. according to the last tick transition that was run;
* Returns This value may not always be equal to SqrtTickMath.getTickAtSqrtRatio(price) if the price is on a tick
* boundary;
* Returns fee The last pool fee value in hundredths of a bip, i.e. 1e-6;
* Returns timepointIndex The index of the last written timepoint;
* Returns communityFeeToken0 The community fee percentage of the swap fee in thousandths (1e-3) for token0;
* Returns communityFeeToken1 The community fee percentage of the swap fee in thousandths (1e-3) for token1;
* Returns unlocked Whether the pool is currently locked to reentrancy;
*/
function globalState()
external
view
returns (
uint160 price,
int24 tick,
uint16 fee,
uint16 timepointIndex,
uint8 communityFeeToken0,
uint8 communityFeeToken1,
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 totalFeeGrowth0Token() 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 totalFeeGrowth1Token() external view returns (uint256);
/**
* @notice The currently in range liquidity available to the pool
* @dev This value has no relationship to the total liquidity across all ticks.
* Returned value cannot exceed type(uint128).max
*/
function liquidity() external view returns (uint128);
/**
* @notice Look up information about a specific tick in the pool
* @dev This is a public structure, so the `return` natspec tags are omitted.
* @param tick The tick to look up
* @return liquidityTotal the total amount of position liquidity that uses the pool either as tick lower or
* tick upper;
* Returns liquidityDelta how much liquidity changes when the pool price crosses the tick;
* Returns outerFeeGrowth0Token the fee growth on the other side of the tick from the current tick in token0;
* Returns outerFeeGrowth1Token the fee growth on the other side of the tick from the current tick in token1;
* Returns outerTickCumulative the cumulative tick value on the other side of the tick from the current tick;
* Returns outerSecondsPerLiquidity the seconds spent per liquidity on the other side of the tick from the current tick;
* Returns outerSecondsSpent the seconds spent on the other side of the tick from the current tick;
* Returns initialized Set to true if the tick is initialized, i.e. liquidityTotal is greater than 0
* otherwise equal to false. Outside values can only be used if the tick is initialized.
* 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 liquidityTotal,
int128 liquidityDelta,
uint256 outerFeeGrowth0Token,
uint256 outerFeeGrowth1Token,
int56 outerTickCumulative,
uint160 outerSecondsPerLiquidity,
uint32 outerSecondsSpent,
bool initialized
);
/** @notice Returns 256 packed tick initialized boolean values. See TickTable for more information */
function tickTable(int16 wordPosition) external view returns (uint256);
/**
* @notice Returns the information about a position by the position's key
* @dev This is a public mapping of structures, so the `return` natspec tags are omitted.
* @param key The position's key is a hash of a preimage composed by the owner, bottomTick and topTick
* @return liquidityAmount The amount of liquidity in the position;
* Returns lastLiquidityAddTimestamp Timestamp of last adding of liquidity;
* Returns innerFeeGrowth0Token Fee growth of token0 inside the tick range as of the last mint/burn/poke;
* Returns innerFeeGrowth1Token Fee growth of token1 inside the tick range as of the last mint/burn/poke;
* Returns fees0 The computed amount of token0 owed to the position as of the last mint/burn/poke;
* Returns fees1 The computed amount of token1 owed to the position as of the last mint/burn/poke
*/
function positions(bytes32 key)
external
view
returns (
uint128 liquidityAmount,
uint32 lastLiquidityAddTimestamp,
uint256 innerFeeGrowth0Token,
uint256 innerFeeGrowth1Token,
uint128 fees0,
uint128 fees1
);
/**
* @notice Returns data about a specific timepoint index
* @param index The element of the timepoints array to fetch
* @dev You most likely want to use #getTimepoints() instead of this method to get an timepoint as of some amount of time
* ago, rather than at a specific index in the array.
* This is a public mapping of structures, so the `return` natspec tags are omitted.
* @return initialized whether the timepoint has been initialized and the values are safe to use;
* Returns blockTimestamp The timestamp of the timepoint;
* Returns tickCumulative the tick multiplied by seconds elapsed for the life of the pool as of the timepoint timestamp;
* Returns secondsPerLiquidityCumulative the seconds per in range liquidity for the life of the pool as of the timepoint timestamp;
* Returns volatilityCumulative Cumulative standard deviation for the life of the pool as of the timepoint timestamp;
* Returns averageTick Time-weighted average tick;
* Returns volumePerLiquidityCumulative Cumulative swap volume per liquidity for the life of the pool as of the timepoint timestamp;
*/
function timepoints(uint256 index)
external
view
returns (
bool initialized,
uint32 blockTimestamp,
int56 tickCumulative,
uint160 secondsPerLiquidityCumulative,
uint88 volatilityCumulative,
int24 averageTick,
uint144 volumePerLiquidityCumulative
);
/**
* @notice Returns the information about active incentive
* @dev if there is no active incentive at the moment, virtualPool,endTimestamp,startTimestamp would be equal to 0
* @return virtualPool The address of a virtual pool associated with the current active incentive
*/
function activeIncentive() external view returns (address virtualPool);
/**
* @notice Returns the lock time for added liquidity
*/
function liquidityCooldown() external view returns (uint32 cooldownInSeconds);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
/// @title Permissionless pool actions
interface IAlgebraPoolActions {
/**
* @notice Sets the initial price for the pool
* @dev Price is represented as a sqrt(amountToken1/amountToken0) Q64.96 value
* @param price the initial sqrt price of the pool as a Q64.96
*/
function initialize(uint160 price) external;
/**
* @notice Adds liquidity for the given recipient/bottomTick/topTick position
* @dev The caller of this method receives a callback in the form of IAlgebraMintCallback# AlgebraMintCallback
* in which they must pay any token0 or token1 owed for the liquidity. The amount of token0/token1 due depends
* on bottomTick, topTick, the amount of liquidity, and the current price.
* @param sender The address which will receive potential surplus of paid tokens
* @param recipient The address for which the liquidity will be created
* @param bottomTick The lower tick of the position in which to add liquidity
* @param topTick The upper tick of the position in which to add liquidity
* @param amount The desired amount of liquidity to mint
* @param data Any data that should be passed through to the callback
* @return amount0 The amount of token0 that was paid to mint the given amount of liquidity. Matches the value in the callback
* @return amount1 The amount of token1 that was paid to mint the given amount of liquidity. Matches the value in the callback
* @return liquidityActual The actual minted amount of liquidity
*/
function mint(
address sender,
address recipient,
int24 bottomTick,
int24 topTick,
uint128 amount,
bytes calldata data
)
external
returns (
uint256 amount0,
uint256 amount1,
uint128 liquidityActual
);
/**
* @notice Collects tokens owed to a position
* @dev Does not recompute fees earned, which must be done either via mint or burn of any amount of liquidity.
* Collect must be called by the position owner. To withdraw only token0 or only token1, amount0Requested or
* amount1Requested may be set to zero. To withdraw all tokens owed, caller may pass any value greater than the
* actual tokens owed, e.g. type(uint128).max. Tokens owed may be from accumulated swap fees or burned liquidity.
* @param recipient The address which should receive the fees collected
* @param bottomTick The lower tick of the position for which to collect fees
* @param topTick The upper tick of the position for which to collect fees
* @param amount0Requested How much token0 should be withdrawn from the fees owed
* @param amount1Requested How much token1 should be withdrawn from the fees owed
* @return amount0 The amount of fees collected in token0
* @return amount1 The amount of fees collected in token1
*/
function collect(
address recipient,
int24 bottomTick,
int24 topTick,
uint128 amount0Requested,
uint128 amount1Requested
) external returns (uint128 amount0, uint128 amount1);
/**
* @notice Burn liquidity from the sender and account tokens owed for the liquidity to the position
* @dev Can be used to trigger a recalculation of fees owed to a position by calling with an amount of 0
* @dev Fees must be collected separately via a call to #collect
* @param bottomTick The lower tick of the position for which to burn liquidity
* @param topTick The upper tick of the position for which to burn liquidity
* @param amount How much liquidity to burn
* @return amount0 The amount of token0 sent to the recipient
* @return amount1 The amount of token1 sent to the recipient
*/
function burn(
int24 bottomTick,
int24 topTick,
uint128 amount
) external returns (uint256 amount0, uint256 amount1);
/**
* @notice Swap token0 for token1, or token1 for token0
* @dev The caller of this method receives a callback in the form of IAlgebraSwapCallback# AlgebraSwapCallback
* @param recipient The address to receive the output of the swap
* @param zeroToOne The direction of the swap, true for token0 to token1, false for token1 to token0
* @param amountSpecified The amount of the swap, which implicitly configures the swap as exact input (positive), or exact output (negative)
* @param limitSqrtPrice The Q64.96 sqrt price limit. If zero for one, the price cannot be less than this
* value after the swap. If one for zero, the price cannot be greater than this value after the swap
* @param data Any data to be passed through to the callback. If using the Router it should contain
* SwapRouter#SwapCallbackData
* @return amount0 The delta of the balance of token0 of the pool, exact when negative, minimum when positive
* @return amount1 The delta of the balance of token1 of the pool, exact when negative, minimum when positive
*/
function swap(
address recipient,
bool zeroToOne,
int256 amountSpecified,
uint160 limitSqrtPrice,
bytes calldata data
) external returns (int256 amount0, int256 amount1);
/**
* @notice Swap token0 for token1, or token1 for token0 (tokens that have fee on transfer)
* @dev The caller of this method receives a callback in the form of I AlgebraSwapCallback# AlgebraSwapCallback
* @param sender The address called this function (Comes from the Router)
* @param recipient The address to receive the output of the swap
* @param zeroToOne The direction of the swap, true for token0 to token1, false for token1 to token0
* @param amountSpecified The amount of the swap, which implicitly configures the swap as exact input (positive), or exact output (negative)
* @param limitSqrtPrice The Q64.96 sqrt price limit. If zero for one, the price cannot be less than this
* value after the swap. If one for zero, the price cannot be greater than this value after the swap
* @param data Any data to be passed through to the callback. If using the Router it should contain
* SwapRouter#SwapCallbackData
* @return amount0 The delta of the balance of token0 of the pool, exact when negative, minimum when positive
* @return amount1 The delta of the balance of token1 of the pool, exact when negative, minimum when positive
*/
function swapSupportingFeeOnInputTokens(
address sender,
address recipient,
bool zeroToOne,
int256 amountSpecified,
uint160 limitSqrtPrice,
bytes calldata data
) external returns (int256 amount0, int256 amount1);
/**
* @notice Receive token0 and/or token1 and pay it back, plus a fee, in the callback
* @dev The caller of this method receives a callback in the form of IAlgebraFlashCallback# AlgebraFlashCallback
* @dev All excess tokens paid in the callback are distributed to liquidity providers as an additional fee. So this method can be used
* to donate underlying tokens to currently in-range liquidity providers by calling with 0 amount{0,1} and sending
* the donation amount(s) from the callback
* @param recipient The address which will receive the token0 and token1 amounts
* @param amount0 The amount of token0 to send
* @param amount1 The amount of token1 to send
* @param data Any data to be passed through to the callback
*/
function flash(
address recipient,
uint256 amount0,
uint256 amount1,
bytes calldata data
) external;
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
/// @title Pool state that never changes
/// @dev Credit to Uniswap Labs under GPL-2.0-or-later license:
/// https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces
interface IAlgebraPoolImmutables {
/**
* @notice The contract that stores all the timepoints and can perform actions with them
* @return The operator address
*/
function dataStorageOperator() external view returns (address);
/**
* @notice The contract that deployed the pool, which must adhere to the IAlgebraFactory 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 tick spacing
* @dev Ticks can only be used at multiples of this value
* e.g.: a tickSpacing of 60 means ticks can be initialized every 60th tick, i.e., ..., -120, -60, 0, 60, 120, ...
* 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);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
interface IVaultUtils {
function updateCumulativeFundingRate(address _collateralToken, address _indexToken) external returns (bool);
function validateIncreasePosition(address _account, address _collateralToken, address _indexToken, uint256 _sizeDelta, bool _isLong) external view;
function validateDecreasePosition(address _account, address _collateralToken, address _indexToken, uint256 _collateralDelta, uint256 _sizeDelta, bool _isLong, address _receiver) external view;
function validateLiquidation(address _account, address _collateralToken, address _indexToken, bool _isLong, bool _raise) external view returns (uint256, uint256);
function getEntryFundingRate(address _collateralToken, address _indexToken, bool _isLong) external view returns (uint256);
function getPositionFee(address _account, address _collateralToken, address _indexToken, bool _isLong, uint256 _sizeDelta) external view returns (uint256);
function getFundingFee(address _account, address _collateralToken, address _indexToken, bool _isLong, uint256 _size, uint256 _entryFundingRate) external view returns (uint256);
function getBuyUsdgFeeBasisPoints(address _token, uint256 _usdgAmount) external view returns (uint256);
function getSellUsdgFeeBasisPoints(address _token, uint256 _usdgAmount) external view returns (uint256);
function getSwapFeeBasisPoints(address _tokenIn, address _tokenOut, uint256 _usdgAmount) external view returns (uint256);
function getFeeBasisPoints(address _token, uint256 _usdgDelta, uint256 _feeBasisPoints, uint256 _taxBasisPoints, bool _increment) external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {ILBPair} from "./ILBPair.sol";
import {IPendingOwnable} from "./IPendingOwnable.sol";
/**
* @title Liquidity Book Factory Interface
* @author Trader Joe
* @notice Required interface of LBFactory contract
*/
interface ILBFactory is IPendingOwnable {
error LBFactory__IdenticalAddresses(IERC20 token);
error LBFactory__QuoteAssetNotWhitelisted(IERC20 quoteAsset);
error LBFactory__QuoteAssetAlreadyWhitelisted(IERC20 quoteAsset);
error LBFactory__AddressZero();
error LBFactory__LBPairAlreadyExists(IERC20 tokenX, IERC20 tokenY, uint256 _binStep);
error LBFactory__LBPairDoesNotExist(IERC20 tokenX, IERC20 tokenY, uint256 binStep);
error LBFactory__LBPairNotCreated(IERC20 tokenX, IERC20 tokenY, uint256 binStep);
error LBFactory__FlashLoanFeeAboveMax(uint256 fees, uint256 maxFees);
error LBFactory__BinStepTooLow(uint256 binStep);
error LBFactory__PresetIsLockedForUsers(address user, uint256 binStep);
error LBFactory__LBPairIgnoredIsAlreadyInTheSameState();
error LBFactory__BinStepHasNoPreset(uint256 binStep);
error LBFactory__PresetOpenStateIsAlreadyInTheSameState();
error LBFactory__SameFeeRecipient(address feeRecipient);
error LBFactory__SameFlashLoanFee(uint256 flashLoanFee);
error LBFactory__LBPairSafetyCheckFailed(address LBPairImplementation);
error LBFactory__SameImplementation(address LBPairImplementation);
error LBFactory__ImplementationNotSet();
/**
* @dev Structure to store the LBPair information, such as:
* binStep: The bin step of the LBPair
* LBPair: The address of the LBPair
* createdByOwner: Whether the pair was created by the owner of the factory
* ignoredForRouting: Whether the pair is ignored for routing or not. An ignored pair will not be explored during routes finding
*/
struct LBPairInformation {
uint16 binStep;
ILBPair LBPair;
bool createdByOwner;
bool ignoredForRouting;
}
event LBPairCreated(
IERC20 indexed tokenX, IERC20 indexed tokenY, uint256 indexed binStep, ILBPair LBPair, uint256 pid
);
event FeeRecipientSet(address oldRecipient, address newRecipient);
event FlashLoanFeeSet(uint256 oldFlashLoanFee, uint256 newFlashLoanFee);
event LBPairImplementationSet(address oldLBPairImplementation, address LBPairImplementation);
event LBPairIgnoredStateChanged(ILBPair indexed LBPair, bool ignored);
event PresetSet(
uint256 indexed binStep,
uint256 baseFactor,
uint256 filterPeriod,
uint256 decayPeriod,
uint256 reductionFactor,
uint256 variableFeeControl,
uint256 protocolShare,
uint256 maxVolatilityAccumulator
);
event PresetOpenStateChanged(uint256 indexed binStep, bool indexed isOpen);
event PresetRemoved(uint256 indexed binStep);
event QuoteAssetAdded(IERC20 indexed quoteAsset);
event QuoteAssetRemoved(IERC20 indexed quoteAsset);
function getMinBinStep() external pure returns (uint256);
function getFeeRecipient() external view returns (address);
function getMaxFlashLoanFee() external pure returns (uint256);
function getFlashLoanFee() external view returns (uint256);
function getLBPairImplementation() external view returns (address);
function getNumberOfLBPairs() external view returns (uint256);
function getLBPairAtIndex(uint256 id) external returns (ILBPair);
function getNumberOfQuoteAssets() external view returns (uint256);
function getQuoteAssetAtIndex(uint256 index) external view returns (IERC20);
function isQuoteAsset(IERC20 token) external view returns (bool);
function getLBPairInformation(IERC20 tokenX, IERC20 tokenY, uint256 binStep)
external
view
returns (LBPairInformation memory);
function getPreset(uint256 binStep)
external
view
returns (
uint256 baseFactor,
uint256 filterPeriod,
uint256 decayPeriod,
uint256 reductionFactor,
uint256 variableFeeControl,
uint256 protocolShare,
uint256 maxAccumulator,
bool isOpen
);
function getAllBinSteps() external view returns (uint256[] memory presetsBinStep);
function getOpenBinSteps() external view returns (uint256[] memory openBinStep);
function getAllLBPairs(IERC20 tokenX, IERC20 tokenY)
external
view
returns (LBPairInformation[] memory LBPairsBinStep);
function setLBPairImplementation(address lbPairImplementation) external;
function createLBPair(IERC20 tokenX, IERC20 tokenY, uint24 activeId, uint16 binStep)
external
returns (ILBPair pair);
function setLBPairIgnored(IERC20 tokenX, IERC20 tokenY, uint16 binStep, bool ignored) external;
function setPreset(
uint16 binStep,
uint16 baseFactor,
uint16 filterPeriod,
uint16 decayPeriod,
uint16 reductionFactor,
uint24 variableFeeControl,
uint16 protocolShare,
uint24 maxVolatilityAccumulator,
bool isOpen
) external;
function setPresetOpenState(uint16 binStep, bool isOpen) external;
function removePreset(uint16 binStep) external;
function setFeesParametersOnPair(
IERC20 tokenX,
IERC20 tokenY,
uint16 binStep,
uint16 baseFactor,
uint16 filterPeriod,
uint16 decayPeriod,
uint16 reductionFactor,
uint24 variableFeeControl,
uint16 protocolShare,
uint24 maxVolatilityAccumulator
) external;
function setFeeRecipient(address feeRecipient) external;
function setFlashLoanFee(uint256 flashLoanFee) external;
function addQuoteAsset(IERC20 quoteAsset) external;
function removeQuoteAsset(IERC20 quoteAsset) external;
function forceDecay(ILBPair lbPair) external;
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
/// @title Liquidity Book Flashloan Callback Interface
/// @author Trader Joe
/// @notice Required interface to interact with LB flash loans
interface ILBFlashLoanCallback {
function LBFlashLoanCallback(
address sender,
IERC20 tokenX,
IERC20 tokenY,
bytes32 amounts,
bytes32 totalFees,
bytes calldata data
) external returns (bytes32);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
/**
* @title Liquidity Book Token Interface
* @author Trader Joe
* @notice Interface to interact with the LBToken.
*/
interface ILBToken {
error LBToken__AddressThisOrZero();
error LBToken__InvalidLength();
error LBToken__SelfApproval(address owner);
error LBToken__SpenderNotApproved(address from, address spender);
error LBToken__TransferExceedsBalance(address from, uint256 id, uint256 amount);
error LBToken__BurnExceedsBalance(address from, uint256 id, uint256 amount);
event TransferBatch(
address indexed sender, address indexed from, address indexed to, uint256[] ids, uint256[] amounts
);
event ApprovalForAll(address indexed account, address indexed sender, bool approved);
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function totalSupply(uint256 id) external view returns (uint256);
function balanceOf(address account, uint256 id) external view returns (uint256);
function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)
external
view
returns (uint256[] memory);
function isApprovedForAll(address owner, address spender) external view returns (bool);
function approveForAll(address spender, bool approved) external;
function batchTransferFrom(address from, address to, uint256[] calldata ids, uint256[] calldata amounts) external;
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
/**
* @title Liquidity Book Pending Ownable Interface
* @author Trader Joe
* @notice Required interface of Pending Ownable contract used for LBFactory
*/
interface IPendingOwnable {
error PendingOwnable__AddressZero();
error PendingOwnable__NoPendingOwner();
error PendingOwnable__NotOwner();
error PendingOwnable__NotPendingOwner();
error PendingOwnable__PendingOwnerAlreadySet();
event PendingOwnerSet(address indexed pendingOwner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
function owner() external view returns (address);
function pendingOwner() external view returns (address);
function setPendingOwner(address pendingOwner) external;
function revokePendingOwner() external;
function becomeOwner() external;
function renounceOwnership() external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {InputStream} from './InputStream.sol';
import {ReentrancyGuard} from "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import {SafeTransferLib} from 'lib/solmate/src/utils/SafeTransferLib.sol';
import {IPair} from "../core/interfaces/IPair.sol";
import {IWETH} from "./interfaces/IWETH.sol";
import {IStableSwapDispatcher} from "./interfaces/IStableSwapDispatcher.sol";
import {IFeeSettlement} from "./interfaces/IFeeSettlement.sol" ;
import {AdminUpgradeable} from "../libraries/AdminUpgradeable.sol";
import {Constants} from "../libraries/Constants.sol";
import {Commands} from "./modules/Commands.sol";
contract UniversalRouter is ReentrancyGuard, AdminUpgradeable {
using SafeERC20 for IERC20;
using SafeTransferLib for address;
using InputStream for uint256;
IStableSwapDispatcher public stableSwapDispatcher;
IFeeSettlement public feeSettlement;
error InvalidCommandCode(uint8 code);
error WrongAmountInValue(uint256 accAmount, uint256 amountIn);
error InsufficientOutAmount();
error InvalidPool(address pool);
event SetStableSwapDispatcher(IStableSwapDispatcher stableSwapDispatcher);
event SetFeeSettlement(IFeeSettlement feeSettlement);
constructor(
IStableSwapDispatcher _stableSwapDispatcher,
IFeeSettlement _feeSettlement
) {
stableSwapDispatcher = _stableSwapDispatcher;
feeSettlement = _feeSettlement;
_initializeAdmin(msg.sender);
}
/// @notice To receive ETH from WETH
receive() external payable {}
/// @notice Set StableSwapDispatcher by admin
/// @param _stableSwapDispatcher StableSwapDispatcher address
function setStableSwapDispatcher(IStableSwapDispatcher _stableSwapDispatcher) external onlyAdmin {
stableSwapDispatcher = _stableSwapDispatcher;
emit SetStableSwapDispatcher(_stableSwapDispatcher);
}
/// @notice Set FeeSettlement by admin
/// @param _feeSettlement FeeSettlement address
function setFeeSettlement(IFeeSettlement _feeSettlement) external onlyAdmin {
feeSettlement = _feeSettlement;
emit SetFeeSettlement(_feeSettlement);
}
/// @notice Decodes and executes the given route
/// @param tokenIn Address of the input token
/// @param amountIn Amount of the input token
/// @param tokenOut Address of the output token
/// @param amountOutMin Minimum amount of the output token
/// @param to Receiver address
/// @param route The encoded route to execute with
/// @return amountOut Actual amount of the output token
function processRoute(
address tokenIn,
uint256 amountIn,
address tokenOut,
uint256 amountOutMin,
address to,
bytes memory route
) external payable nonReentrant returns (uint256 amountOut) {
return processRouteInternal(tokenIn, amountIn, tokenOut, amountOutMin, to, route);
}
/// @notice Decodes and executes the given route
/// @param tokenIn Address of the input token
/// @param amountIn Amount of the input token
/// @param tokenOut Address of the output token
/// @param amountOutMin Minimum amount of the output token
/// @param to Receiver address
/// @param route The encoded route to execute with
/// @return amountOut Actual amount of the output token
function processRouteInternal(
address tokenIn,
uint256 amountIn,
address tokenOut,
uint256 amountOutMin,
address to,
bytes memory route
) private returns (uint256 amountOut) {
uint256 amountInAcc = 0;
uint256 balanceInitial = tokenOut == Constants.NATIVE_ADDRESS ?
address(to).balance
: IERC20(tokenOut).balanceOf(to);
uint256 stream = InputStream.createStream(route);
while (stream.isNotEmpty()) {
uint8 commandCode = stream.readUint8();
if (commandCode < 20) {
// 0 <= command < 20
if (commandCode == Commands.SWAP_UNISWAPV2_POOL) {
// UniswapV2 pool swap
swapUniswapV2Pool(stream);
} else if (commandCode == Commands.DISTRIBUTE_ERC20_SHARES) {
// distribute ERC20 tokens from this router to pools
distributeERC20Shares(stream);
} else if (commandCode == Commands.DISTRIBUTE_ERC20_AMOUNTS) {
// initial distribution
amountInAcc += distributeERC20Amounts(stream, tokenIn);
} else if (commandCode == Commands.WRAP_AND_DISTRIBUTE_ERC20_AMOUNTS) {
// wrap natives and initial distribution
amountInAcc += wrapAndDistributeERC20Amounts(stream, amountIn);
} else if (commandCode == Commands.UNWRAP_NATIVE) {
// unwrap natives
unwrapNative(stream);
} else {
revert InvalidCommandCode(commandCode);
}
} else if (commandCode < 24) {
// 20 <= command < 24
if (commandCode == Commands.SWAP_ZENLINK_STABLESWAP) {
// Zenlink stable pool swap
swapZenlinkStableSwap(stream);
} else {
revert InvalidCommandCode(commandCode);
}
} else {
// placeholder area for commands 24-255
revert InvalidCommandCode(commandCode);
}
}
if (amountInAcc != amountIn) revert WrongAmountInValue(amountInAcc, amountIn);
feeSettlement.processSettlement(tokenOut, amountOutMin, msg.sender, to);
uint256 balanceFinal = tokenOut == Constants.NATIVE_ADDRESS ?
address(to).balance
: IERC20(tokenOut).balanceOf(to);
if (balanceFinal < balanceInitial + amountOutMin) revert InsufficientOutAmount();
amountOut = balanceFinal - balanceInitial;
}
/// @notice Performs a UniswapV2 pool swap
/// @param stream [Pool, TokenIn, Direction, To]
/// @return amountOut Amount of the output token
function swapUniswapV2Pool(uint256 stream) private returns (uint256 amountOut) {
address pool = stream.readAddress();
address tokenIn = stream.readAddress();
uint8 direction = stream.readUint8();
address to = stream.readAddress();
(uint256 reserve0, uint256 reserve1, ) = IPair(pool).getReserves();
if (reserve0 == 0 || reserve1 == 0) revert InvalidPool(pool);
(uint256 reserveIn, uint256 reserveOut) = direction == 1
? (reserve0, reserve1)
: (reserve1, reserve0);
uint256 amountIn = IERC20(tokenIn).balanceOf(pool) - reserveIn;
uint256 amountInWithFee = amountIn * 997;
amountOut = (amountInWithFee * reserveOut) / (reserveIn * 1000 + amountInWithFee);
(uint256 amount0Out, uint256 amount1Out) = direction == 1
? (uint256(0), amountOut)
: (amountOut, uint256(0));
IPair(pool).swap(amount0Out, amount1Out, to, new bytes(0));
}
/// @notice Performs a Zenlink stable pool swap
/// @param stream [isMetaSwap, To, [Pool, Option(isNativePool), TokenInIndex, TokenOutIndex, TokenIn, TokenOut]]
function swapZenlinkStableSwap(uint256 stream) private {
uint8 isMetaSwap = stream.readUint8();
address to = stream.readAddress();
bytes memory swapData = stream.readBytes();
if (isMetaSwap == 1) {
(
address pool,
uint8 tokenInIndex,
uint8 tokenOutIndex,
address tokenIn,
address tokenOut
) = abi.decode(
swapData,
(address, uint8, uint8, address, address)
);
stableSwapDispatcher.swapUnderlying(
pool,
tokenInIndex,
tokenOutIndex,
tokenIn,
tokenOut,
to
);
} else {
(
address pool,
bool isNativePool,
uint8 tokenInIndex,
uint8 tokenOutIndex,
address tokenIn,
address tokenOut
) = abi.decode(
swapData,
(address, bool, uint8, uint8, address, address)
);
stableSwapDispatcher.swap(
pool,
isNativePool,
tokenInIndex,
tokenOutIndex,
tokenIn,
tokenOut,
to
);
}
}
/// @notice Distributes input ERC20 tokens from msg.sender to addresses. Tokens should be approved
/// @param stream [ArrayLength, ...[To, Amount][]]. An array of destinations and token amounts
/// @param token Token to distribute
/// @return amountTotal Total amount distributed
function distributeERC20Amounts(uint256 stream, address token) private returns (uint256 amountTotal) {
uint8 num = stream.readUint8();
amountTotal = 0;
for (uint256 i = 0; i < num; ++i) {
address to = stream.readAddress();
uint256 amount = stream.readUint();
amountTotal += amount;
IERC20(token).safeTransferFrom(msg.sender, to, amount);
}
}
/// @notice Wraps all native inputs and distributes wrapped ERC20 tokens from router to addresses
/// @param stream [WrapToken, ArrayLength, ...[To, Amount][]]. An array of destinations and token amounts
/// @return amountTotal Total amount distributed
function wrapAndDistributeERC20Amounts(uint256 stream, uint256 amountIn) private returns (uint256 amountTotal) {
address token = stream.readAddress();
IWETH(token).deposit{value: amountIn}();
uint8 num = stream.readUint8();
amountTotal = 0;
for (uint256 i = 0; i < num; ++i) {
address to = stream.readAddress();
uint256 amount = stream.readUint();
amountTotal += amount;
IERC20(token).safeTransfer(to, amount);
}
}
/// @notice Distributes ERC20 tokens from router to addresses
/// @notice Quantity for sending is determined by share in 1/65535
/// @notice During routing we can't predict in advance the actual value of internal swaps because of slippage,
/// @notice so we have to work with shares - not fixed amounts
/// @param stream [Token, ArrayLength, ...[To, ShareAmount][]]. Token to distribute. An array of destinations and token share amounts
function distributeERC20Shares(uint256 stream) private {
address token = stream.readAddress();
uint8 num = stream.readUint8();
// slot undrain protection
uint256 amountTotal = IERC20(token).balanceOf(address(this)) - 1;
for (uint256 i = 0; i < num; ++i) {
address to = stream.readAddress();
uint16 share = stream.readUint16();
uint256 amount = (amountTotal * share) / 65535;
amountTotal -= amount;
IERC20(token).safeTransfer(to, amount);
}
}
/// @notice Unwraps the Native Token
/// @param stream [Token]. Token to unwrap native
function unwrapNative(uint256 stream) private {
address token = stream.readAddress();
address receiver = stream.readAddress();
uint256 amount = IERC20(token).balanceOf(address(this)) - 1;
// slot undrain protection
IWETH(token).withdraw(amount);
receiver.safeTransferETH(amount);
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
library Commands {
// Command Types. Maximum supported command at this moment is 255.
// Command Types where value<20, executed in the first nested-if block
uint8 constant DISTRIBUTE_ERC20_AMOUNTS = 3;
uint8 constant DISTRIBUTE_ERC20_SHARES = 4;
uint8 constant WRAP_AND_DISTRIBUTE_ERC20_AMOUNTS = 5;
uint8 constant UNWRAP_NATIVE = 6;
uint8 constant SWAP_UNISWAPV2_POOL = 10;
// Command Types where 20<=value<24, executed in the second nested-if block
uint8 constant SWAP_ZENLINK_STABLESWAP = 20;
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {ICurveStableSwap} from "../../interfaces/curve/ICurveStableSwap.sol";
import {ICurveStableDispatcher} from "../../interfaces/curve/ICurveStableDispatcher.sol";
import {IWETH} from "../../interfaces/IWETH.sol";
contract CurveStableDispatcher is ICurveStableDispatcher {
using SafeERC20 for IERC20;
address public immutable weth;
error InsufficientAmountIn();
constructor(address _weth) {
weth = _weth;
}
/// @notice To receive ETH from WETH
receive() external payable {}
function exchange(
address _pool,
bool _isNativePool,
int128 _tokenInIndex,
int128 _tokenOutIndex,
address _tokenIn,
address _tokenOut,
address _to
) external override {
ICurveStableSwap pool = ICurveStableSwap(_pool);
IERC20 tokenIn = IERC20(_tokenIn);
IERC20 tokenOut = IERC20(_tokenOut);
bool isNativeTokenIn = _tokenIn == weth && _isNativePool;
bool isNatvieTokenOut = _tokenOut == weth && _isNativePool;
uint256 amountIn = tokenIn.balanceOf(address(this));
if (amountIn == 0) revert InsufficientAmountIn();
if (isNativeTokenIn) {
IWETH(_tokenIn).withdraw(amountIn);
pool.exchange{value: address(this).balance}(
_tokenInIndex,
_tokenOutIndex,
address(this).balance,
0
);
} else {
tokenIn.safeIncreaseAllowance(address(pool), amountIn);
pool.exchange(_tokenInIndex, _tokenOutIndex, amountIn, 0);
}
if (isNatvieTokenOut) {
IWETH(_tokenOut).deposit{value: address(this).balance}();
}
tokenOut.safeTransfer(_to, tokenOut.balanceOf(address(this)));
}
function exchange_underlying(
address _pool,
int128 _tokenInIndex,
int128 _tokenOutIndex,
address _tokenIn,
address _tokenOut,
address _to
) external override {
ICurveStableSwap metaPool = ICurveStableSwap(_pool);
IERC20 tokenIn = IERC20(_tokenIn);
IERC20 tokenOut = IERC20(_tokenOut);
uint256 amountIn = tokenIn.balanceOf(address(this));
if (amountIn == 0) revert InsufficientAmountIn();
tokenIn.safeIncreaseAllowance(address(metaPool), amountIn);
metaPool.exchange_underlying(
_tokenInIndex,
_tokenOutIndex,
amountIn,
0
);
tokenOut.safeTransfer(_to, tokenOut.balanceOf(address(this)));
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
interface ICurveStableSwap {
// state modifying functions
function exchange(
int128 tokenIndexFrom,
int128 tokenIndexTo,
uint256 dx,
uint256 minDy
) external payable returns (uint256);
function exchange_underlying(
int128 tokenIndexFrom,
int128 tokenIndexTo,
uint256 dx,
uint256 minDy
) external returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
import {ILBFactory} from "../../../interfaces/joe/v2/ILBFactory.sol";
import {ILBPair} from "../../../interfaces/joe/v2/ILBPair.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
contract JoeV2StateMulticall {
struct BinInfo {
uint24 id;
uint128 reserveX;
uint128 reserveY;
}
struct StateResult {
ILBPair pair;
address tokenX;
address tokenY;
uint24 activeId;
uint16 binStep;
uint256 reserve0;
uint256 reserve1;
uint256 totalFee;
BinInfo[] binInfos;
}
function getFullState(
ILBFactory factory,
IERC20 tokenX,
IERC20 tokenY,
uint256 leftBinLength,
uint256 rightBinLength
) external view returns (StateResult[] memory states) {
ILBFactory.LBPairInformation[] memory pairsInformation = factory.getAllLBPairs(tokenX, tokenY);
uint256 numOfAvailablePairs = 0;
for (uint256 i = 0; i < pairsInformation.length; i++) {
if (pairsInformation[i].ignoredForRouting) {
continue;
} else {
numOfAvailablePairs++;
}
}
states = new StateResult[](numOfAvailablePairs);
for (uint256 i = 0; i < pairsInformation.length; i++) {
ILBFactory.LBPairInformation memory pairInformation = pairsInformation[i];
if (pairInformation.ignoredForRouting) {
continue;
} else {
ILBPair pair = pairInformation.LBPair;
uint16 binStep = pairInformation.binStep;
uint24 activeId = pair.getActiveId();
StateResult memory state;
state.pair = pair;
state.tokenX = address(pair.getTokenX());
state.tokenY = address(pair.getTokenY());
state.activeId = activeId;
state.binStep = binStep;
(state.reserve0, state.reserve1) = pair.getReserves();
{
(uint16 baseFactor, , , , uint24 variableFeeControl, , ) = pair.getStaticFeeParameters();
(uint24 volatilityAccumulator, , , ) = pair.getVariableFeeParameters();
uint256 baseFee = uint256(baseFactor) * binStep * 1e10;
uint256 variableFee;
if (variableFeeControl != 0) {
uint256 prod = uint256(volatilityAccumulator) * binStep;
variableFee = (prod * prod * variableFeeControl + 99) / 100;
}
state.totalFee = baseFee + variableFee;
}
state.binInfos = _getBinInfos(pair, leftBinLength, rightBinLength);
states[i] = state;
}
}
}
function _getBinInfo( ILBPair pair, uint24 id) internal view returns (BinInfo memory) {
(uint128 binReserveX, uint128 binReserveY) = pair.getBin(id);
return BinInfo({
id: id,
reserveX: binReserveX,
reserveY: binReserveY
});
}
function _getBinInfos(
ILBPair pair,
uint256 leftBinLength,
uint256 rightBinLength
) internal view returns (BinInfo[] memory binInfos) {
binInfos = new BinInfo[](leftBinLength + rightBinLength + 1);
uint24 activeId = pair.getActiveId();
binInfos[leftBinLength] = _getBinInfo(pair, activeId);
uint24 leftBinId = activeId;
for (uint256 i = 0; i < leftBinLength; i++) {
uint24 nextLeftBinId = pair.getNextNonEmptyBin(false, leftBinId);
binInfos[leftBinLength - i - 1] = _getBinInfo(pair, nextLeftBinId);
leftBinId = nextLeftBinId;
}
uint24 rightBinId = activeId;
for (uint256 i = 0; i < rightBinLength; i++) {
uint24 nextRightBinId = pair.getNextNonEmptyBin(true, rightBinId);
binInfos[leftBinLength + i + 1] = _getBinInfo(pair, nextRightBinId);
rightBinId = nextRightBinId;
}
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
import {IAlgebraPool} from "../../interfaces/algebra/IAlgebraPool.sol";
import {IAlgebraFactory} from "../../interfaces/algebra/IAlgebraFactory.sol";
import {IERC20Minimal} from "../../interfaces/IERC20Minimal.sol";
contract AlgebraStateMulticall {
struct Slot0 {
uint160 sqrtPriceX96;
uint16 fee;
int24 tick;
uint16 observationIndex;
uint8 communityFeeToken0;
uint8 communityFeeToken1;
bool unlocked;
}
struct TickBitMapMappings {
int16 index;
uint256 value;
}
struct TickInfo {
uint128 liquidityGross;
int128 liquidityNet;
int56 tickCumulativeOutside;
uint160 secondsPerLiquidityOutsideX128;
uint32 secondsOutside;
bool initialized;
}
struct TickInfoMappings {
int24 index;
TickInfo value;
}
struct Observation {
uint32 blockTimestamp;
int56 tickCumulative;
uint160 secondsPerLiquidityCumulativeX128;
bool initialized;
}
struct StateResult {
IAlgebraPool pool;
uint256 blockTimestamp;
Slot0 slot0;
uint128 liquidity;
int24 tickSpacing;
uint128 maxLiquidityPerTick;
uint256 balance0;
uint256 balance1;
Observation observation;
TickBitMapMappings[] tickBitmap;
TickInfoMappings[] ticks;
}
function getFullStateWithRelativeBitmaps(
IAlgebraFactory factory,
address tokenIn,
address tokenOut,
int16 leftBitmapAmount,
int16 rightBitmapAmount
) external view returns (StateResult memory state) {
require(leftBitmapAmount > 0, "leftBitmapAmount <= 0");
require(rightBitmapAmount > 0, "rightBitmapAmount <= 0");
state = _fillStateWithoutBitmapsAndTicks(
factory,
tokenIn,
tokenOut
);
int16 currentBitmapIndex = _getBitmapIndexFromTick(
state.slot0.tick / state.tickSpacing
);
state.tickBitmap = _calcTickBitmaps(
factory,
tokenIn,
tokenOut,
currentBitmapIndex - leftBitmapAmount,
currentBitmapIndex + rightBitmapAmount
);
}
function _fillStateWithoutBitmapsAndTicks(
IAlgebraFactory factory,
address tokenIn,
address tokenOut
) internal view returns (StateResult memory state) {
IAlgebraPool pool = _getPool(factory, tokenIn, tokenOut);
state.pool = pool;
state.blockTimestamp = block.timestamp;
state.liquidity = pool.liquidity();
state.tickSpacing = pool.tickSpacing();
state.maxLiquidityPerTick = pool.maxLiquidityPerTick();
state.balance0 = _getBalance(pool.token0(), address(pool));
state.balance1= _getBalance(pool.token1(), address(pool));
(
state.slot0.sqrtPriceX96,
state.slot0.tick,
state.slot0.fee,
state.slot0.observationIndex,
state.slot0.communityFeeToken0,
state.slot0.communityFeeToken1,
state.slot0.unlocked
) = pool.globalState();
(
state.observation.initialized,
state.observation.blockTimestamp,
state.observation.tickCumulative,
state.observation.secondsPerLiquidityCumulativeX128,
,
,
) = pool.timepoints(state.slot0.observationIndex);
}
function _calcTickBitmaps(
IAlgebraFactory factory,
address tokenIn,
address tokenOut,
int16 tickBitmapStart,
int16 tickBitmapEnd
) internal view returns (TickBitMapMappings[] memory tickBitmap) {
IAlgebraPool pool = _getPool(factory, tokenIn, tokenOut);
uint256 numberOfPopulatedBitmaps = 0;
for (int256 i = tickBitmapStart; i <= tickBitmapEnd; i++) {
uint256 bitmap = pool.tickTable(int16(i));
if (bitmap == 0) continue;
numberOfPopulatedBitmaps++;
}
tickBitmap = new TickBitMapMappings[](numberOfPopulatedBitmaps);
uint256 globalIndex = 0;
for (int256 i = tickBitmapStart; i <= tickBitmapEnd; i++) {
int16 index = int16(i);
uint256 bitmap = pool.tickTable(index);
if (bitmap == 0) continue;
tickBitmap[globalIndex] = TickBitMapMappings({
index: index,
value: bitmap
});
globalIndex++;
}
}
function _getPool(
IAlgebraFactory factory,
address tokenIn,
address tokenOut
) internal view returns (IAlgebraPool pool) {
pool = IAlgebraPool(factory.poolByPair(tokenIn, tokenOut));
require(address(pool) != address(0), "Pool does not exist");
}
function _getBitmapIndexFromTick(int24 tick) internal pure returns (int16) {
return int16(tick >> 8);
}
function _getBalance(address token, address pool) internal view returns (uint256) {
(bool success, bytes memory data) = token.staticcall(
abi.encodeWithSelector(IERC20Minimal.balanceOf.selector, pool)
);
require(success && data.length >= 32);
return abi.decode(data, (uint256));
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
/**
* @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 the owner of the factory is changed
* @param newOwner The owner after the owner was changed
*/
event Owner(address indexed newOwner);
/**
* @notice Emitted when the vault address is changed
* @param newVaultAddress The vault address after the address was changed
*/
event VaultAddress(address indexed newVaultAddress);
/**
* @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 farming address is changed
* @param newFarmingAddress The farming address after the address was changed
*/
event FarmingAddress(address indexed newFarmingAddress);
event FeeConfiguration(
uint16 alpha1,
uint16 alpha2,
uint32 beta1,
uint32 beta2,
uint16 gamma1,
uint16 gamma2,
uint32 volumeBeta,
uint16 volumeGamma,
uint16 baseFee
);
/**
* @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 current poolDeployerAddress
* @return The address of the poolDeployer
*/
function poolDeployer() external view returns (address);
/**
* @dev Is retrieved from the pools to restrict calling
* certain functions not by a tokenomics contract
* @return The tokenomics contract address
*/
function farmingAddress() external view returns (address);
function vaultAddress() external view returns (address);
/**
* @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
* @return pool The pool address
*/
function poolByPair(address tokenA, address tokenB) 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
* @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) 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;
/**
* @dev updates tokenomics address on the factory
* @param _farmingAddress The new tokenomics contract address
*/
function setFarmingAddress(address _farmingAddress) external;
/**
* @dev updates vault address on the factory
* @param _vaultAddress The new vault contract address
*/
function setVaultAddress(address _vaultAddress) external;
/**
* @notice Changes initial fee configuration for new pools
* @dev changes coefficients for sigmoids: α / (1 + e^( (β-x) / γ))
* alpha1 + alpha2 + baseFee (max possible fee) must be <= type(uint16).max
* gammas must be > 0
* @param alpha1 max value of the first sigmoid
* @param alpha2 max value of the second sigmoid
* @param beta1 shift along the x-axis for the first sigmoid
* @param beta2 shift along the x-axis for the second sigmoid
* @param gamma1 horizontal stretch factor for the first sigmoid
* @param gamma2 horizontal stretch factor for the second sigmoid
* @param volumeBeta shift along the x-axis for the outer volume-sigmoid
* @param volumeGamma horizontal stretch factor the outer volume-sigmoid
* @param baseFee minimum possible fee
*/
function setBaseFeeConfiguration(
uint16 alpha1,
uint16 alpha2,
uint32 beta1,
uint32 beta2,
uint16 gamma1,
uint16 gamma2,
uint32 volumeBeta,
uint16 volumeGamma,
uint16 baseFee
) external;
}// 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 the balance of a 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;
import {IUniswapV3Pool} from "../../../interfaces/uniswap/v3/IUniswapV3Pool.sol";
import {IUniswapV3Factory} from "../../../interfaces/uniswap/v3/IUniswapV3Factory.sol";
import {IUniswapV3StateMulticall} from "../../../interfaces/uniswap/v3/IUniswapV3StateMulticall.sol";
import {IERC20Minimal} from "../../../interfaces/IERC20Minimal.sol";
contract UniswapV3StateMulticall is IUniswapV3StateMulticall {
function getFullState(
IUniswapV3Factory factory,
address tokenIn,
address tokenOut,
uint24 fee,
int16 tickBitmapStart,
int16 tickBitmapEnd
) external view override returns (StateResult memory state) {
require(
tickBitmapEnd >= tickBitmapStart,
"tickBitmapEnd < tickBitmapStart"
);
state = _fillStateWithoutTicks(
factory,
tokenIn,
tokenOut,
fee,
tickBitmapStart,
tickBitmapEnd
);
state.ticks = _calcTicksFromBitMap(
factory,
tokenIn,
tokenOut,
fee,
state.tickBitmap
);
}
function getFullStateWithoutTicks(
IUniswapV3Factory factory,
address tokenIn,
address tokenOut,
uint24 fee,
int16 tickBitmapStart,
int16 tickBitmapEnd
) external view override returns (StateResult memory state) {
require(
tickBitmapEnd >= tickBitmapStart,
"tickBitmapEnd < tickBitmapStart"
);
return
_fillStateWithoutTicks(
factory,
tokenIn,
tokenOut,
fee,
tickBitmapStart,
tickBitmapEnd
);
}
function getFullStateWithRelativeBitmaps(
IUniswapV3Factory factory,
address tokenIn,
address tokenOut,
uint24 fee,
int16 leftBitmapAmount,
int16 rightBitmapAmount
) external view override returns (StateResult memory state) {
require(leftBitmapAmount > 0, "leftBitmapAmount <= 0");
require(rightBitmapAmount > 0, "rightBitmapAmount <= 0");
state = _fillStateWithoutBitmapsAndTicks(
factory,
tokenIn,
tokenOut,
fee
);
int16 currentBitmapIndex = _getBitmapIndexFromTick(
state.slot0.tick / state.tickSpacing
);
state.tickBitmap = _calcTickBitmaps(
factory,
tokenIn,
tokenOut,
fee,
currentBitmapIndex - leftBitmapAmount,
currentBitmapIndex + rightBitmapAmount
);
}
function getAdditionalBitmapWithTicks(
IUniswapV3Factory factory,
address tokenIn,
address tokenOut,
uint24 fee,
int16 tickBitmapStart,
int16 tickBitmapEnd
)
external
view
override
returns (
TickBitMapMappings[] memory tickBitmap,
TickInfoMappings[] memory ticks
)
{
require(
tickBitmapEnd >= tickBitmapStart,
"tickBitmapEnd < tickBitmapStart"
);
tickBitmap = _calcTickBitmaps(
factory,
tokenIn,
tokenOut,
fee,
tickBitmapStart,
tickBitmapEnd
);
ticks = _calcTicksFromBitMap(
factory,
tokenIn,
tokenOut,
fee,
tickBitmap
);
}
function getAdditionalBitmapWithoutTicks(
IUniswapV3Factory factory,
address tokenIn,
address tokenOut,
uint24 fee,
int16 tickBitmapStart,
int16 tickBitmapEnd
) external view override returns (TickBitMapMappings[] memory tickBitmap) {
require(
tickBitmapEnd >= tickBitmapStart,
"tickBitmapEnd < tickBitmapStart"
);
return
_calcTickBitmaps(
factory,
tokenIn,
tokenOut,
fee,
tickBitmapStart,
tickBitmapEnd
);
}
function _fillStateWithoutTicks(
IUniswapV3Factory factory,
address tokenIn,
address tokenOut,
uint24 fee,
int16 tickBitmapStart,
int16 tickBitmapEnd
) internal view returns (StateResult memory state) {
state = _fillStateWithoutBitmapsAndTicks(
factory,
tokenIn,
tokenOut,
fee
);
state.tickBitmap = _calcTickBitmaps(
factory,
tokenIn,
tokenOut,
fee,
tickBitmapStart,
tickBitmapEnd
);
}
function _fillStateWithoutBitmapsAndTicks(
IUniswapV3Factory factory,
address tokenIn,
address tokenOut,
uint24 fee
) internal view returns (StateResult memory state) {
IUniswapV3Pool pool = _getPool(factory, tokenIn, tokenOut, fee);
state.pool = pool;
state.blockTimestamp = block.timestamp;
state.liquidity = pool.liquidity();
state.tickSpacing = pool.tickSpacing();
state.maxLiquidityPerTick = pool.maxLiquidityPerTick();
state.balance0 = _getBalance(pool.token0(), address(pool));
state.balance1= _getBalance(pool.token1(), address(pool));
(
state.slot0.sqrtPriceX96,
state.slot0.tick,
state.slot0.observationIndex,
state.slot0.observationCardinality,
state.slot0.observationCardinalityNext,
state.slot0.feeProtocol,
state.slot0.unlocked
) = pool.slot0();
(
state.observation.blockTimestamp,
state.observation.tickCumulative,
state.observation.secondsPerLiquidityCumulativeX128,
state.observation.initialized
) = pool.observations(state.slot0.observationIndex);
}
function _calcTickBitmaps(
IUniswapV3Factory factory,
address tokenIn,
address tokenOut,
uint24 fee,
int16 tickBitmapStart,
int16 tickBitmapEnd
) internal view returns (TickBitMapMappings[] memory tickBitmap) {
IUniswapV3Pool pool = _getPool(factory, tokenIn, tokenOut, fee);
uint256 numberOfPopulatedBitmaps = 0;
for (int256 i = tickBitmapStart; i <= tickBitmapEnd; i++) {
uint256 bitmap = pool.tickBitmap(int16(i));
if (bitmap == 0) continue;
numberOfPopulatedBitmaps++;
}
tickBitmap = new TickBitMapMappings[](numberOfPopulatedBitmaps);
uint256 globalIndex = 0;
for (int256 i = tickBitmapStart; i <= tickBitmapEnd; i++) {
int16 index = int16(i);
uint256 bitmap = pool.tickBitmap(index);
if (bitmap == 0) continue;
tickBitmap[globalIndex] = TickBitMapMappings({
index: index,
value: bitmap
});
globalIndex++;
}
}
function _calcTicksFromBitMap(
IUniswapV3Factory factory,
address tokenIn,
address tokenOut,
uint24 fee,
TickBitMapMappings[] memory tickBitmap
) internal view returns (TickInfoMappings[] memory ticks) {
IUniswapV3Pool pool = _getPool(factory, tokenIn, tokenOut, fee);
uint256 numberOfPopulatedTicks = 0;
for (uint256 i = 0; i < tickBitmap.length; i++) {
uint256 bitmap = tickBitmap[i].value;
for (uint256 j = 0; j < 256; j++) {
if (bitmap & (1 << j) > 0) numberOfPopulatedTicks++;
}
}
ticks = new TickInfoMappings[](numberOfPopulatedTicks);
int24 tickSpacing = pool.tickSpacing();
uint256 globalIndex = 0;
for (uint256 i = 0; i < tickBitmap.length; i++) {
uint256 bitmap = tickBitmap[i].value;
for (uint256 j = 0; j < 256; j++) {
if (bitmap & (1 << j) > 0) {
int24 populatedTick = ((int24(tickBitmap[i].index) << 8) +
int24(uint24(j))) * tickSpacing;
ticks[globalIndex].index = populatedTick;
TickInfo memory newTickInfo = ticks[globalIndex].value;
(
newTickInfo.liquidityGross,
newTickInfo.liquidityNet,
,
,
newTickInfo.tickCumulativeOutside,
newTickInfo.secondsPerLiquidityOutsideX128,
newTickInfo.secondsOutside,
newTickInfo.initialized
) = pool.ticks(populatedTick);
globalIndex++;
}
}
}
}
function _getPool(
IUniswapV3Factory factory,
address tokenIn,
address tokenOut,
uint24 fee
) internal view returns (IUniswapV3Pool pool) {
pool = IUniswapV3Pool(factory.getPool(tokenIn, tokenOut, fee));
require(address(pool) != address(0), "Pool does not exist");
}
function _getBitmapIndexFromTick(int24 tick) internal pure returns (int16) {
return int16(tick >> 8);
}
function _getBalance(address token, address pool) internal view returns (uint256) {
(bool success, bytes memory data) = token.staticcall(
abi.encodeWithSelector(IERC20Minimal.balanceOf.selector, pool)
);
require(success && data.length >= 32);
return abi.decode(data, (uint256));
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.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 {IUniswapV3Pool} from "./IUniswapV3Pool.sol";
import {IUniswapV3Factory} from "./IUniswapV3Factory.sol";
interface IUniswapV3StateMulticall {
struct Slot0 {
uint160 sqrtPriceX96;
int24 tick;
uint16 observationIndex;
uint16 observationCardinality;
uint16 observationCardinalityNext;
uint8 feeProtocol;
bool unlocked;
}
struct TickBitMapMappings {
int16 index;
uint256 value;
}
struct TickInfo {
uint128 liquidityGross;
int128 liquidityNet;
int56 tickCumulativeOutside;
uint160 secondsPerLiquidityOutsideX128;
uint32 secondsOutside;
bool initialized;
}
struct TickInfoMappings {
int24 index;
TickInfo value;
}
struct Observation {
uint32 blockTimestamp;
int56 tickCumulative;
uint160 secondsPerLiquidityCumulativeX128;
bool initialized;
}
struct StateResult {
IUniswapV3Pool pool;
uint256 blockTimestamp;
Slot0 slot0;
uint128 liquidity;
int24 tickSpacing;
uint128 maxLiquidityPerTick;
uint256 balance0;
uint256 balance1;
Observation observation;
TickBitMapMappings[] tickBitmap;
TickInfoMappings[] ticks;
}
function getFullState(
IUniswapV3Factory factory,
address tokenIn,
address tokenOut,
uint24 fee,
int16 tickBitmapStart,
int16 tickBitmapEnd
) external view returns (StateResult memory state);
function getFullStateWithoutTicks(
IUniswapV3Factory factory,
address tokenIn,
address tokenOut,
uint24 fee,
int16 tickBitmapStart,
int16 tickBitmapEnd
) external view returns (StateResult memory state);
function getFullStateWithRelativeBitmaps(
IUniswapV3Factory factory,
address tokenIn,
address tokenOut,
uint24 fee,
int16 leftBitmapAmount,
int16 rightBitmapAmount
) external view returns (StateResult memory state);
function getAdditionalBitmapWithTicks(
IUniswapV3Factory factory,
address tokenIn,
address tokenOut,
uint24 fee,
int16 tickBitmapStart,
int16 tickBitmapEnd
)
external
view
returns (
TickBitMapMappings[] memory tickBitmap,
TickInfoMappings[] memory ticks
);
function getAdditionalBitmapWithoutTicks(
IUniswapV3Factory factory,
address tokenIn,
address tokenOut,
uint24 fee,
int16 tickBitmapStart,
int16 tickBitmapEnd
) external view returns (TickBitMapMappings[] memory tickBitmap);
}{
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"abi"
]
}
},
"metadata": {
"useLiteralContent": true
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract IStableSwapDispatcher","name":"_stableSwapDispatcher","type":"address"},{"internalType":"contract ICurveStableDispatcher","name":"_curveStableDispatcher","type":"address"},{"internalType":"contract IFeeSettlement","name":"_feeSettlement","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"pool","type":"address"}],"name":"InvalidPool","type":"error"},{"inputs":[],"name":"MinimalInputBalanceViolation","type":"error"},{"inputs":[],"name":"MinimalOutputBalanceViolation","type":"error"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"UnexpectedAddress","type":"error"},{"inputs":[],"name":"UnexpectedAlgebraSwap","type":"error"},{"inputs":[],"name":"UnexpectedUniV3Swap","type":"error"},{"inputs":[{"internalType":"uint8","name":"code","type":"uint8"}],"name":"UnknownCommandCode","type":"error"},{"inputs":[{"internalType":"uint8","name":"poolType","type":"uint8"}],"name":"UnknownPoolType","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldAdmin","type":"address"},{"indexed":true,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newAdmin","type":"address"}],"name":"Candidate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract ICurveStableDispatcher","name":"curveStableDispatcher","type":"address"}],"name":"SetCurveStableDispatcher","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IFeeSettlement","name":"feeSettlement","type":"address"}],"name":"SetFeeSettlement","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IStableSwapDispatcher","name":"stableSwapDispatcher","type":"address"}],"name":"SetStableSwapDispatcher","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"adminCandidate","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":"candidateConfirm","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"curveStableDispatcher","outputs":[{"internalType":"contract ICurveStableDispatcher","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeSettlement","outputs":[{"internalType":"contract IFeeSettlement","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bytes","name":"route","type":"bytes"}],"name":"processRoute","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_candidate","type":"address"}],"name":"setAdminCandidate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ICurveStableDispatcher","name":"_curveStableDispatcher","type":"address"}],"name":"setCurveStableDispatcher","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IFeeSettlement","name":"_feeSettlement","type":"address"}],"name":"setFeeSettlement","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IStableSwapDispatcher","name":"_stableSwapDispatcher","type":"address"}],"name":"setStableSwapDispatcher","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stableSwapDispatcher","outputs":[{"internalType":"contract IStableSwapDispatcher","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"transferValueTo","type":"address"},{"internalType":"uint256","name":"amountValueTransfer","type":"uint256"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bytes","name":"route","type":"bytes"}],"name":"transferValueAndprocessRoute","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","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"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60806040523480156200001157600080fd5b5060405162002a9b38038062002a9b833981016040819052620000349162000119565b600160008190556002805460ff60a01b19169055600380546001600160a01b038087166001600160a01b0319928316179092556004805486841690831617905560058054928516928216929092179091556006805490911690911790556200009c33620000a5565b50505062000186565b6001546001600160a01b031615620000f75760405162461bcd60e51b815260206004820152601160248201527018591b5a5b88185b1c9958591e481cd95d607a1b604482015260640160405180910390fd5b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000806000606084860312156200012f57600080fd5b83516200013c816200016d565b60208501519093506200014f816200016d565b604085015190925062000162816200016d565b809150509250925092565b6001600160a01b03811681146200018357600080fd5b50565b61290580620001966000396000f3fe6080604052600436106100ec5760003560e01c806373ce06271161008a578063a81e200b11610059578063a81e200b1461026a578063b34ee91b1461028a578063f851a440146102aa578063fa461e33146102ca57600080fd5b806373ce0627146101f757806377cc4e9a1461021757806393b3774c1461023757806396de7aa01461024a57600080fd5b80633f023230116100c65780633f023230146101785780635c975abb1461018d5780635efc9dcd146101b7578063656745aa146101d757600080fd5b80632646478b146100f85780632c8958f61461011e5780633accfa6c1461014057600080fd5b366100f357005b600080fd5b61010b61010636600461240a565b6102ea565b6040519081526020015b60405180910390f35b34801561012a57600080fd5b5061013e61013936600461258e565b61036f565b005b34801561014c57600080fd5b50600254610160906001600160a01b031681565b6040516001600160a01b039091168152602001610115565b34801561018457600080fd5b5061013e61040d565b34801561019957600080fd5b50600254600160a01b900460ff166040519015158152602001610115565b3480156101c357600080fd5b5061013e6101d23660046122a0565b6104bd565b3480156101e357600080fd5b5061013e6101f23660046122a0565b61053c565b34801561020357600080fd5b50600354610160906001600160a01b031681565b34801561022357600080fd5b5061013e6102323660046122a0565b6105b4565b61010b610245366004612491565b61062c565b34801561025657600080fd5b5061013e6102653660046122a0565b6106c1565b34801561027657600080fd5b50600554610160906001600160a01b031681565b34801561029657600080fd5b50600454610160906001600160a01b031681565b3480156102b657600080fd5b50600154610160906001600160a01b031681565b3480156102d657600080fd5b5061013e6102e536600461258e565b610735565b6000600260005414156103445760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b60026000556103516107b7565b61035f878787878787610806565b6001600055979650505050505050565b6006546001600160a01b0316331461039a57604051635c8868c560e11b815260040160405180910390fd5b600680546001600160a01b031916600117905560006103bb828401846122a0565b905060008086136103cc57846103ce565b855b9050600081136103f157604051635c8868c560e11b815260040160405180910390fd5b6104056001600160a01b0383163383610c51565b505050505050565b6002546001600160a01b031633146104575760405162461bcd60e51b815260206004820152600d60248201526c6e6f742043616e64696461746560981b604482015260640161033b565b6002546001546040516001600160a01b0392831692909116907f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f90600090a360028054600180546001600160a01b03199081166001600160a01b03841617909155169055565b6001546001600160a01b031633146104e75760405162461bcd60e51b815260040161033b90612727565b600580546001600160a01b0319166001600160a01b0383169081179091556040519081527f5b63ecb9cf822eda2eff61a085df526dda34a89520e32c60dd98f6d2718e68df906020015b60405180910390a150565b6001546001600160a01b031633146105665760405162461bcd60e51b815260040161033b90612727565b600480546001600160a01b0319166001600160a01b0383169081179091556040519081527f6c6548cee62112c33dc4b31463a57934b1e1e3fb0edda850ff84868beaea1a4c90602001610531565b6001546001600160a01b031633146105de5760405162461bcd60e51b815260040161033b90612727565b600380546001600160a01b0319166001600160a01b0383169081179091556040519081527f8fbcedcd8235dbaa973a11fd69b709a18f639a45103ddb133a16b046e38dcb2590602001610531565b6000600260005414156106815760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161033b565b600260005561068e6107b7565b6106a16001600160a01b038a1689610cb9565b6106af878787878787610806565b60016000559998505050505050505050565b6001546001600160a01b031633146106eb5760405162461bcd60e51b815260040161033b90612727565b600280546001600160a01b0319166001600160a01b0383169081179091556040517f8cc40b9abca4a505a92028908f9d913d621d18112c69412806506f02333f26b490600090a250565b6006546001600160a01b0316331461076057604051630eeada1560e11b815260040160405180910390fd5b600680546001600160a01b03191660011790556000610781828401846122a0565b905060008086136107925784610794565b855b9050600081136103f157604051630eeada1560e11b815260040160405180910390fd5b600254600160a01b900460ff16156108045760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015260640161033b565b565b6000806001600160a01b03881673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee146108a9576040516370a0823160e01b81523360048201526001600160a01b038916906370a082319060240160206040518083038186803b15801561086c57600080fd5b505afa158015610880573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108a49190612551565b6108ab565b475b905060006001600160a01b03871673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14610951576040516370a0823160e01b81526001600160a01b0386811660048301528816906370a082319060240160206040518083038186803b15801561091457600080fd5b505afa158015610928573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061094c9190612551565b61095d565b846001600160a01b0316315b604080518082019091528581528551860160208201529091505b805160208201511115610a165760006109968280516001018051915290565b90508060ff16600114156109b2576109ad82610d0a565b610a10565b8060ff16600214156109c8576109ad828b610db2565b8060ff16600314156109dd576109ad82610dd2565b8060ff16600414156109f2576109ad82610df7565b604051633e3bf85d60e01b815260ff8216600482015260240161033b565b50610977565b60006001600160a01b038b1673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14610ab8576040516370a0823160e01b81523360048201526001600160a01b038c16906370a082319060240160206040518083038186803b158015610a7b57600080fd5b505afa158015610a8f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ab39190612551565b610aba565b475b905083610ac78b836127ac565b1015610ae657604051631a9bae5760e31b815260040160405180910390fd5b60055460405163ee18077360e01b81526001600160a01b038b81166004830152602482018b905233604483015289811660648301529091169063ee18077390608401600060405180830381600087803b158015610b4257600080fd5b505af1158015610b56573d6000803e3d6000fd5b506000925050506001600160a01b038a1673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14610bff576040516370a0823160e01b81526001600160a01b0389811660048301528b16906370a082319060240160206040518083038186803b158015610bc257600080fd5b505afa158015610bd6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bfa9190612551565b610c0b565b876001600160a01b0316315b9050610c1789856127ac565b811015610c375760405163858a872160e01b815260040160405180910390fd5b610c41848261282d565b9c9b505050505050505050505050565b6040516001600160a01b038316602482015260448101829052610cb490849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152610e18565b505050565b600080600080600085875af1905080610cb45760405162461bcd60e51b815260206004820152601360248201527211551217d514905394d1915497d19052531151606a1b604482015260640161033b565b6000610d1c8280516014018051915290565b6040516370a0823160e01b81523060048201529091506000906001600160a01b038316906370a082319060240160206040518083038186803b158015610d6157600080fd5b505afa158015610d75573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d999190612551565b90508015610da657600019015b610cb483308484610eea565b6000610dc48380516014018051915290565b9050610cb483338385610eea565b47610df3823073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee84610eea565b5050565b6000610e098280516014018051915290565b9050610df38230836000610f68565b6000610e6d826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166110689092919063ffffffff16565b805190915015610cb45780806020019051810190610e8b9190612536565b610cb45760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161033b565b6000610efc8580516001018051915290565b905060005b8160ff16811015610405576000610f1e8780516002018051915290565b9050600061ffff610f31818416876127e6565b610f3b91906127c4565b9050610f47818661282d565b9450610f5588888884610f68565b505080610f6190612870565b9050610f01565b6000610f7a8580516001018051915290565b905060ff8116610f9657610f9085858585611081565b50611061565b8060ff1660011415610fb357610fae8585858561134a565b611061565b8060ff1660021415610fcb57610fae8585858561150e565b8060ff1660031415610fe357610fae85858585611667565b8060ff1660041415610ffb57610fae85858585611928565b8060ff166005141561101357610fae85858585611b3d565b8060ff166006141561102b57610fae8585858561134a565b8060ff166007141561104357610fae85858585611db8565b604051634059968560e11b815260ff8216600482015260240161033b565b5050505050565b60606110778484600085612005565b90505b9392505050565b6000806110948680516014018051915290565b905060006110a88780516001018051915290565b905060006110bc8880516014018051915290565b9050600080846001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b1580156110fa57600080fd5b505afa15801561110e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611132919061260e565b506001600160701b031691506001600160701b031691508160001480611156575080155b1561117f57604051630f4c971b60e21b81526001600160a01b038616600482015260240161033b565b6000808560ff16600114611194578284611197565b83835b91509150886000146111e2576001600160a01b038b163014156111cd576111c86001600160a01b038b16888b610c51565b61126b565b6111c86001600160a01b038b168c898c612136565b6040516370a0823160e01b81526001600160a01b0388811660048301528391908c16906370a082319060240160206040518083038186803b15801561122657600080fd5b505afa15801561123a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061125e9190612551565b611268919061282d565b98505b60006112798a6103e56127e6565b905080611288846103e86127e6565b61129291906127ac565b61129c83836127e6565b6112a691906127c4565b98506000808860ff166001146112be578a60006112c2565b60008b5b6040805160008152602081019182905263022c0d9f60e01b90915291935091506001600160a01b038b169063022c0d9f9061130690859085908d906024810161274a565b600060405180830381600087803b15801561132057600080fd5b505af1158015611334573d6000803e3d6000fd5b5050505050505050505050505050949350505050565b600061135c8580516014018051915290565b90506000806113718780516001018051915290565b60ff1611905060006113898780516014018051915290565b90506001600160a01b03861630146113e4576001600160a01b03861633146113cf57604051630336a30160e11b81526001600160a01b038716600482015260240161033b565b6113e46001600160a01b038616333087612136565b600680546001600160a01b0319166001600160a01b03851690811790915563128acb08828487816114335761142e600173fffd8963efd1fc6a506488495d951d5263988d26612805565b611443565b6114436401000276a36001612781565b604080516001600160a01b038d166020820152016040516020818303038152906040526040518663ffffffff1660e01b81526004016114869594939291906126d9565b6040805180830381600087803b15801561149f57600080fd5b505af11580156114b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114d7919061256a565b50506006546001600160a01b031660011461150557604051630eeada1560e11b815260040160405180910390fd5b50505050505050565b60006115208580516001018051915290565b905060006115348680516014018051915290565b9050600180831614156115d45760006115538780516014018051915290565b9050806001600160a01b031663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b15801561159057600080fd5b505af11580156115a4573d6000803e3d6000fd5b505050506001600160a01b038316301490506115ce576115ce6001600160a01b0382168386610c51565b50610405565b6001600160a01b03851630146115f9576115f96001600160a01b038516863086612136565b604051632e1a7d4d60e01b8152600481018490526001600160a01b03851690632e1a7d4d90602401600060405180830381600087803b15801561163b57600080fd5b505af115801561164f573d6000803e3d6000fd5b50610405925050506001600160a01b03821647610cb9565b60006116798580516001018051915290565b9050600061168d8680516014018051915290565b86516020808201805190920101885290915083156116f1576001600160a01b0386163014156116d5576003546116d0906001600160a01b03878116911686610c51565b611771565b6003546116d0906001600160a01b038781169189911687612136565b6003546040516370a0823160e01b81526001600160a01b039182166004820152908616906370a082319060240160206040518083038186803b15801561173657600080fd5b505afa15801561174a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061176e9190612551565b93505b8260ff1660011415611835576000806000808480602001905181019061179791906123cd565b600354604051630ba1448d60e01b81526001600160a01b03808716600483015260ff8087166024840152851660448301528f8116606483015280841660848301528c811660a483015295995093975091955093509190911690630ba1448d9060c4015b600060405180830381600087803b15801561181457600080fd5b505af1158015611828573d6000803e3d6000fd5b5050505050505050611505565b6000806000806000858060200190518101906118519190612328565b94509450945094509450600360009054906101000a90046001600160a01b03166001600160a01b031663cbf45e88868686868f878e6040518863ffffffff1660e01b81526004016118e897969594939291906001600160a01b039788168152951515602087015260ff94851660408701529290931660608501528416608084015290831660a083015290911660c082015260e00190565b600060405180830381600087803b15801561190257600080fd5b505af1158015611916573d6000803e3d6000fd5b50505050505050505050505050505050565b600061193a8580516014018051915290565b9050600061194e8680516014018051915290565b905060006119628780516014018051915290565b905083156119a9576001600160a01b0386163014156119945761198f6001600160a01b0386168486610c51565b611aa8565b61198f6001600160a01b038616878587612136565b60405163523fba7f60e01b81526001600160a01b03868116600483015284169063523fba7f9060240160206040518083038186803b1580156119ea57600080fd5b505afa1580156119fe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a229190612551565b6040516370a0823160e01b81526001600160a01b0385811660048301528716906370a082319060240160206040518083038186803b158015611a6357600080fd5b505afa158015611a77573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a9b9190612551565b611aa5919061282d565b93505b604051634998b10960e11b81526001600160a01b03868116600483015283811660248301528281166044830152841690639331621290606401602060405180830381600087803b158015611afb57600080fd5b505af1158015611b0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b339190612551565b5050505050505050565b6000611b4f8580516014018051915290565b9050600080611b648780516001018051915290565b60ff161190506000611b7c8780516014018051915290565b9050600080846001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401604080518083038186803b158015611bb957600080fd5b505afa158015611bcd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bf1919061265e565b91509150816001600160801b031660001480611c1457506001600160801b038116155b15611c3d57604051630f4c971b60e21b81526001600160a01b038616600482015260240161033b565b600084611c4b578183611c4e565b82825b506001600160801b031690508615611c9f576001600160a01b038916301415611c8a57611c856001600160a01b0389168789610c51565b611d28565b611c856001600160a01b0389168a888a612136565b6040516370a0823160e01b81526001600160a01b0387811660048301528291908a16906370a082319060240160206040518083038186803b158015611ce357600080fd5b505afa158015611cf7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d1b9190612551565b611d25919061282d565b96505b60405163029e02cd60e51b815285151560048201526001600160a01b0385811660248301528716906353c059a090604401602060405180830381600087803b158015611d7357600080fd5b505af1158015611d87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dab9190612551565b5050505050505050505050565b6000611dca8580516001018051915290565b90506000611dde8680516014018051915290565b8651602080820180519092010188529091508315611e42576001600160a01b038616301415611e2657600454611e21906001600160a01b03878116911686610c51565b611ec4565b600454611e21906001600160a01b038781169189911687612136565b600480546040516370a0823160e01b81526001600160a01b03918216928101929092528616906370a082319060240160206040518083038186803b158015611e8957600080fd5b505afa158015611e9d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ec19190612551565b93505b8260ff1660011415611f525760008060008084806020019051810190611eea9190612375565b60048054604051635f1766e760e11b81526001600160a01b0380881693820193909352600f86810b602483015285900b60448201528f8316606482015282841660848201528c831660a48201529599509397509195509350169063be2ecdce9060c4016117fa565b600080600080600085806020019051810190611f6e91906122bd565b94509450945094509450600460009054906101000a90046001600160a01b03166001600160a01b0316631e7603e6868686868f878e6040518863ffffffff1660e01b81526004016118e897969594939291906001600160a01b0397881681529515156020870152600f94850b60408701529290930b60608501528416608084015290831660a083015290911660c082015260e00190565b6060824710156120665760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161033b565b6001600160a01b0385163b6120bd5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161033b565b600080866001600160a01b031685876040516120d991906126bd565b60006040518083038185875af1925050503d8060008114612116576040519150601f19603f3d011682016040523d82523d6000602084013e61211b565b606091505b509150915061212b828286612174565b979650505050505050565b6040516001600160a01b038085166024830152831660448201526064810182905261216e9085906323b872dd60e01b90608401610c7d565b50505050565b6060831561218357508161107a565b8251156121935782518084602001fd5b8160405162461bcd60e51b815260040161033b9190612714565b805180151581146121bd57600080fd5b919050565b600082601f8301126121d357600080fd5b813567ffffffffffffffff808211156121ee576121ee6128a1565b604051601f8301601f19908116603f01168101908282118183101715612216576122166128a1565b8160405283815286602085880101111561222f57600080fd5b836020870160208301376000602085830101528094505050505092915050565b8051600f81900b81146121bd57600080fd5b80516001600160701b03811681146121bd57600080fd5b80516001600160801b03811681146121bd57600080fd5b805160ff811681146121bd57600080fd5b6000602082840312156122b257600080fd5b813561107a816128b7565b600080600080600060a086880312156122d557600080fd5b85516122e0816128b7565b94506122ee602087016121ad565b93506122fc6040870161224f565b925061230a6060870161224f565b9150608086015161231a816128b7565b809150509295509295909350565b600080600080600060a0868803121561234057600080fd5b855161234b816128b7565b9450612359602087016121ad565b93506123676040870161228f565b925061230a6060870161228f565b6000806000806080858703121561238b57600080fd5b8451612396816128b7565b93506123a46020860161224f565b92506123b26040860161224f565b915060608501516123c2816128b7565b939692955090935050565b600080600080608085870312156123e357600080fd5b84516123ee816128b7565b93506123fc6020860161228f565b92506123b26040860161228f565b60008060008060008060c0878903121561242357600080fd5b863561242e816128b7565b9550602087013594506040870135612445816128b7565b935060608701359250608087013561245c816128b7565b915060a087013567ffffffffffffffff81111561247857600080fd5b61248489828a016121c2565b9150509295509295509295565b600080600080600080600080610100898b0312156124ae57600080fd5b88356124b9816128b7565b97506020890135965060408901356124d0816128b7565b95506060890135945060808901356124e7816128b7565b935060a0890135925060c08901356124fe816128b7565b915060e089013567ffffffffffffffff81111561251a57600080fd5b6125268b828c016121c2565b9150509295985092959890939650565b60006020828403121561254857600080fd5b61107a826121ad565b60006020828403121561256357600080fd5b5051919050565b6000806040838503121561257d57600080fd5b505080516020909101519092909150565b600080600080606085870312156125a457600080fd5b8435935060208501359250604085013567ffffffffffffffff808211156125ca57600080fd5b818701915087601f8301126125de57600080fd5b8135818111156125ed57600080fd5b8860208285010111156125ff57600080fd5b95989497505060200194505050565b60008060006060848603121561262357600080fd5b61262c84612261565b925061263a60208501612261565b9150604084015163ffffffff8116811461265357600080fd5b809150509250925092565b6000806040838503121561267157600080fd5b61267a83612278565b915061268860208401612278565b90509250929050565b600081518084526126a9816020860160208601612844565b601f01601f19169290920160200192915050565b600082516126cf818460208701612844565b9190910192915050565b6001600160a01b0386811682528515156020830152604082018590528316606082015260a06080820181905260009061212b90830184612691565b60208152600061107a6020830184612691565b6020808252600990820152683737ba1030b236b4b760b91b604082015260600190565b84815283602082015260018060a01b03831660408201526080606082015260006127776080830184612691565b9695505050505050565b60006001600160a01b038281168482168083038211156127a3576127a361288b565b01949350505050565b600082198211156127bf576127bf61288b565b500190565b6000826127e157634e487b7160e01b600052601260045260246000fd5b500490565b60008160001904831182151516156128005761280061288b565b500290565b60006001600160a01b03838116908316818110156128255761282561288b565b039392505050565b60008282101561283f5761283f61288b565b500390565b60005b8381101561285f578181015183820152602001612847565b8381111561216e5750506000910152565b60006000198214156128845761288461288b565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b03811681146128cc57600080fd5b5056fea2646970667358221220c7033b57a2370dec5ae58096dcb95eb925704bb15bd06f15c360d67caf820ed264736f6c634300080700330000000000000000000000006d48a5ce3815c29ff1deea157380e896bdb9f3460000000000000000000000001b5a2f88420ff329406d108e641e52e46465f68e000000000000000000000000afcca0f68e0883b797c71525377de46b2e65ab28
Deployed Bytecode
0x6080604052600436106100ec5760003560e01c806373ce06271161008a578063a81e200b11610059578063a81e200b1461026a578063b34ee91b1461028a578063f851a440146102aa578063fa461e33146102ca57600080fd5b806373ce0627146101f757806377cc4e9a1461021757806393b3774c1461023757806396de7aa01461024a57600080fd5b80633f023230116100c65780633f023230146101785780635c975abb1461018d5780635efc9dcd146101b7578063656745aa146101d757600080fd5b80632646478b146100f85780632c8958f61461011e5780633accfa6c1461014057600080fd5b366100f357005b600080fd5b61010b61010636600461240a565b6102ea565b6040519081526020015b60405180910390f35b34801561012a57600080fd5b5061013e61013936600461258e565b61036f565b005b34801561014c57600080fd5b50600254610160906001600160a01b031681565b6040516001600160a01b039091168152602001610115565b34801561018457600080fd5b5061013e61040d565b34801561019957600080fd5b50600254600160a01b900460ff166040519015158152602001610115565b3480156101c357600080fd5b5061013e6101d23660046122a0565b6104bd565b3480156101e357600080fd5b5061013e6101f23660046122a0565b61053c565b34801561020357600080fd5b50600354610160906001600160a01b031681565b34801561022357600080fd5b5061013e6102323660046122a0565b6105b4565b61010b610245366004612491565b61062c565b34801561025657600080fd5b5061013e6102653660046122a0565b6106c1565b34801561027657600080fd5b50600554610160906001600160a01b031681565b34801561029657600080fd5b50600454610160906001600160a01b031681565b3480156102b657600080fd5b50600154610160906001600160a01b031681565b3480156102d657600080fd5b5061013e6102e536600461258e565b610735565b6000600260005414156103445760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b60026000556103516107b7565b61035f878787878787610806565b6001600055979650505050505050565b6006546001600160a01b0316331461039a57604051635c8868c560e11b815260040160405180910390fd5b600680546001600160a01b031916600117905560006103bb828401846122a0565b905060008086136103cc57846103ce565b855b9050600081136103f157604051635c8868c560e11b815260040160405180910390fd5b6104056001600160a01b0383163383610c51565b505050505050565b6002546001600160a01b031633146104575760405162461bcd60e51b815260206004820152600d60248201526c6e6f742043616e64696461746560981b604482015260640161033b565b6002546001546040516001600160a01b0392831692909116907f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f90600090a360028054600180546001600160a01b03199081166001600160a01b03841617909155169055565b6001546001600160a01b031633146104e75760405162461bcd60e51b815260040161033b90612727565b600580546001600160a01b0319166001600160a01b0383169081179091556040519081527f5b63ecb9cf822eda2eff61a085df526dda34a89520e32c60dd98f6d2718e68df906020015b60405180910390a150565b6001546001600160a01b031633146105665760405162461bcd60e51b815260040161033b90612727565b600480546001600160a01b0319166001600160a01b0383169081179091556040519081527f6c6548cee62112c33dc4b31463a57934b1e1e3fb0edda850ff84868beaea1a4c90602001610531565b6001546001600160a01b031633146105de5760405162461bcd60e51b815260040161033b90612727565b600380546001600160a01b0319166001600160a01b0383169081179091556040519081527f8fbcedcd8235dbaa973a11fd69b709a18f639a45103ddb133a16b046e38dcb2590602001610531565b6000600260005414156106815760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161033b565b600260005561068e6107b7565b6106a16001600160a01b038a1689610cb9565b6106af878787878787610806565b60016000559998505050505050505050565b6001546001600160a01b031633146106eb5760405162461bcd60e51b815260040161033b90612727565b600280546001600160a01b0319166001600160a01b0383169081179091556040517f8cc40b9abca4a505a92028908f9d913d621d18112c69412806506f02333f26b490600090a250565b6006546001600160a01b0316331461076057604051630eeada1560e11b815260040160405180910390fd5b600680546001600160a01b03191660011790556000610781828401846122a0565b905060008086136107925784610794565b855b9050600081136103f157604051630eeada1560e11b815260040160405180910390fd5b600254600160a01b900460ff16156108045760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015260640161033b565b565b6000806001600160a01b03881673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee146108a9576040516370a0823160e01b81523360048201526001600160a01b038916906370a082319060240160206040518083038186803b15801561086c57600080fd5b505afa158015610880573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108a49190612551565b6108ab565b475b905060006001600160a01b03871673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14610951576040516370a0823160e01b81526001600160a01b0386811660048301528816906370a082319060240160206040518083038186803b15801561091457600080fd5b505afa158015610928573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061094c9190612551565b61095d565b846001600160a01b0316315b604080518082019091528581528551860160208201529091505b805160208201511115610a165760006109968280516001018051915290565b90508060ff16600114156109b2576109ad82610d0a565b610a10565b8060ff16600214156109c8576109ad828b610db2565b8060ff16600314156109dd576109ad82610dd2565b8060ff16600414156109f2576109ad82610df7565b604051633e3bf85d60e01b815260ff8216600482015260240161033b565b50610977565b60006001600160a01b038b1673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14610ab8576040516370a0823160e01b81523360048201526001600160a01b038c16906370a082319060240160206040518083038186803b158015610a7b57600080fd5b505afa158015610a8f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ab39190612551565b610aba565b475b905083610ac78b836127ac565b1015610ae657604051631a9bae5760e31b815260040160405180910390fd5b60055460405163ee18077360e01b81526001600160a01b038b81166004830152602482018b905233604483015289811660648301529091169063ee18077390608401600060405180830381600087803b158015610b4257600080fd5b505af1158015610b56573d6000803e3d6000fd5b506000925050506001600160a01b038a1673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14610bff576040516370a0823160e01b81526001600160a01b0389811660048301528b16906370a082319060240160206040518083038186803b158015610bc257600080fd5b505afa158015610bd6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bfa9190612551565b610c0b565b876001600160a01b0316315b9050610c1789856127ac565b811015610c375760405163858a872160e01b815260040160405180910390fd5b610c41848261282d565b9c9b505050505050505050505050565b6040516001600160a01b038316602482015260448101829052610cb490849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152610e18565b505050565b600080600080600085875af1905080610cb45760405162461bcd60e51b815260206004820152601360248201527211551217d514905394d1915497d19052531151606a1b604482015260640161033b565b6000610d1c8280516014018051915290565b6040516370a0823160e01b81523060048201529091506000906001600160a01b038316906370a082319060240160206040518083038186803b158015610d6157600080fd5b505afa158015610d75573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d999190612551565b90508015610da657600019015b610cb483308484610eea565b6000610dc48380516014018051915290565b9050610cb483338385610eea565b47610df3823073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee84610eea565b5050565b6000610e098280516014018051915290565b9050610df38230836000610f68565b6000610e6d826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166110689092919063ffffffff16565b805190915015610cb45780806020019051810190610e8b9190612536565b610cb45760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161033b565b6000610efc8580516001018051915290565b905060005b8160ff16811015610405576000610f1e8780516002018051915290565b9050600061ffff610f31818416876127e6565b610f3b91906127c4565b9050610f47818661282d565b9450610f5588888884610f68565b505080610f6190612870565b9050610f01565b6000610f7a8580516001018051915290565b905060ff8116610f9657610f9085858585611081565b50611061565b8060ff1660011415610fb357610fae8585858561134a565b611061565b8060ff1660021415610fcb57610fae8585858561150e565b8060ff1660031415610fe357610fae85858585611667565b8060ff1660041415610ffb57610fae85858585611928565b8060ff166005141561101357610fae85858585611b3d565b8060ff166006141561102b57610fae8585858561134a565b8060ff166007141561104357610fae85858585611db8565b604051634059968560e11b815260ff8216600482015260240161033b565b5050505050565b60606110778484600085612005565b90505b9392505050565b6000806110948680516014018051915290565b905060006110a88780516001018051915290565b905060006110bc8880516014018051915290565b9050600080846001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b1580156110fa57600080fd5b505afa15801561110e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611132919061260e565b506001600160701b031691506001600160701b031691508160001480611156575080155b1561117f57604051630f4c971b60e21b81526001600160a01b038616600482015260240161033b565b6000808560ff16600114611194578284611197565b83835b91509150886000146111e2576001600160a01b038b163014156111cd576111c86001600160a01b038b16888b610c51565b61126b565b6111c86001600160a01b038b168c898c612136565b6040516370a0823160e01b81526001600160a01b0388811660048301528391908c16906370a082319060240160206040518083038186803b15801561122657600080fd5b505afa15801561123a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061125e9190612551565b611268919061282d565b98505b60006112798a6103e56127e6565b905080611288846103e86127e6565b61129291906127ac565b61129c83836127e6565b6112a691906127c4565b98506000808860ff166001146112be578a60006112c2565b60008b5b6040805160008152602081019182905263022c0d9f60e01b90915291935091506001600160a01b038b169063022c0d9f9061130690859085908d906024810161274a565b600060405180830381600087803b15801561132057600080fd5b505af1158015611334573d6000803e3d6000fd5b5050505050505050505050505050949350505050565b600061135c8580516014018051915290565b90506000806113718780516001018051915290565b60ff1611905060006113898780516014018051915290565b90506001600160a01b03861630146113e4576001600160a01b03861633146113cf57604051630336a30160e11b81526001600160a01b038716600482015260240161033b565b6113e46001600160a01b038616333087612136565b600680546001600160a01b0319166001600160a01b03851690811790915563128acb08828487816114335761142e600173fffd8963efd1fc6a506488495d951d5263988d26612805565b611443565b6114436401000276a36001612781565b604080516001600160a01b038d166020820152016040516020818303038152906040526040518663ffffffff1660e01b81526004016114869594939291906126d9565b6040805180830381600087803b15801561149f57600080fd5b505af11580156114b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114d7919061256a565b50506006546001600160a01b031660011461150557604051630eeada1560e11b815260040160405180910390fd5b50505050505050565b60006115208580516001018051915290565b905060006115348680516014018051915290565b9050600180831614156115d45760006115538780516014018051915290565b9050806001600160a01b031663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b15801561159057600080fd5b505af11580156115a4573d6000803e3d6000fd5b505050506001600160a01b038316301490506115ce576115ce6001600160a01b0382168386610c51565b50610405565b6001600160a01b03851630146115f9576115f96001600160a01b038516863086612136565b604051632e1a7d4d60e01b8152600481018490526001600160a01b03851690632e1a7d4d90602401600060405180830381600087803b15801561163b57600080fd5b505af115801561164f573d6000803e3d6000fd5b50610405925050506001600160a01b03821647610cb9565b60006116798580516001018051915290565b9050600061168d8680516014018051915290565b86516020808201805190920101885290915083156116f1576001600160a01b0386163014156116d5576003546116d0906001600160a01b03878116911686610c51565b611771565b6003546116d0906001600160a01b038781169189911687612136565b6003546040516370a0823160e01b81526001600160a01b039182166004820152908616906370a082319060240160206040518083038186803b15801561173657600080fd5b505afa15801561174a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061176e9190612551565b93505b8260ff1660011415611835576000806000808480602001905181019061179791906123cd565b600354604051630ba1448d60e01b81526001600160a01b03808716600483015260ff8087166024840152851660448301528f8116606483015280841660848301528c811660a483015295995093975091955093509190911690630ba1448d9060c4015b600060405180830381600087803b15801561181457600080fd5b505af1158015611828573d6000803e3d6000fd5b5050505050505050611505565b6000806000806000858060200190518101906118519190612328565b94509450945094509450600360009054906101000a90046001600160a01b03166001600160a01b031663cbf45e88868686868f878e6040518863ffffffff1660e01b81526004016118e897969594939291906001600160a01b039788168152951515602087015260ff94851660408701529290931660608501528416608084015290831660a083015290911660c082015260e00190565b600060405180830381600087803b15801561190257600080fd5b505af1158015611916573d6000803e3d6000fd5b50505050505050505050505050505050565b600061193a8580516014018051915290565b9050600061194e8680516014018051915290565b905060006119628780516014018051915290565b905083156119a9576001600160a01b0386163014156119945761198f6001600160a01b0386168486610c51565b611aa8565b61198f6001600160a01b038616878587612136565b60405163523fba7f60e01b81526001600160a01b03868116600483015284169063523fba7f9060240160206040518083038186803b1580156119ea57600080fd5b505afa1580156119fe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a229190612551565b6040516370a0823160e01b81526001600160a01b0385811660048301528716906370a082319060240160206040518083038186803b158015611a6357600080fd5b505afa158015611a77573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a9b9190612551565b611aa5919061282d565b93505b604051634998b10960e11b81526001600160a01b03868116600483015283811660248301528281166044830152841690639331621290606401602060405180830381600087803b158015611afb57600080fd5b505af1158015611b0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b339190612551565b5050505050505050565b6000611b4f8580516014018051915290565b9050600080611b648780516001018051915290565b60ff161190506000611b7c8780516014018051915290565b9050600080846001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401604080518083038186803b158015611bb957600080fd5b505afa158015611bcd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bf1919061265e565b91509150816001600160801b031660001480611c1457506001600160801b038116155b15611c3d57604051630f4c971b60e21b81526001600160a01b038616600482015260240161033b565b600084611c4b578183611c4e565b82825b506001600160801b031690508615611c9f576001600160a01b038916301415611c8a57611c856001600160a01b0389168789610c51565b611d28565b611c856001600160a01b0389168a888a612136565b6040516370a0823160e01b81526001600160a01b0387811660048301528291908a16906370a082319060240160206040518083038186803b158015611ce357600080fd5b505afa158015611cf7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d1b9190612551565b611d25919061282d565b96505b60405163029e02cd60e51b815285151560048201526001600160a01b0385811660248301528716906353c059a090604401602060405180830381600087803b158015611d7357600080fd5b505af1158015611d87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dab9190612551565b5050505050505050505050565b6000611dca8580516001018051915290565b90506000611dde8680516014018051915290565b8651602080820180519092010188529091508315611e42576001600160a01b038616301415611e2657600454611e21906001600160a01b03878116911686610c51565b611ec4565b600454611e21906001600160a01b038781169189911687612136565b600480546040516370a0823160e01b81526001600160a01b03918216928101929092528616906370a082319060240160206040518083038186803b158015611e8957600080fd5b505afa158015611e9d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ec19190612551565b93505b8260ff1660011415611f525760008060008084806020019051810190611eea9190612375565b60048054604051635f1766e760e11b81526001600160a01b0380881693820193909352600f86810b602483015285900b60448201528f8316606482015282841660848201528c831660a48201529599509397509195509350169063be2ecdce9060c4016117fa565b600080600080600085806020019051810190611f6e91906122bd565b94509450945094509450600460009054906101000a90046001600160a01b03166001600160a01b0316631e7603e6868686868f878e6040518863ffffffff1660e01b81526004016118e897969594939291906001600160a01b0397881681529515156020870152600f94850b60408701529290930b60608501528416608084015290831660a083015290911660c082015260e00190565b6060824710156120665760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161033b565b6001600160a01b0385163b6120bd5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161033b565b600080866001600160a01b031685876040516120d991906126bd565b60006040518083038185875af1925050503d8060008114612116576040519150601f19603f3d011682016040523d82523d6000602084013e61211b565b606091505b509150915061212b828286612174565b979650505050505050565b6040516001600160a01b038085166024830152831660448201526064810182905261216e9085906323b872dd60e01b90608401610c7d565b50505050565b6060831561218357508161107a565b8251156121935782518084602001fd5b8160405162461bcd60e51b815260040161033b9190612714565b805180151581146121bd57600080fd5b919050565b600082601f8301126121d357600080fd5b813567ffffffffffffffff808211156121ee576121ee6128a1565b604051601f8301601f19908116603f01168101908282118183101715612216576122166128a1565b8160405283815286602085880101111561222f57600080fd5b836020870160208301376000602085830101528094505050505092915050565b8051600f81900b81146121bd57600080fd5b80516001600160701b03811681146121bd57600080fd5b80516001600160801b03811681146121bd57600080fd5b805160ff811681146121bd57600080fd5b6000602082840312156122b257600080fd5b813561107a816128b7565b600080600080600060a086880312156122d557600080fd5b85516122e0816128b7565b94506122ee602087016121ad565b93506122fc6040870161224f565b925061230a6060870161224f565b9150608086015161231a816128b7565b809150509295509295909350565b600080600080600060a0868803121561234057600080fd5b855161234b816128b7565b9450612359602087016121ad565b93506123676040870161228f565b925061230a6060870161228f565b6000806000806080858703121561238b57600080fd5b8451612396816128b7565b93506123a46020860161224f565b92506123b26040860161224f565b915060608501516123c2816128b7565b939692955090935050565b600080600080608085870312156123e357600080fd5b84516123ee816128b7565b93506123fc6020860161228f565b92506123b26040860161228f565b60008060008060008060c0878903121561242357600080fd5b863561242e816128b7565b9550602087013594506040870135612445816128b7565b935060608701359250608087013561245c816128b7565b915060a087013567ffffffffffffffff81111561247857600080fd5b61248489828a016121c2565b9150509295509295509295565b600080600080600080600080610100898b0312156124ae57600080fd5b88356124b9816128b7565b97506020890135965060408901356124d0816128b7565b95506060890135945060808901356124e7816128b7565b935060a0890135925060c08901356124fe816128b7565b915060e089013567ffffffffffffffff81111561251a57600080fd5b6125268b828c016121c2565b9150509295985092959890939650565b60006020828403121561254857600080fd5b61107a826121ad565b60006020828403121561256357600080fd5b5051919050565b6000806040838503121561257d57600080fd5b505080516020909101519092909150565b600080600080606085870312156125a457600080fd5b8435935060208501359250604085013567ffffffffffffffff808211156125ca57600080fd5b818701915087601f8301126125de57600080fd5b8135818111156125ed57600080fd5b8860208285010111156125ff57600080fd5b95989497505060200194505050565b60008060006060848603121561262357600080fd5b61262c84612261565b925061263a60208501612261565b9150604084015163ffffffff8116811461265357600080fd5b809150509250925092565b6000806040838503121561267157600080fd5b61267a83612278565b915061268860208401612278565b90509250929050565b600081518084526126a9816020860160208601612844565b601f01601f19169290920160200192915050565b600082516126cf818460208701612844565b9190910192915050565b6001600160a01b0386811682528515156020830152604082018590528316606082015260a06080820181905260009061212b90830184612691565b60208152600061107a6020830184612691565b6020808252600990820152683737ba1030b236b4b760b91b604082015260600190565b84815283602082015260018060a01b03831660408201526080606082015260006127776080830184612691565b9695505050505050565b60006001600160a01b038281168482168083038211156127a3576127a361288b565b01949350505050565b600082198211156127bf576127bf61288b565b500190565b6000826127e157634e487b7160e01b600052601260045260246000fd5b500490565b60008160001904831182151516156128005761280061288b565b500290565b60006001600160a01b03838116908316818110156128255761282561288b565b039392505050565b60008282101561283f5761283f61288b565b500390565b60005b8381101561285f578181015183820152602001612847565b8381111561216e5750506000910152565b60006000198214156128845761288461288b565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b03811681146128cc57600080fd5b5056fea2646970667358221220c7033b57a2370dec5ae58096dcb95eb925704bb15bd06f15c360d67caf820ed264736f6c63430008070033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000006d48a5ce3815c29ff1deea157380e896bdb9f3460000000000000000000000001b5a2f88420ff329406d108e641e52e46465f68e000000000000000000000000afcca0f68e0883b797c71525377de46b2e65ab28
-----Decoded View---------------
Arg [0] : _stableSwapDispatcher (address): 0x6D48a5Ce3815c29Ff1Deea157380e896bdb9f346
Arg [1] : _curveStableDispatcher (address): 0x1B5a2f88420ff329406D108e641e52E46465F68e
Arg [2] : _feeSettlement (address): 0xAFCCA0f68e0883b797c71525377DE46B2E65AB28
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 0000000000000000000000006d48a5ce3815c29ff1deea157380e896bdb9f346
Arg [1] : 0000000000000000000000001b5a2f88420ff329406d108e641e52e46465f68e
Arg [2] : 000000000000000000000000afcca0f68e0883b797c71525377de46b2e65ab28
Deployed Bytecode Sourcemap
1193:22513:13:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3995:353;;;;;;:::i;:::-;;:::i;:::-;;;19719:25:47;;;19707:2;19692:18;3995:353:13;;;;;;;;16589:519;;;;;;;;;;-1:-1:-1;16589:519:13;;;;;:::i;:::-;;:::i;:::-;;126:29:8;;;;;;;;;;-1:-1:-1;126:29:8;;;;-1:-1:-1;;;;;126:29:8;;;;;;-1:-1:-1;;;;;10422:32:47;;;10404:51;;10392:2;10377:18;126:29:8;10258:203:47;310:228:8;;;;;;;;;;;;;:::i;1615:84:0:-;;;;;;;;;;-1:-1:-1;1685:7:0;;-1:-1:-1;;;1685:7:0;;;;1615:84;;15417:14:47;;15410:22;15392:41;;15380:2;15365:18;1615:84:0;15252:187:47;3401:170:13;;;;;;;;;;-1:-1:-1;3401:170:13;;;;;:::i;:::-;;:::i;3074:226::-;;;;;;;;;;-1:-1:-1;3074:226:13;;;;;:::i;:::-;;:::i;1379:49::-;;;;;;;;;;-1:-1:-1;1379:49:13;;;;-1:-1:-1;;;;;1379:49:13;;;2730:219;;;;;;;;;;-1:-1:-1;2730:219:13;;;;;:::i;:::-;;:::i;4354:501::-;;;;;;:::i;:::-;;:::i;544:146:8:-;;;;;;;;;;-1:-1:-1;544:146:8;;;;;:::i;:::-;;:::i;1491:35:13:-;;;;;;;;;;-1:-1:-1;1491:35:13;;;;-1:-1:-1;;;;;1491:35:13;;;1434:51;;;;;;;;;;-1:-1:-1;1434:51:13;;;;-1:-1:-1;;;;;1434:51:13;;;100:20:8;;;;;;;;;;-1:-1:-1;100:20:8;;;;-1:-1:-1;;;;;100:20:8;;;14081:517:13;;;;;;;;;;-1:-1:-1;14081:517:13;;;;;:::i;:::-;;:::i;3995:353::-;4231:17;1744:1:1;2325:7;;:19;;2317:63;;;;-1:-1:-1;;;2317:63:1;;19415:2:47;2317:63:1;;;19397:21:47;19454:2;19434:18;;;19427:30;19493:33;19473:18;;;19466:61;19544:18;;2317:63:1;;;;;;;;;1744:1;2455:7;:18;1239:19:0::1;:17;:19::i;:::-;4267:74:13::2;4288:7;4297:8;4307;4317:12;4331:2;4335:5;4267:20;:74::i;:::-;1701:1:1::0;2628:7;:22;4260:81:13;3995:353;-1:-1:-1;;;;;;;3995:353:13:o;16589:519::-;16742:14;;-1:-1:-1;;;;;16742:14:13;16728:10;:28;16724:64;;16765:23;;-1:-1:-1;;;16765:23:13;;;;;;;;;;;16724:64;16798:14;:50;;-1:-1:-1;;;;;;16798:50:13;355:42:9;16798:50:13;;;:14;16878:27;;;;16889:4;16878:27;:::i;:::-;16858:47;;16915:13;16946:1;16931:12;:16;:46;;16965:12;16931:46;;;16950:12;16931:46;16915:62;;17001:1;16991:6;:11;16987:47;;17011:23;;-1:-1:-1;;;17011:23:13;;;;;;;;;;;16987:47;17044:57;-1:-1:-1;;;;;17044:28:13;;17073:10;17093:6;17044:28;:57::i;:::-;16714:394;;16589:519;;;;:::o;310:228:8:-;379:14;;-1:-1:-1;;;;;379:14:8;365:10;:28;357:54;;;;-1:-1:-1;;;357:54:8;;17619:2:47;357:54:8;;;17601:21:47;17658:2;17638:18;;;17631:30;-1:-1:-1;;;17677:18:47;;;17670:43;17730:18;;357:54:8;17417:337:47;357:54:8;446:14;;;439:5;426:35;;-1:-1:-1;;;;;446:14:8;;;;439:5;;;;426:35;;446:14;;426:35;480:14;;;;472:22;;-1:-1:-1;;;;;;472:22:8;;;-1:-1:-1;;;;;480:14:8;;472:22;;;;504:27;;;310:228::o;3401:170:13:-;747:5:8;;-1:-1:-1;;;;;747:5:8;733:10;:19;725:41;;;;-1:-1:-1;;;725:41:8;;;;;;;:::i;:::-;3487:13:13::1;:30:::0;;-1:-1:-1;;;;;;3487:30:13::1;-1:-1:-1::0;;;;;3487:30:13;::::1;::::0;;::::1;::::0;;;3532:32:::1;::::0;10404:51:47;;;3532:32:13::1;::::0;10392:2:47;10377:18;3532:32:13::1;;;;;;;;3401:170:::0;:::o;3074:226::-;747:5:8;;-1:-1:-1;;;;;747:5:8;733:10;:19;725:41;;;;-1:-1:-1;;;725:41:8;;;;;;;:::i;:::-;3184:21:13::1;:46:::0;;-1:-1:-1;;;;;;3184:46:13::1;-1:-1:-1::0;;;;;3184:46:13;::::1;::::0;;::::1;::::0;;;3245:48:::1;::::0;10404:51:47;;;3245:48:13::1;::::0;10392:2:47;10377:18;3245:48:13::1;10258:203:47::0;2730:219:13;747:5:8;;-1:-1:-1;;;;;747:5:8;733:10;:19;725:41;;;;-1:-1:-1;;;725:41:8;;;;;;;:::i;:::-;2837:20:13::1;:44:::0;;-1:-1:-1;;;;;;2837:44:13::1;-1:-1:-1::0;;;;;2837:44:13;::::1;::::0;;::::1;::::0;;;2896:46:::1;::::0;10404:51:47;;;2896:46:13::1;::::0;10392:2:47;10377:18;2896:46:13::1;10258:203:47::0;4354:501:13;4676:17;1744:1:1;2325:7;;:19;;2317:63;;;;-1:-1:-1;;;2317:63:1;;19415:2:47;2317:63:1;;;19397:21:47;19454:2;19434:18;;;19427:30;19493:33;19473:18;;;19466:61;19544:18;;2317:63:1;19213:355:47;2317:63:1;1744:1;2455:7;:18;1239:19:0::1;:17;:19::i;:::-;4705:52:13::2;-1:-1:-1::0;;;;;4705:31:13;::::2;4737:19:::0;4705:31:::2;:52::i;:::-;4774:74;4795:7;4804:8;4814;4824:12;4838:2;4842:5;4774:20;:74::i;:::-;1701:1:1::0;2628:7;:22;4767:81:13;4354:501;-1:-1:-1;;;;;;;;;4354:501:13:o;544:146:8:-;747:5;;-1:-1:-1;;;;;747:5:8;733:10;:19;725:41;;;;-1:-1:-1;;;725:41:8;;;;;;;:::i;:::-;620:14:::1;:27:::0;;-1:-1:-1;;;;;;620:27:8::1;-1:-1:-1::0;;;;;620:27:8;::::1;::::0;;::::1;::::0;;;662:21:::1;::::0;::::1;::::0;-1:-1:-1;;662:21:8::1;544:146:::0;:::o;14081:517:13:-;14236:14;;-1:-1:-1;;;;;14236:14:13;14222:10;:28;14218:62;;14259:21;;-1:-1:-1;;;14259:21:13;;;;;;;;;;;14218:62;14290:14;:50;;-1:-1:-1;;;;;;14290:50:13;355:42:9;14290:50:13;;;:14;14370:27;;;;14381:4;14370:27;:::i;:::-;14350:47;;14407:13;14438:1;14423:12;:16;:46;;14457:12;14423:46;;;14442:12;14423:46;14407:62;;14493:1;14483:6;:11;14479:45;;14503:21;;-1:-1:-1;;;14503:21:13;;;;;;;;;;;1767:106:0;1685:7;;-1:-1:-1;;;1685:7:0;;;;1836:9;1828:38;;;;-1:-1:-1;;;1828:38:0;;17274:2:47;1828:38:0;;;17256:21:47;17313:2;17293:18;;;17286:30;-1:-1:-1;;;17332:18:47;;;17325:46;17388:18;;1828:38:0;17072:340:47;1828:38:0;1767:106::o;5279:1685:13:-;5487:17;;-1:-1:-1;;;;;5543:35:13;;208:42:9;5543:35:13;:125;;5631:37;;-1:-1:-1;;;5631:37:13;;5657:10;5631:37;;;10404:51:47;-1:-1:-1;;;;;5631:25:13;;;;;10377:18:47;;5631:37:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;5543:125;;;5594:21;5543:125;5516:152;-1:-1:-1;5678:25:13;-1:-1:-1;;;;;5706:36:13;;208:42:9;5706:36:13;:117;;5793:30;;-1:-1:-1;;;5793:30:13;;-1:-1:-1;;;;;10422:32:47;;;5793:30:13;;;10404:51:47;5793:26:13;;;;;10377:18:47;;5793:30:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;5706:117;;;5766:2;-1:-1:-1;;;;;5758:19:13;;5706:117;213:4:11;207:11;;244:15;;;231:29;;;273:20;;;320:11;;368:17;;363:2;351:15;;344:42;5678:145:13;;-1:-1:-1;5892:410:13;558:13:11;;612:2;600:15;;594:22;-1:-1:-1;5892:410:13;;;5934:17;5954:18;:6;780:13:11;;822:1;813:11;844:10;;867:19;;844:10;667:235;5954:18:13;5934:38;;5990:11;:16;;6005:1;5990:16;5986:305;;;6008:23;6024:6;6008:15;:23::i;:::-;5986:305;;;6054:11;:16;;6069:1;6054:16;6050:241;;;6072:35;6090:6;6098:8;6072:17;:35::i;6050:241::-;6130:11;:16;;6145:1;6130:16;6126:165;;;6148:22;6163:6;6148:14;:22::i;6126:165::-;6193:11;:16;;6208:1;6193:16;6189:102;;;6211:23;6227:6;6211:15;:23::i;6189:102::-;6260:31;;-1:-1:-1;;;6260:31:13;;20390:4:47;20378:17;;6260:31:13;;;20360:36:47;20333:18;;6260:31:13;20218:184:47;6189:102:13;5920:382;5892:410;;;6312:22;-1:-1:-1;;;;;6337:35:13;;208:42:9;6337:35:13;:125;;6425:37;;-1:-1:-1;;;6425:37:13;;6451:10;6425:37;;;10404:51:47;-1:-1:-1;;;;;6425:25:13;;;;;10377:18:47;;6425:37:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;6337:125;;;6388:21;6337:125;6312:150;-1:-1:-1;6504:16:13;6476:25;6493:8;6312:150;6476:25;:::i;:::-;:44;6472:87;;;6529:30;;-1:-1:-1;;;6529:30:13;;;;;;;;;;;6472:87;6570:13;;:71;;-1:-1:-1;;;6570:71:13;;-1:-1:-1;;;;;14450:15:47;;;6570:71:13;;;14432:34:47;14482:18;;;14475:34;;;6626:10:13;14525:18:47;;;14518:43;14597:15;;;14577:18;;;14570:43;6570:13:13;;;;:31;;14366:19:47;;6570:71:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;6652:23:13;;-1:-1:-1;;;;;;;;6678:36:13;;208:42:9;6678:36:13;:117;;6765:30;;-1:-1:-1;;;6765:30:13;;-1:-1:-1;;;;;10422:32:47;;;6765:30:13;;;10404:51:47;6765:26:13;;;;;10377:18:47;;6765:30:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;6678:117;;;6738:2;-1:-1:-1;;;;;6730:19:13;;6678:117;6652:143;-1:-1:-1;6827:32:13;6847:12;6827:17;:32;:::i;:::-;6809:15;:50;6805:94;;;6868:31;;-1:-1:-1;;;6868:31:13;;;;;;;;;;;6805:94;6922:35;6940:17;6922:15;:35;:::i;:::-;6910:47;5279:1685;-1:-1:-1;;;;;;;;;;;;5279:1685:13:o;763:205:4:-;902:58;;-1:-1:-1;;;;;14076:32:47;;902:58:4;;;14058:51:47;14125:18;;;14118:34;;;875:86:4;;895:5;;-1:-1:-1;;;925:23:4;14031:18:47;;902:58:4;;;;-1:-1:-1;;902:58:4;;;;;;;;;;;;;;-1:-1:-1;;;;;902:58:4;-1:-1:-1;;;;;;902:58:4;;;;;;;;;;875:19;:86::i;:::-;763:205;;;:::o;799:339:46:-;871:12;1070:1;1067;1064;1061;1053:6;1049:2;1042:5;1037:35;1026:46;;1100:7;1092:39;;;;-1:-1:-1;;;1092:39:46;;18319:2:47;1092:39:46;;;18301:21:47;18358:2;18338:18;;;18331:30;-1:-1:-1;;;18377:18:47;;;18370:49;18436:18;;1092:39:46;18117:343:47;7490:355:13;7549:13;7565:20;:6;1754:13:11;;1796:2;1787:12;1819:10;;1842:19;;1819:10;1637:240;7565:20:13;7617:38;;-1:-1:-1;;;7617:38:13;;7649:4;7617:38;;;10404:51:47;7549:36:13;;-1:-1:-1;7595:19:13;;-1:-1:-1;;;;;7617:23:13;;;;;10377:18:47;;7617:38:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;7595:60;-1:-1:-1;7693:15:13;;7689:37;;-1:-1:-1;;7710:16:13;7689:37;7777:61;7796:6;7812:4;7819:5;7826:11;7777:18;:61::i;8095:193::-;8177:13;8193:20;:6;1754:13:11;;1796:2;1787:12;1819:10;;1842:19;;1819:10;1637:240;8193:20:13;8177:36;;8223:58;8242:6;8250:10;8262:5;8269:11;8223:18;:58::i;7107:198::-;7187:21;7218:80;7237:6;7253:4;208:42:9;7187:21:13;7218:18;:80::i;:::-;7155:150;7107:198;:::o;9340:150::-;9399:13;9415:20;:6;1754:13:11;;1796:2;1787:12;1819:10;;1842:19;;1819:10;1637:240;9415:20:13;9399:36;;9445:38;9451:6;9467:4;9474:5;9481:1;9445:5;:38::i;3747:706:4:-;4166:23;4192:69;4220:4;4192:69;;;;;;;;;;;;;;;;;4200:5;-1:-1:-1;;;;;4192:27:4;;;:69;;;;;:::i;:::-;4275:17;;4166:95;;-1:-1:-1;4275:21:4;4271:176;;4370:10;4359:30;;;;;;;;;;;;:::i;:::-;4351:85;;;;-1:-1:-1;;;4351:85:4;;18667:2:47;4351:85:4;;;18649:21:47;18706:2;18686:18;;;18679:30;18745:34;18725:18;;;18718:62;-1:-1:-1;;;18796:18:47;;;18789:40;18846:19;;4351:85:4;18465:406:47;8603:439:13;8758:9;8770:18;:6;780:13:11;;822:1;813:11;844:10;;867:19;;844:10;667:235;8770:18:13;8758:30;;8803:9;8798:238;8822:3;8818:7;;:1;:7;8798:238;;;8846:12;8861:19;:6;1023:13:11;;1065:1;1056:11;1087:10;;1110:19;;1087:10;908:237;8861:19:13;8846:34;-1:-1:-1;8894:14:13;8935:5;8912:19;;;;:11;:19;:::i;:::-;8911:29;;;;:::i;:::-;8894:46;-1:-1:-1;8954:21:13;8894:46;8954:21;;:::i;:::-;;;8989:36;8995:6;9003:4;9009:7;9018:6;8989:5;:36::i;:::-;8832:204;;8827:3;;;;:::i;:::-;;;8798:238;;9717:810;9815:14;9832:18;:6;780:13:11;;822:1;813:11;844:10;;867:19;;844:10;667:235;9832:18:13;9815:35;-1:-1:-1;9864:13:13;;;9860:660;;9879:43;9890:6;9898:4;9904:7;9913:8;9879:10;:43::i;:::-;;9860:660;;;9941:8;:13;;9953:1;9941:13;9937:583;;;9956:43;9967:6;9975:4;9981:7;9990:8;9956:10;:43::i;:::-;9937:583;;;10018:8;:13;;10030:1;10018:13;10014:506;;;10033:44;10045:6;10053:4;10059:7;10068:8;10033:11;:44::i;10014:506::-;10096:8;:13;;10108:1;10096:13;10092:428;;;10111:48;10127:6;10135:4;10141:7;10150:8;10111:15;:48::i;10092:428::-;10178:8;:13;;10190:1;10178:13;10174:346;;;10193:41;10202:6;10210:4;10216:7;10225:8;10193;:41::i;10174:346::-;10253:8;:13;;10265:1;10253:13;10249:271;;;10268:43;10279:6;10287:4;10293:7;10302:8;10268:10;:43::i;10249:271::-;10330:8;:13;;10342:1;10330:13;10326:194;;;10345:45;10358:6;10366:4;10372:7;10381:8;10345:12;:45::i;10326:194::-;10409:8;:13;;10421:1;10409:13;10405:115;;;10424:49;10441:6;10449:4;10455:7;10464:8;10424:16;:49::i;10405:115::-;10495:25;;-1:-1:-1;;;10495:25:13;;20390:4:47;20378:17;;10495:25:13;;;20360:36:47;20333:18;;10495:25:13;20218:184:47;10405:115:13;9805:722;9717:810;;;;:::o;3861:223:5:-;3994:12;4025:52;4047:6;4055:4;4061:1;4064:12;4025:21;:52::i;:::-;4018:59;;3861:223;;;;;;:::o;10767:1314:13:-;10910:17;10939:12;10954:20;:6;1754:13:11;;1796:2;1787:12;1819:10;;1842:19;;1819:10;1637:240;10954:20:13;10939:35;;10984:15;11002:18;:6;780:13:11;;822:1;813:11;844:10;;867:19;;844:10;667:235;11002:18:13;10984:36;;11030:10;11043:20;:6;1754:13:11;;1796:2;1787:12;1819:10;;1842:19;;1819:10;1637:240;11043:20:13;11030:33;;11075:16;11093;11121:4;-1:-1:-1;;;;;11115:23:13;;:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;11074:66;-1:-1:-1;;;;;11074:66:13;;;-1:-1:-1;;;;;11074:66:13;;;11154:8;11166:1;11154:13;:30;;;-1:-1:-1;11171:13:13;;11154:30;11150:60;;;11193:17;;-1:-1:-1;;;11193:17:13;;-1:-1:-1;;;;;10422:32:47;;11193:17:13;;;10404:51:47;10377:18;;11193:17:13;10258:203:47;11150:60:13;11221:17;11240:18;11262:9;:14;;11275:1;11262:14;:86;;11329:8;11339;11262:86;;;11293:8;11303;11262:86;11220:128;;;;11363:8;11375:1;11363:13;11359:361;;-1:-1:-1;;;;;11396:21:13;;11412:4;11396:21;11392:197;;;11437:44;-1:-1:-1;;;;;11437:28:13;;11466:4;11472:8;11437:28;:44::i;:::-;11359:361;;11392:197;11520:54;-1:-1:-1;;;;;11520:32:13;;11553:4;11559;11565:8;11520:32;:54::i;11359:361::-;11630:31;;-1:-1:-1;;;11630:31:13;;-1:-1:-1;;;;;10422:32:47;;;11630:31:13;;;10404:51:47;11664:9:13;;11630:25;;;;;;10377:18:47;;11630:31:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:43;;;;:::i;:::-;11619:54;;11359:361;11729:23;11755:14;:8;11766:3;11755:14;:::i;:::-;11729:40;-1:-1:-1;11729:40:13;11825:16;:9;11837:4;11825:16;:::i;:::-;:34;;;;:::i;:::-;11792:28;11810:10;11792:15;:28;:::i;:::-;11791:69;;;;:::i;:::-;11779:81;;11871:18;11891;11913:9;:14;;11926:1;11913:14;:92;;11983:9;12002:1;11913:92;;;11952:1;11956:9;11913:92;12061:12;;;12071:1;12061:12;;;;;;;;;-1:-1:-1;;;12016:58:13;;;11870:135;;-1:-1:-1;11870:135:13;-1:-1:-1;;;;;;12016:16:13;;;;;:58;;11870:135;;;;12057:2;;12016:58;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;10929:1152;;;;;;;;;;10767:1314;;;;;;:::o;12321:851::-;12462:12;12477:20;:6;1754:13:11;;1796:2;1787:12;1819:10;;1842:19;;1819:10;1637:240;12477:20:13;12462:35;;12507:15;12546:1;12525:18;:6;780:13:11;;822:1;813:11;844:10;;867:19;;844:10;667:235;12525:18:13;:22;;;12507:40;;12557:17;12577:20;:6;1754:13:11;;1796:2;1787:12;1819:10;;1842:19;;1819:10;1637:240;12577:20:13;12557:40;-1:-1:-1;;;;;;12612:21:13;;12628:4;12612:21;12608:190;;-1:-1:-1;;;;;12653:19:13;;12662:10;12653:19;12649:55;;12681:23;;-1:-1:-1;;;12681:23:13;;-1:-1:-1;;;;;10422:32:47;;12681:23:13;;;10404:51:47;10377:18;;12681:23:13;10258:203:47;12649:55:13;12718:69;-1:-1:-1;;;;;12718:32:13;;12751:10;12771:4;12778:8;12718:32;:69::i;:::-;12808:14;:21;;-1:-1:-1;;;;;;12808:21:13;-1:-1:-1;;;;;12808:21:13;;;;;;;;12839:25;12878:9;12901:10;12932:8;12901:10;12955:72;;12999:28;13026:1;747:49:9;12999:28:13;:::i;:::-;12955:72;;;12968:28;567:10:9;12995:1:13;12968:28;:::i;:::-;13041:19;;;-1:-1:-1;;;;;10422:32:47;;13041:19:13;;;10404:51:47;10377:18;13041:19:13;;;;;;;;;;;;12839:231;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;13084:14:13;;-1:-1:-1;;;;;13084:14:13;355:42:9;13084:51:13;13080:85;;13144:21;;-1:-1:-1;;;13144:21:13;;;;;;;;;;;13080:85;12452:720;;;12321:851;;;;:::o;17368:693::-;17513:15;17531:18;:6;780:13:11;;822:1;813:11;844:10;;867:19;;844:10;667:235;17531:18:13;17513:36;;17559:10;17572:20;:6;1754:13:11;;1796:2;1787:12;1819:10;;1842:19;;1819:10;1637:240;17572:20:13;17559:33;-1:-1:-1;17619:1:13;17607:13;;;:18;17603:452;;;17641:17;17661:20;:6;1754:13:11;;1796:2;1787:12;1819:10;;1842:19;;1819:10;1637:240;17661:20:13;17641:40;;17701:9;-1:-1:-1;;;;;17695:24:13;;17727:8;17695:43;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;17756:19:13;;17770:4;17756:19;;-1:-1:-1;17752:69:13;;17777:44;-1:-1:-1;;;;;17777:30:13;;17808:2;17812:8;17777:30;:44::i;:::-;17627:205;17603:452;;;-1:-1:-1;;;;;17856:21:13;;17872:4;17856:21;17852:90;;17879:63;-1:-1:-1;;;;;17879:32:13;;17912:4;17926;17933:8;17879:32;:63::i;:::-;17956:33;;-1:-1:-1;;;17956:33:13;;;;;19719:25:47;;;-1:-1:-1;;;;;17956:23:13;;;;;19692:18:47;;17956:33:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;18003:41:13;;-1:-1:-1;;;;;;;;18003:18:13;;18022:21;18003:18;:41::i;18374:1413::-;18523:16;18542:18;:6;780:13:11;;822:1;813:11;844:10;;867:19;;844:10;667:235;18542:18:13;18523:37;;18570:10;18583:20;:6;1754:13:11;;1796:2;1787:12;1819:10;;1842:19;;1819:10;1637:240;18583:20:13;2003:13:11;;2045:2;2036:12;;;2075:10;;2113:16;;;;2098:32;;18570:33:13;;-1:-1:-1;18669:13:13;;18665:424;;-1:-1:-1;;;;;18702:21:13;;18718:4;18702:21;18698:247;;;18780:20;;18743:69;;-1:-1:-1;;;;;18743:28:13;;;;18780:20;18803:8;18743:28;:69::i;:::-;18665:424;;18698:247;18898:20;;18851:79;;-1:-1:-1;;;;;18851:32:13;;;;18884:4;;18898:20;18921:8;18851:32;:79::i;18665:424::-;19020:20;;18986:56;;-1:-1:-1;;;18986:56:13;;-1:-1:-1;;;;;19020:20:13;;;18986:56;;;10404:51:47;18986:25:13;;;;;;10377:18:47;;18986:56:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;18975:67;;18665:424;19111:10;:15;;19125:1;19111:15;19107:674;;;19143:12;19157:18;19177:19;19198:16;19246:8;19218:101;;;;;;;;;;;;:::i;:::-;19333:20;;:93;;-1:-1:-1;;;19333:93:13;;-1:-1:-1;;;;;14959:15:47;;;19333:93:13;;;14941:34:47;15023:4;15011:17;;;14991:18;;;14984:45;15065:17;;15045:18;;;15038:45;15119:15;;;15099:18;;;15092:43;15172:15;;;15151:19;;;15144:44;15225:15;;;15204:19;;;15197:44;19142:177:13;;-1:-1:-1;19142:177:13;;-1:-1:-1;19142:177:13;;-1:-1:-1;19142:177:13;-1:-1:-1;19333:20:13;;;;;:35;;14875:19:47;;19333:93:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;19128:309;;;;19107:674;;;19458:12;19472:17;19491:18;19511:19;19532:16;19580:8;19552:107;;;;;;;;;;;;:::i;:::-;19457:202;;;;;;;;;;19673:20;;;;;;;;;-1:-1:-1;;;;;19673:20:13;-1:-1:-1;;;;;19673:25:13;;19699:4;19705:12;19719;19733:13;19748:7;19757:8;19767:2;19673:97;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;12889:15:47;;;12871:34;;12948:14;;12941:22;12936:2;12921:18;;12914:50;13012:4;13000:17;;;12995:2;12980:18;;12973:45;13054:17;;;;13049:2;13034:18;;13027:45;13109:15;;13103:3;13088:19;;13081:44;13162:15;;;12851:3;13141:19;;13134:44;13215:15;;;13209:3;13194:19;;13187:44;12820:3;12805:19;;12532:705;19673:97:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;19443:338;;;;;18513:1274;;;18374:1413;;;;:::o;21761:741::-;21903:13;21919:20;:6;1754:13:11;;1796:2;1787:12;1819:10;;1842:19;;1819:10;1637:240;21919:20:13;21903:36;;21949:16;21968:20;:6;1754:13:11;;1796:2;1787:12;1819:10;;1842:19;;1819:10;1637:240;21968:20:13;21949:39;;21998:16;22017:20;:6;1754:13:11;;1796:2;1787:12;1819:10;;1842:19;;1819:10;1637:240;22017:20:13;21998:39;-1:-1:-1;22052:13:13;;22048:391;;-1:-1:-1;;;;;22085:21:13;;22101:4;22085:21;22081:199;;;22126:45;-1:-1:-1;;;;;22126:28:13;;22155:5;22162:8;22126:28;:45::i;:::-;22048:391;;22081:199;22210:55;-1:-1:-1;;;;;22210:32:13;;22243:4;22249:5;22256:8;22210:32;:55::i;22048:391::-;22356:36;;-1:-1:-1;;;22356:36:13;;-1:-1:-1;;;;;10422:32:47;;;22356:36:13;;;10404:51:47;22356:27:13;;;;;10377:18:47;;22356:36:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;22321:32;;-1:-1:-1;;;22321:32:13;;-1:-1:-1;;;;;10422:32:47;;;22321::13;;;10404:51:47;22321:25:13;;;;;10377:18:47;;22321:32:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:71;;;;:::i;:::-;22310:82;;22048:391;22448:47;;-1:-1:-1;;;22448:47:13;;-1:-1:-1;;;;;10724:15:47;;;22448:47:13;;;10706:34:47;10776:15;;;10756:18;;;10749:43;10828:15;;;10808:18;;;10801:43;22448:18:13;;;;;10641::47;;22448:47:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;21893:609;;;21761:741;;;;:::o;22739:965::-;22883:12;22898:20;:6;1754:13:11;;1796:2;1787:12;1819:10;;1842:19;;1819:10;1637:240;22898:20:13;22883:35;;22928:13;22965:1;22944:18;:6;780:13:11;;822:1;813:11;844:10;;867:19;;844:10;667:235;22944:18:13;:22;;;22928:38;;22976:17;22996:20;:6;1754:13:11;;1796:2;1787:12;1819:10;;1842:19;;1819:10;1637:240;22996:20:13;22976:40;;23028:16;23046;23074:4;-1:-1:-1;;;;;23066:25:13;;:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;23027:66;;;;23107:8;-1:-1:-1;;;;;23107:13:13;23119:1;23107:13;:30;;;-1:-1:-1;;;;;;23124:13:13;;;23107:30;23103:60;;;23146:17;;-1:-1:-1;;;23146:17:13;;-1:-1:-1;;;;;10422:32:47;;23146:17:13;;;10404:51:47;10377:18;;23146:17:13;10258:203:47;23103:60:13;23174:17;23197:8;:79;;23257:8;23267;23197:79;;;23221:8;23231;23197:79;-1:-1:-1;;;;;;23173:103:13;;-1:-1:-1;23291:13:13;;23287:361;;-1:-1:-1;;;;;23324:21:13;;23340:4;23324:21;23320:197;;;23365:44;-1:-1:-1;;;;;23365:28:13;;23394:4;23400:8;23365:28;:44::i;:::-;23287:361;;23320:197;23448:54;-1:-1:-1;;;;;23448:32:13;;23481:4;23487;23493:8;23448:32;:54::i;23287:361::-;23558:31;;-1:-1:-1;;;23558:31:13;;-1:-1:-1;;;;;10422:32:47;;;23558:31:13;;;10404:51:47;23592:9:13;;23558:25;;;;;;10377:18:47;;23558:31:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:43;;;;:::i;:::-;23547:54;;23287:361;23658:39;;-1:-1:-1;;;23658:39:13;;15637:14:47;;15630:22;23658:39:13;;;15612:41:47;-1:-1:-1;;;;;15689:32:47;;;15669:18;;;15662:60;23658:18:13;;;;;15585::47;;23658:39:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;22873:831;;;;;;22739:965;;;;:::o;20098:1436::-;20248:16;20267:18;:6;780:13:11;;822:1;813:11;844:10;;867:19;;844:10;667:235;20267:18:13;20248:37;;20295:10;20308:20;:6;1754:13:11;;1796:2;1787:12;1819:10;;1842:19;;1819:10;1637:240;20308:20:13;2003:13:11;;2045:2;2036:12;;;2075:10;;2113:16;;;;2098:32;;20295:33:13;;-1:-1:-1;20394:13:13;;20390:427;;-1:-1:-1;;;;;20427:21:13;;20443:4;20427:21;20423:249;;;20505:21;;20468:70;;-1:-1:-1;;;;;20468:28:13;;;;20505:21;20529:8;20468:28;:70::i;:::-;20390:427;;20423:249;20624:21;;20577:80;;-1:-1:-1;;;;;20577:32:13;;;;20610:4;;20624:21;20648:8;20577:32;:80::i;20390:427::-;20747:21;;;20713:57;;-1:-1:-1;;;20713:57:13;;-1:-1:-1;;;;;20747:21:13;;;20713:57;;;10404:51:47;;;;20713:25:13;;;;;10377:18:47;;20713:57:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;20702:68;;20390:427;20839:10;:15;;20853:1;20839:15;20835:693;;;20871:12;20885:19;20906:20;20928:16;20976:8;20948:103;;;;;;;;;;;;:::i;:::-;21065:21;;;:99;;-1:-1:-1;;;21065:99:13;;-1:-1:-1;;;;;13581:15:47;;;21065:99:13;;;13563:34:47;;;;13644:2;13633:22;;;13613:18;;;13606:50;13692:22;;;13672:18;;;13665:50;13751:15;;;13731:18;;;13724:43;13804:15;;;13783:19;;;13776:44;13857:15;;;13836:19;;;13829:44;20870:181:13;;-1:-1:-1;20870:181:13;;-1:-1:-1;20870:181:13;;-1:-1:-1;20870:181:13;-1:-1:-1;21065:21:13;;:41;;13497:19:47;;21065:99:13;13242:637:47;20835:693:13;21196:12;21210:17;21229:19;21250:20;21272:16;21320:8;21292:109;;;;;;;;;;;;:::i;:::-;21195:206;;;;;;;;;;21415:21;;;;;;;;;-1:-1:-1;;;;;21415:21:13;-1:-1:-1;;;;;21415:30:13;;21446:4;21452:12;21466;21480:13;21495:7;21504:8;21514:2;21415:102;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;11596:15:47;;;11578:34;;11655:14;;11648:22;11643:2;11628:18;;11621:50;11718:2;11707:22;;;11702:2;11687:18;;11680:50;11766:22;;;;11761:2;11746:18;;11739:50;11826:15;;11820:3;11805:19;;11798:44;11879:15;;;11558:3;11858:19;;11851:44;11932:15;;;11926:3;11911:19;;11904:44;11527:3;11512:19;;11235:719;4948:499:5;5113:12;5170:5;5145:21;:30;;5137:81;;;;-1:-1:-1;;;5137:81:5;;16867:2:47;5137:81:5;;;16849:21:47;16906:2;16886:18;;;16879:30;16945:34;16925:18;;;16918:62;-1:-1:-1;;;16996:18:47;;;16989:36;17042:19;;5137:81:5;16665:402:47;5137:81:5;-1:-1:-1;;;;;1465:19:5;;;5228:60;;;;-1:-1:-1;;;5228:60:5;;17961:2:47;5228:60:5;;;17943:21:47;18000:2;17980:18;;;17973:30;18039:31;18019:18;;;18012:59;18088:18;;5228:60:5;17759:353:47;5228:60:5;5300:12;5314:23;5341:6;-1:-1:-1;;;;;5341:11:5;5360:5;5367:4;5341:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5299:73;;;;5389:51;5406:7;5415:10;5427:12;5389:16;:51::i;:::-;5382:58;4948:499;-1:-1:-1;;;;;;;4948:499:5:o;974:241:4:-;1139:68;;-1:-1:-1;;;;;11113:15:47;;;1139:68:4;;;11095:34:47;11165:15;;11145:18;;;11138:43;11197:18;;;11190:34;;;1112:96:4;;1132:5;;-1:-1:-1;;;1162:27:4;11030:18:47;;1139:68:4;10855:375:47;1112:96:4;974:241;;;;:::o;7561:742:5:-;7707:12;7735:7;7731:566;;;-1:-1:-1;7765:10:5;7758:17;;7731:566;7876:17;;:21;7872:415;;8120:10;8114:17;8180:15;8167:10;8163:2;8159:19;8152:44;7872:415;8259:12;8252:20;;-1:-1:-1;;;8252:20:5;;;;;;;;:::i;14:164:47:-;90:13;;139;;132:21;122:32;;112:60;;168:1;165;158:12;112:60;14:164;;;:::o;183:718::-;225:5;278:3;271:4;263:6;259:17;255:27;245:55;;296:1;293;286:12;245:55;332:6;319:20;358:18;395:2;391;388:10;385:36;;;401:18;;:::i;:::-;476:2;470:9;444:2;530:13;;-1:-1:-1;;526:22:47;;;550:2;522:31;518:40;506:53;;;574:18;;;594:22;;;571:46;568:72;;;620:18;;:::i;:::-;660:10;656:2;649:22;695:2;687:6;680:18;741:3;734:4;729:2;721:6;717:15;713:26;710:35;707:55;;;758:1;755;748:12;707:55;822:2;815:4;807:6;803:17;796:4;788:6;784:17;771:54;869:1;862:4;857:2;849:6;845:15;841:26;834:37;889:6;880:15;;;;;;183:718;;;;:::o;906:166::-;984:13;;1037:2;1026:21;;;1016:32;;1006:60;;1062:1;1059;1052:12;1077:188;1156:13;;-1:-1:-1;;;;;1198:42:47;;1188:53;;1178:81;;1255:1;1252;1245:12;1270:192;1349:13;;-1:-1:-1;;;;;1391:46:47;;1381:57;;1371:85;;1452:1;1449;1442:12;1467:160;1544:13;;1597:4;1586:16;;1576:27;;1566:55;;1617:1;1614;1607:12;1632:247;1691:6;1744:2;1732:9;1723:7;1719:23;1715:32;1712:52;;;1760:1;1757;1750:12;1712:52;1799:9;1786:23;1818:31;1843:5;1818:31;:::i;2144:648::-;2261:6;2269;2277;2285;2293;2346:3;2334:9;2325:7;2321:23;2317:33;2314:53;;;2363:1;2360;2353:12;2314:53;2395:9;2389:16;2414:31;2439:5;2414:31;:::i;:::-;2464:5;-1:-1:-1;2488:46:47;2530:2;2515:18;;2488:46;:::i;:::-;2478:56;;2553:48;2597:2;2586:9;2582:18;2553:48;:::i;:::-;2543:58;;2620:48;2664:2;2653:9;2649:18;2620:48;:::i;:::-;2610:58;;2713:3;2702:9;2698:19;2692:26;2727:33;2752:7;2727:33;:::i;:::-;2779:7;2769:17;;;2144:648;;;;;;;;:::o;2797:644::-;2912:6;2920;2928;2936;2944;2997:3;2985:9;2976:7;2972:23;2968:33;2965:53;;;3014:1;3011;3004:12;2965:53;3046:9;3040:16;3065:31;3090:5;3065:31;:::i;:::-;3115:5;-1:-1:-1;3139:46:47;3181:2;3166:18;;3139:46;:::i;:::-;3129:56;;3204:47;3247:2;3236:9;3232:18;3204:47;:::i;:::-;3194:57;;3270:47;3313:2;3302:9;3298:18;3270:47;:::i;3446:568::-;3557:6;3565;3573;3581;3634:3;3622:9;3613:7;3609:23;3605:33;3602:53;;;3651:1;3648;3641:12;3602:53;3683:9;3677:16;3702:31;3727:5;3702:31;:::i;:::-;3752:5;-1:-1:-1;3776:48:47;3820:2;3805:18;;3776:48;:::i;:::-;3766:58;;3843:48;3887:2;3876:9;3872:18;3843:48;:::i;:::-;3833:58;;3936:2;3925:9;3921:18;3915:25;3949:33;3974:7;3949:33;:::i;:::-;3446:568;;;;-1:-1:-1;3446:568:47;;-1:-1:-1;;3446:568:47:o;4019:564::-;4128:6;4136;4144;4152;4205:3;4193:9;4184:7;4180:23;4176:33;4173:53;;;4222:1;4219;4212:12;4173:53;4254:9;4248:16;4273:31;4298:5;4273:31;:::i;:::-;4323:5;-1:-1:-1;4347:47:47;4390:2;4375:18;;4347:47;:::i;:::-;4337:57;;4413:47;4456:2;4445:9;4441:18;4413:47;:::i;4588:876::-;4701:6;4709;4717;4725;4733;4741;4794:3;4782:9;4773:7;4769:23;4765:33;4762:53;;;4811:1;4808;4801:12;4762:53;4850:9;4837:23;4869:31;4894:5;4869:31;:::i;:::-;4919:5;-1:-1:-1;4971:2:47;4956:18;;4943:32;;-1:-1:-1;5027:2:47;5012:18;;4999:32;5040:33;4999:32;5040:33;:::i;:::-;5092:7;-1:-1:-1;5146:2:47;5131:18;;5118:32;;-1:-1:-1;5202:3:47;5187:19;;5174:33;5216;5174;5216;:::i;:::-;5268:7;-1:-1:-1;5326:3:47;5311:19;;5298:33;5354:18;5343:30;;5340:50;;;5386:1;5383;5376:12;5340:50;5409:49;5450:7;5441:6;5430:9;5426:22;5409:49;:::i;:::-;5399:59;;;4588:876;;;;;;;;:::o;5469:1087::-;5600:6;5608;5616;5624;5632;5640;5648;5656;5709:3;5697:9;5688:7;5684:23;5680:33;5677:53;;;5726:1;5723;5716:12;5677:53;5765:9;5752:23;5784:31;5809:5;5784:31;:::i;:::-;5834:5;-1:-1:-1;5886:2:47;5871:18;;5858:32;;-1:-1:-1;5942:2:47;5927:18;;5914:32;5955:33;5914:32;5955:33;:::i;:::-;6007:7;-1:-1:-1;6061:2:47;6046:18;;6033:32;;-1:-1:-1;6117:3:47;6102:19;;6089:33;6131;6089;6131;:::i;:::-;6183:7;-1:-1:-1;6237:3:47;6222:19;;6209:33;;-1:-1:-1;6294:3:47;6279:19;;6266:33;6308;6266;6308;:::i;:::-;6360:7;-1:-1:-1;6418:3:47;6403:19;;6390:33;6446:18;6435:30;;6432:50;;;6478:1;6475;6468:12;6432:50;6501:49;6542:7;6533:6;6522:9;6518:22;6501:49;:::i;:::-;6491:59;;;5469:1087;;;;;;;;;;;:::o;6561:202::-;6628:6;6681:2;6669:9;6660:7;6656:23;6652:32;6649:52;;;6697:1;6694;6687:12;6649:52;6720:37;6747:9;6720:37;:::i;6768:184::-;6838:6;6891:2;6879:9;6870:7;6866:23;6862:32;6859:52;;;6907:1;6904;6897:12;6859:52;-1:-1:-1;6930:16:47;;6768:184;-1:-1:-1;6768:184:47:o;7797:243::-;7874:6;7882;7935:2;7923:9;7914:7;7910:23;7906:32;7903:52;;;7951:1;7948;7941:12;7903:52;-1:-1:-1;;7974:16:47;;8030:2;8015:18;;;8009:25;7974:16;;8009:25;;-1:-1:-1;7797:243:47:o;8045:725::-;8131:6;8139;8147;8155;8208:2;8196:9;8187:7;8183:23;8179:32;8176:52;;;8224:1;8221;8214:12;8176:52;8260:9;8247:23;8237:33;;8317:2;8306:9;8302:18;8289:32;8279:42;;8372:2;8361:9;8357:18;8344:32;8395:18;8436:2;8428:6;8425:14;8422:34;;;8452:1;8449;8442:12;8422:34;8490:6;8479:9;8475:22;8465:32;;8535:7;8528:4;8524:2;8520:13;8516:27;8506:55;;8557:1;8554;8547:12;8506:55;8597:2;8584:16;8623:2;8615:6;8612:14;8609:34;;;8639:1;8636;8629:12;8609:34;8684:7;8679:2;8670:6;8666:2;8662:15;8658:24;8655:37;8652:57;;;8705:1;8702;8695:12;8652:57;8045:725;;;;-1:-1:-1;;8736:2:47;8728:11;;-1:-1:-1;;;8045:725:47:o;8775:450::-;8862:6;8870;8878;8931:2;8919:9;8910:7;8906:23;8902:32;8899:52;;;8947:1;8944;8937:12;8899:52;8970:40;9000:9;8970:40;:::i;:::-;8960:50;;9029:49;9074:2;9063:9;9059:18;9029:49;:::i;:::-;9019:59;;9121:2;9110:9;9106:18;9100:25;9165:10;9158:5;9154:22;9147:5;9144:33;9134:61;;9191:1;9188;9181:12;9134:61;9214:5;9204:15;;;8775:450;;;;;:::o;9230:293::-;9309:6;9317;9370:2;9358:9;9349:7;9345:23;9341:32;9338:52;;;9386:1;9383;9376:12;9338:52;9409:40;9439:9;9409:40;:::i;:::-;9399:50;;9468:49;9513:2;9502:9;9498:18;9468:49;:::i;:::-;9458:59;;9230:293;;;;;:::o;9717:257::-;9758:3;9796:5;9790:12;9823:6;9818:3;9811:19;9839:63;9895:6;9888:4;9883:3;9879:14;9872:4;9865:5;9861:16;9839:63;:::i;:::-;9956:2;9935:15;-1:-1:-1;;9931:29:47;9922:39;;;;9963:4;9918:50;;9717:257;-1:-1:-1;;9717:257:47:o;9979:274::-;10108:3;10146:6;10140:13;10162:53;10208:6;10203:3;10196:4;10188:6;10184:17;10162:53;:::i;:::-;10231:16;;;;;9979:274;-1:-1:-1;;9979:274:47:o;11959:568::-;-1:-1:-1;;;;;12248:15:47;;;12230:34;;12307:14;;12300:22;12295:2;12280:18;;12273:50;12354:2;12339:18;;12332:34;;;12402:15;;12397:2;12382:18;;12375:43;12210:3;12449;12434:19;;12427:32;;;12173:4;;12476:45;;12501:19;;12493:6;12476:45;:::i;16441:219::-;16590:2;16579:9;16572:21;16553:4;16610:44;16650:2;16639:9;16635:18;16627:6;16610:44;:::i;18876:332::-;19078:2;19060:21;;;19117:1;19097:18;;;19090:29;-1:-1:-1;;;19150:2:47;19135:18;;19128:39;19199:2;19184:18;;18876:332::o;19755:458::-;19986:6;19975:9;19968:25;20029:6;20024:2;20013:9;20009:18;20002:34;20101:1;20097;20092:3;20088:11;20084:19;20076:6;20072:32;20067:2;20056:9;20052:18;20045:60;20141:3;20136:2;20125:9;20121:18;20114:31;19949:4;20162:45;20202:3;20191:9;20187:19;20179:6;20162:45;:::i;:::-;20154:53;19755:458;-1:-1:-1;;;;;;19755:458:47:o;20407:238::-;20447:3;-1:-1:-1;;;;;20514:10:47;;;20544;;;20574:12;;;20566:21;;20563:47;;;20590:18;;:::i;:::-;20626:13;;20407:238;-1:-1:-1;;;;20407:238:47:o;20650:128::-;20690:3;20721:1;20717:6;20714:1;20711:13;20708:39;;;20727:18;;:::i;:::-;-1:-1:-1;20763:9:47;;20650:128::o;20783:217::-;20823:1;20849;20839:132;;20893:10;20888:3;20884:20;20881:1;20874:31;20928:4;20925:1;20918:15;20956:4;20953:1;20946:15;20839:132;-1:-1:-1;20985:9:47;;20783:217::o;21005:168::-;21045:7;21111:1;21107;21103:6;21099:14;21096:1;21093:21;21088:1;21081:9;21074:17;21070:45;21067:71;;;21118:18;;:::i;:::-;-1:-1:-1;21158:9:47;;21005:168::o;21178:231::-;21218:4;-1:-1:-1;;;;;21316:10:47;;;;21286;;21338:12;;;21335:38;;;21353:18;;:::i;:::-;21390:13;;21178:231;-1:-1:-1;;;21178:231:47:o;21414:125::-;21454:4;21482:1;21479;21476:8;21473:34;;;21487:18;;:::i;:::-;-1:-1:-1;21524:9:47;;21414:125::o;21544:258::-;21616:1;21626:113;21640:6;21637:1;21634:13;21626:113;;;21716:11;;;21710:18;21697:11;;;21690:39;21662:2;21655:10;21626:113;;;21757:6;21754:1;21751:13;21748:48;;;-1:-1:-1;;21792:1:47;21774:16;;21767:27;21544:258::o;21807:135::-;21846:3;-1:-1:-1;;21867:17:47;;21864:43;;;21887:18;;:::i;:::-;-1:-1:-1;21934:1:47;21923:13;;21807:135::o;21947:127::-;22008:10;22003:3;21999:20;21996:1;21989:31;22039:4;22036:1;22029:15;22063:4;22060:1;22053:15;22079:127;22140:10;22135:3;22131:20;22128:1;22121:31;22171:4;22168:1;22161:15;22195:4;22192:1;22185:15;22211:131;-1:-1:-1;;;;;22286:31:47;;22276:42;;22266:70;;22332:1;22329;22322:12;22266:70;22211:131;:::o
Swarm Source
ipfs://c7033b57a2370dec5ae58096dcb95eb925704bb15bd06f15c360d67caf820ed2
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.