Overview
ETH Balance
ETH Value
$0.00Latest 25 from a total of 1,912 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Add Liquidity | 16352153 | 2 days ago | IN | 0 ETH | 0.00000002 | ||||
| Remove Liquidity | 16301580 | 4 days ago | IN | 0 ETH | 0.00000018 | ||||
| Remove Liquidity | 16140143 | 7 days ago | IN | 0 ETH | 0 | ||||
| Remove Liquidity | 16130080 | 8 days ago | IN | 0 ETH | 0 | ||||
| Remove Liquidity | 16109270 | 8 days ago | IN | 0 ETH | 0 | ||||
| Add Liquidity | 15824217 | 15 days ago | IN | 0 ETH | 0 | ||||
| Add Liquidity | 15824148 | 15 days ago | IN | 0 ETH | 0 | ||||
| Remove Liquidity | 15806918 | 15 days ago | IN | 0 ETH | 0 | ||||
| Add Liquidity | 15785632 | 16 days ago | IN | 0 ETH | 0 | ||||
| Add Liquidity | 15785626 | 16 days ago | IN | 0 ETH | 0 | ||||
| Add Liquidity | 15785560 | 16 days ago | IN | 0 ETH | 0 | ||||
| Add Liquidity | 15785552 | 16 days ago | IN | 0 ETH | 0 | ||||
| Remove Liquidity | 15759546 | 16 days ago | IN | 0 ETH | 0 | ||||
| Remove Liquidity | 15756616 | 16 days ago | IN | 0 ETH | 0 | ||||
| Remove Liquidity | 15755335 | 16 days ago | IN | 0 ETH | 0 | ||||
| Remove Liquidity | 15753529 | 16 days ago | IN | 0 ETH | 0 | ||||
| Remove Liquidity | 15753302 | 16 days ago | IN | 0 ETH | 0 | ||||
| Remove Liquidity | 15749200 | 16 days ago | IN | 0 ETH | 0 | ||||
| Remove Liquidity | 15743065 | 17 days ago | IN | 0 ETH | 0 | ||||
| Remove Liquidity | 15736499 | 17 days ago | IN | 0 ETH | 0 | ||||
| Add Liquidity | 15736402 | 17 days ago | IN | 0 ETH | 0 | ||||
| Add Liquidity ET... | 15736252 | 17 days ago | IN | 0.0004647 ETH | 0 | ||||
| Add Liquidity ET... | 15736248 | 17 days ago | IN | 0.0004647 ETH | 0 | ||||
| Remove Liquidity | 15688223 | 18 days ago | IN | 0 ETH | 0 | ||||
| Remove Liquidity | 15687382 | 18 days ago | IN | 0 ETH | 0 |
Latest 25 internal transactions (View All)
| Parent Transaction Hash | Block | From | To | ||||
|---|---|---|---|---|---|---|---|
| 16352153 | 2 days ago | 0 ETH | |||||
| 16352153 | 2 days ago | 0 ETH | |||||
| 16352153 | 2 days ago | 0 ETH | |||||
| 16352153 | 2 days ago | 0 ETH | |||||
| 16352153 | 2 days ago | 0 ETH | |||||
| 16301580 | 4 days ago | 0 ETH | |||||
| 16301580 | 4 days ago | 0 ETH | |||||
| 16140143 | 7 days ago | 0 ETH | |||||
| 16140143 | 7 days ago | 0 ETH | |||||
| 16130080 | 8 days ago | 0 ETH | |||||
| 16130080 | 8 days ago | 0 ETH | |||||
| 16109270 | 8 days ago | 0 ETH | |||||
| 16109270 | 8 days ago | 0 ETH | |||||
| 15824217 | 15 days ago | 0 ETH | |||||
| 15824217 | 15 days ago | 0 ETH | |||||
| 15824217 | 15 days ago | 0 ETH | |||||
| 15824148 | 15 days ago | 0 ETH | |||||
| 15824148 | 15 days ago | 0 ETH | |||||
| 15824148 | 15 days ago | 0 ETH | |||||
| 15824148 | 15 days ago | 0 ETH | |||||
| 15824148 | 15 days ago | 0 ETH | |||||
| 15806918 | 15 days ago | 0 ETH | |||||
| 15806918 | 15 days ago | 0 ETH | |||||
| 15785632 | 16 days ago | 0 ETH | |||||
| 15785632 | 16 days ago | 0 ETH |
Cross-Chain Transactions
Contract Source Code Verified (Exact Match)
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.8.19 <0.9.0;
import {Math} from "@openzeppelin5/contracts/utils/math/Math.sol";
import {IERC20} from "@openzeppelin5/contracts/token/ERC20/IERC20.sol";
import {Clones} from "@openzeppelin5/contracts/proxy/Clones.sol";
import {IPool} from "./interfaces/pools/IPool.sol";
import {IPoolFactory} from "./interfaces/pools/IPoolFactory.sol";
import {IRouter} from "./interfaces/IRouter.sol";
import {IWETH} from "./interfaces/external/IWETH.sol";
/*
██╗ ██╗███████╗██╗ ██████╗ ██████╗ ██████╗ ██████╗ ███╗ ███╗███████╗
██║ ██║██╔════╝██║ ██╔═══██╗██╔══██╗██╔══██╗██╔═══██╗████╗ ████║██╔════╝
██║ ██║█████╗ ██║ ██║ ██║██║ ██║██████╔╝██║ ██║██╔████╔██║█████╗
╚██╗ ██╔╝██╔══╝ ██║ ██║ ██║██║ ██║██╔══██╗██║ ██║██║╚██╔╝██║██╔══╝
╚████╔╝ ███████╗███████╗╚██████╔╝██████╔╝██║ ██║╚██████╔╝██║ ╚═╝ ██║███████╗
╚═══╝ ╚══════╝╚══════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝
███████╗██╗ ██╗██████╗ ███████╗██████╗ ██████╗██╗ ██╗ █████╗ ██╗███╗ ██╗
██╔════╝██║ ██║██╔══██╗██╔════╝██╔══██╗██╔════╝██║ ██║██╔══██╗██║████╗ ██║
███████╗██║ ██║██████╔╝█████╗ ██████╔╝██║ ███████║███████║██║██╔██╗ ██║
╚════██║██║ ██║██╔═══╝ ██╔══╝ ██╔══██╗██║ ██╔══██║██╔══██║██║██║╚██╗██║
███████║╚██████╔╝██║ ███████╗██║ ██║╚██████╗██║ ██║██║ ██║██║██║ ╚████║
╚══════╝ ╚═════╝ ╚═╝ ╚══════╝╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝
██████╗ ██████╗ ██╗ ██╗████████╗███████╗██████╗
██╔══██╗██╔═══██╗██║ ██║╚══██╔══╝██╔════╝██╔══██╗
██████╔╝██║ ██║██║ ██║ ██║ █████╗ ██████╔╝
██╔══██╗██║ ██║██║ ██║ ██║ ██╔══╝ ██╔══██╗
██║ ██║╚██████╔╝╚██████╔╝ ██║ ███████╗██║ ██║
╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚══════╝╚═╝ ╚═╝
*/
/// @title Velodrome Superchain Router
/// @author velodrome.finance, Solidly, Uniswap Labs, @pegahcarter
/// @notice Supports adding and removing liquidity from v2 pools
contract Router is IRouter {
/// @inheritdoc IRouter
address public immutable factory;
/// @inheritdoc IRouter
address public immutable poolImplementation;
/// @inheritdoc IRouter
IWETH public immutable weth;
uint256 internal constant MINIMUM_LIQUIDITY = 10 ** 3;
modifier ensure(uint256 deadline) {
_ensureDeadline(deadline);
_;
}
function _ensureDeadline(uint256 deadline) internal view {
if (deadline < block.timestamp) revert Expired();
}
constructor(address _factory, address _weth) {
factory = _factory;
poolImplementation = IPoolFactory(_factory).implementation();
weth = IWETH(_weth);
}
receive() external payable {
if (msg.sender != address(weth)) revert OnlyWETH();
}
/// @inheritdoc IRouter
function sortTokens(address tokenA, address tokenB) public pure returns (address token0, address token1) {
if (tokenA == tokenB) revert SameAddresses();
(token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
if (token0 == address(0)) revert ZeroAddress();
}
/// @inheritdoc IRouter
function poolFor(address tokenA, address tokenB, bool stable) public view returns (address pool) {
(address token0, address token1) = sortTokens(tokenA, tokenB);
bytes32 salt = keccak256(abi.encodePacked(token0, token1, stable));
pool = Clones.predictDeterministicAddress(poolImplementation, salt, factory);
}
/// @dev given some amount of an asset and pool reserves, returns an equivalent amount of the other asset
/// @dev this only accounts for volatile pools and may return insufficient liquidity for stable pools
function quoteLiquidity(uint256 amountA, uint256 reserveA, uint256 reserveB)
internal
pure
returns (uint256 amountB)
{
if (amountA == 0) revert InsufficientAmount();
if (reserveA == 0 || reserveB == 0) revert InsufficientLiquidity();
amountB = (amountA * reserveB) / reserveA;
}
/// @inheritdoc IRouter
function getReserves(address tokenA, address tokenB, bool stable)
public
view
returns (uint256 reserveA, uint256 reserveB)
{
(address token0,) = sortTokens(tokenA, tokenB);
(uint256 reserve0, uint256 reserve1,) = IPool(poolFor(tokenA, tokenB, stable)).getReserves();
(reserveA, reserveB) = tokenA == token0 ? (reserve0, reserve1) : (reserve1, reserve0);
}
/// @inheritdoc IRouter
function getAmountsOut(uint256 amountIn, Route[] memory routes) public view returns (uint256[] memory amounts) {
if (routes.length < 1) revert InvalidPath();
amounts = new uint256[](routes.length + 1);
amounts[0] = amountIn;
uint256 _length = routes.length;
for (uint256 i = 0; i < _length; i++) {
address pool = poolFor(routes[i].from, routes[i].to, routes[i].stable);
if (IPoolFactory(factory).isPool(pool)) {
amounts[i + 1] = IPool(pool).getAmountOut(amounts[i], routes[i].from);
} else {
revert InvalidPath();
}
}
}
/// @inheritdoc IRouter
function quoteAddLiquidity(
address tokenA,
address tokenB,
bool stable,
uint256 amountADesired,
uint256 amountBDesired
) external view returns (uint256 amountA, uint256 amountB, uint256 liquidity) {
address _pool = IPoolFactory(factory).getPool(tokenA, tokenB, stable);
(uint256 reserveA, uint256 reserveB) = (0, 0);
uint256 _totalSupply = 0;
if (_pool != address(0)) {
_totalSupply = IERC20(_pool).totalSupply();
(reserveA, reserveB) = getReserves(tokenA, tokenB, stable);
}
if (reserveA == 0 && reserveB == 0) {
(amountA, amountB) = (amountADesired, amountBDesired);
liquidity = Math.sqrt(amountA * amountB) - MINIMUM_LIQUIDITY;
} else {
uint256 amountBOptimal = quoteLiquidity(amountADesired, reserveA, reserveB);
if (amountBOptimal <= amountBDesired) {
(amountA, amountB) = (amountADesired, amountBOptimal);
liquidity = Math.min((amountA * _totalSupply) / reserveA, (amountB * _totalSupply) / reserveB);
} else {
uint256 amountAOptimal = quoteLiquidity(amountBDesired, reserveB, reserveA);
(amountA, amountB) = (amountAOptimal, amountBDesired);
liquidity = Math.min((amountA * _totalSupply) / reserveA, (amountB * _totalSupply) / reserveB);
}
}
}
/// @inheritdoc IRouter
function quoteRemoveLiquidity(address tokenA, address tokenB, bool stable, uint256 liquidity)
external
view
returns (uint256 amountA, uint256 amountB)
{
address _pool = IPoolFactory(factory).getPool(tokenA, tokenB, stable);
if (_pool == address(0)) {
return (0, 0);
}
(uint256 reserveA, uint256 reserveB) = getReserves(tokenA, tokenB, stable);
uint256 _totalSupply = IERC20(_pool).totalSupply();
amountA = (liquidity * reserveA) / _totalSupply; // using balances ensures pro-rata distribution
amountB = (liquidity * reserveB) / _totalSupply; // using balances ensures pro-rata distribution
}
function _addLiquidity(
address tokenA,
address tokenB,
bool stable,
uint256 amountADesired,
uint256 amountBDesired,
uint256 amountAMin,
uint256 amountBMin
) internal returns (uint256 amountA, uint256 amountB) {
if (amountADesired < amountAMin) revert InsufficientAmountADesired();
if (amountBDesired < amountBMin) revert InsufficientAmountBDesired();
// create the pool if it doesn't exist yet
address _pool = IPoolFactory(factory).getPool(tokenA, tokenB, stable);
if (_pool == address(0)) {
_pool = IPoolFactory(factory).createPool(tokenA, tokenB, stable);
}
(uint256 reserveA, uint256 reserveB) = getReserves(tokenA, tokenB, stable);
if (reserveA == 0 && reserveB == 0) {
(amountA, amountB) = (amountADesired, amountBDesired);
} else {
uint256 amountBOptimal = quoteLiquidity(amountADesired, reserveA, reserveB);
if (amountBOptimal <= amountBDesired) {
if (amountBOptimal < amountBMin) revert InsufficientAmountB();
(amountA, amountB) = (amountADesired, amountBOptimal);
} else {
uint256 amountAOptimal = quoteLiquidity(amountBDesired, reserveB, reserveA);
assert(amountAOptimal <= amountADesired);
if (amountAOptimal < amountAMin) revert InsufficientAmountA();
(amountA, amountB) = (amountAOptimal, amountBDesired);
}
}
}
/// @inheritdoc IRouter
function addLiquidity(
address tokenA,
address tokenB,
bool stable,
uint256 amountADesired,
uint256 amountBDesired,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline
) external ensure(deadline) returns (uint256 amountA, uint256 amountB, uint256 liquidity) {
(amountA, amountB) =
_addLiquidity(tokenA, tokenB, stable, amountADesired, amountBDesired, amountAMin, amountBMin);
address pool = poolFor(tokenA, tokenB, stable);
_safeTransferFrom(tokenA, msg.sender, pool, amountA);
_safeTransferFrom(tokenB, msg.sender, pool, amountB);
liquidity = IPool(pool).mint(to);
}
/// @inheritdoc IRouter
function addLiquidityETH(
address token,
bool stable,
uint256 amountTokenDesired,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
) external payable ensure(deadline) returns (uint256 amountToken, uint256 amountETH, uint256 liquidity) {
(amountToken, amountETH) =
_addLiquidity(token, address(weth), stable, amountTokenDesired, msg.value, amountTokenMin, amountETHMin);
address pool = poolFor(token, address(weth), stable);
_safeTransferFrom(token, msg.sender, pool, amountToken);
weth.deposit{value: amountETH}();
assert(weth.transfer(pool, amountETH));
liquidity = IPool(pool).mint(to);
// refund dust eth, if any
if (msg.value > amountETH) _safeTransferETH(msg.sender, msg.value - amountETH);
}
// **** REMOVE LIQUIDITY ****
/// @inheritdoc IRouter
function removeLiquidity(
address tokenA,
address tokenB,
bool stable,
uint256 liquidity,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline
) public ensure(deadline) returns (uint256 amountA, uint256 amountB) {
address pool = poolFor(tokenA, tokenB, stable);
_safeTransferFrom(pool, msg.sender, pool, liquidity);
(uint256 amount0, uint256 amount1) = IPool(pool).burn(to);
(address token0,) = sortTokens(tokenA, tokenB);
(amountA, amountB) = tokenA == token0 ? (amount0, amount1) : (amount1, amount0);
if (amountA < amountAMin) revert InsufficientAmountA();
if (amountB < amountBMin) revert InsufficientAmountB();
}
/// @inheritdoc IRouter
function removeLiquidityETH(
address token,
bool stable,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
) external ensure(deadline) returns (uint256 amountToken, uint256 amountETH) {
(amountToken, amountETH) = removeLiquidity(
token, address(weth), stable, liquidity, amountTokenMin, amountETHMin, address(this), deadline
);
_safeTransfer(token, to, amountToken);
weth.withdraw(amountETH);
_safeTransferETH(to, amountETH);
}
// **** SWAP ****
/// @dev requires the initial amount to have already been sent to the first pool
function _swap(uint256[] memory amounts, Route[] memory routes, address _to) internal virtual {
uint256 _length = routes.length;
for (uint256 i = 0; i < _length; i++) {
(address token0,) = sortTokens(routes[i].from, routes[i].to);
uint256 amountOut = amounts[i + 1];
(uint256 amount0Out, uint256 amount1Out) =
routes[i].from == token0 ? (uint256(0), amountOut) : (amountOut, uint256(0));
address to =
i < routes.length - 1 ? poolFor(routes[i + 1].from, routes[i + 1].to, routes[i + 1].stable) : _to;
IPool(poolFor(routes[i].from, routes[i].to, routes[i].stable)).swap(
amount0Out, amount1Out, to, new bytes(0)
);
}
}
/// @inheritdoc IRouter
function swapExactTokensForTokens(
uint256 amountIn,
uint256 amountOutMin,
Route[] calldata routes,
address to,
uint256 deadline
) external ensure(deadline) returns (uint256[] memory amounts) {
amounts = getAmountsOut(amountIn, routes);
if (amounts[amounts.length - 1] < amountOutMin) revert InsufficientOutputAmount();
_safeTransferFrom(
routes[0].from, msg.sender, poolFor(routes[0].from, routes[0].to, routes[0].stable), amounts[0]
);
_swap(amounts, routes, to);
}
/// @inheritdoc IRouter
function swapExactETHForTokens(uint256 amountOutMin, Route[] calldata routes, address to, uint256 deadline)
external
payable
ensure(deadline)
returns (uint256[] memory amounts)
{
if (routes[0].from != address(weth)) revert InvalidPath();
amounts = getAmountsOut(msg.value, routes);
if (amounts[amounts.length - 1] < amountOutMin) revert InsufficientOutputAmount();
weth.deposit{value: amounts[0]}();
assert(weth.transfer(poolFor(routes[0].from, routes[0].to, routes[0].stable), amounts[0]));
_swap(amounts, routes, to);
}
/// @inheritdoc IRouter
function swapExactTokensForETH(
uint256 amountIn,
uint256 amountOutMin,
Route[] calldata routes,
address to,
uint256 deadline
) external ensure(deadline) returns (uint256[] memory amounts) {
if (routes[routes.length - 1].to != address(weth)) revert InvalidPath();
amounts = getAmountsOut(amountIn, routes);
if (amounts[amounts.length - 1] < amountOutMin) revert InsufficientOutputAmount();
_safeTransferFrom(
routes[0].from, msg.sender, poolFor(routes[0].from, routes[0].to, routes[0].stable), amounts[0]
);
_swap(amounts, routes, address(this));
weth.withdraw(amounts[amounts.length - 1]);
_safeTransferETH(to, amounts[amounts.length - 1]);
}
// **** REMOVE LIQUIDITY (supporting fee-on-transfer tokens) ****
function removeLiquidityETHSupportingFeeOnTransferTokens(
address token,
bool stable,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
) public ensure(deadline) returns (uint256 amountETH) {
(, amountETH) = removeLiquidity(
token, address(weth), stable, liquidity, amountTokenMin, amountETHMin, address(this), deadline
);
_safeTransfer(token, to, IERC20(token).balanceOf(address(this)));
weth.withdraw(amountETH);
_safeTransferETH(to, amountETH);
}
function _safeTransferETH(address to, uint256 value) internal {
(bool success,) = to.call{value: value}(new bytes(0));
if (!success) revert ETHTransferFailed();
}
function _safeTransfer(address token, address to, uint256 value) internal {
require(token.code.length > 0);
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.transfer.selector, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))));
}
function _safeTransferFrom(address token, address from, address to, uint256 value) internal {
require(token.code.length > 0);
(bool success, bytes memory data) =
token.call(abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
/**
* @dev Muldiv operation overflow.
*/
error MathOverflowedMulDiv();
enum Rounding {
Floor, // Toward negative infinity
Ceil, // Toward positive infinity
Trunc, // Toward zero
Expand // Away from zero
}
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an overflow flag.
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds towards infinity instead
* of rounding towards zero.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
if (b == 0) {
// Guarantee the same behavior as in a regular Solidity division.
return a / b;
}
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
* denominator == 0.
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
* Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0 = x * y; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
if (denominator <= prod1) {
revert MathOverflowedMulDiv();
}
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator.
// Always >= 1. See https://cs.stackexchange.com/q/138556/92363.
uint256 twos = denominator & (0 - denominator);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
// works in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
* towards zero.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256 of a positive value rounded towards zero.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
}
}
/**
* @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
*/
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
return uint8(rounding) % 2 == 1;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/Clones.sol)
pragma solidity ^0.8.20;
/**
* @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for
* deploying minimal proxy contracts, also known as "clones".
*
* > To simply and cheaply clone contract functionality in an immutable way, this standard specifies
* > a minimal bytecode implementation that delegates all calls to a known, fixed address.
*
* The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`
* (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the
* deterministic method.
*/
library Clones {
/**
* @dev A clone instance deployment failed.
*/
error ERC1167FailedCreateClone();
/**
* @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
*
* This function uses the create opcode, which should never revert.
*/
function clone(address implementation) internal returns (address instance) {
/// @solidity memory-safe-assembly
assembly {
// Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
// of the `implementation` address with the bytecode before the address.
mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
// Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
instance := create(0, 0x09, 0x37)
}
if (instance == address(0)) {
revert ERC1167FailedCreateClone();
}
}
/**
* @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
*
* This function uses the create2 opcode and a `salt` to deterministically deploy
* the clone. Using the same `implementation` and `salt` multiple time will revert, since
* the clones cannot be deployed twice at the same address.
*/
function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {
/// @solidity memory-safe-assembly
assembly {
// Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
// of the `implementation` address with the bytecode before the address.
mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
// Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
instance := create2(0, 0x09, 0x37, salt)
}
if (instance == address(0)) {
revert ERC1167FailedCreateClone();
}
}
/**
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
*/
function predictDeterministicAddress(
address implementation,
bytes32 salt,
address deployer
) internal pure returns (address predicted) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40)
mstore(add(ptr, 0x38), deployer)
mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff)
mstore(add(ptr, 0x14), implementation)
mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73)
mstore(add(ptr, 0x58), salt)
mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37))
predicted := keccak256(add(ptr, 0x43), 0x55)
}
}
/**
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
*/
function predictDeterministicAddress(
address implementation,
bytes32 salt
) internal view returns (address predicted) {
return predictDeterministicAddress(implementation, salt, address(this));
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IPool {
error DepositsNotEqual();
error BelowMinimumK();
error FactoryAlreadySet();
error InsufficientLiquidity();
error InsufficientLiquidityMinted();
error InsufficientLiquidityBurned();
error InsufficientOutputAmount();
error InsufficientInputAmount();
error IsPaused();
error InvalidTo();
error K();
event Fees(address indexed sender, uint256 amount0, uint256 amount1);
event Mint(address indexed sender, address indexed to, uint256 amount0, uint256 amount1);
event Burn(address indexed sender, address indexed to, uint256 amount0, uint256 amount1);
event Swap(
address indexed sender,
address indexed to,
uint256 amount0In,
uint256 amount1In,
uint256 amount0Out,
uint256 amount1Out
);
event Sync(uint256 reserve0, uint256 reserve1);
event Claim(address indexed sender, address indexed recipient, uint256 amount0, uint256 amount1);
// Struct to capture time period obervations every 30 minutes, used for local oracles
struct Observation {
uint256 timestamp;
uint256 reserve0Cumulative;
uint256 reserve1Cumulative;
}
/// @notice Returns the decimal (dec), reserves (r), stable (st), and tokens (t) of token0 and token1
function metadata()
external
view
returns (uint256 dec0, uint256 dec1, uint256 r0, uint256 r1, bool st, address t0, address t1);
/// @notice Claim accumulated but unclaimed fees (claimable0 and claimable1)
function claimFees() external returns (uint256, uint256);
/// @notice Returns [token0, token1]
function tokens() external view returns (address, address);
/// @notice Address of token in the pool with the lower address value
function token0() external view returns (address);
/// @notice Address of token in the pool with the higher address value
function token1() external view returns (address);
/// @notice Address of linked PoolFees.sol
function poolFees() external view returns (address);
/// @notice Address of PoolFactory that created this contract
function factory() external view returns (address);
/// @notice Capture oracle reading every 30 minutes (1800 seconds)
function periodSize() external view returns (uint256);
/// @notice Amount of token0 in pool
function reserve0() external view returns (uint256);
/// @notice Amount of token1 in pool
function reserve1() external view returns (uint256);
/// @notice Timestamp of last update to pool
function blockTimestampLast() external view returns (uint256);
/// @notice Cumulative of reserve0 factoring in time elapsed
function reserve0CumulativeLast() external view returns (uint256);
/// @notice Cumulative of reserve1 factoring in time elapsed
function reserve1CumulativeLast() external view returns (uint256);
/// @notice Accumulated fees of token0 (global)
function index0() external view returns (uint256);
/// @notice Accumulated fees of token1 (global)
function index1() external view returns (uint256);
/// @notice Get an LP's relative index0 to index0
function supplyIndex0(address) external view returns (uint256);
/// @notice Get an LP's relative index1 to index1
function supplyIndex1(address) external view returns (uint256);
/// @notice Amount of unclaimed, but claimable tokens from fees of token0 for an LP
function claimable0(address) external view returns (uint256);
/// @notice Amount of unclaimed, but claimable tokens from fees of token1 for an LP
function claimable1(address) external view returns (uint256);
/// @notice Returns the value of K in the Pool, based on its reserves.
function getK() external returns (uint256);
/// @notice Set pool name
/// Only callable by Voter.emergencyCouncil()
/// @param __name String of new name
function setName(string calldata __name) external;
/// @notice Set pool symbol
/// Only callable by Voter.emergencyCouncil()
/// @param __symbol String of new symbol
function setSymbol(string calldata __symbol) external;
/// @notice Get the number of observations recorded
function observationLength() external view returns (uint256);
/// @notice Get the value of the most recent observation
function lastObservation() external view returns (Observation memory);
/// @notice True if pool is stable, false if volatile
function stable() external view returns (bool);
/// @notice Produces the cumulative price using counterfactuals to save gas and avoid a call to sync.
function currentCumulativePrices()
external
view
returns (uint256 reserve0Cumulative, uint256 reserve1Cumulative, uint256 blockTimestamp);
/// @notice Provides twap price with user configured granularity, up to the full window size
/// @param tokenIn .
/// @param amountIn .
/// @param granularity .
/// @return amountOut .
function quote(address tokenIn, uint256 amountIn, uint256 granularity) external view returns (uint256 amountOut);
/// @notice Returns a memory set of TWAP prices
/// Same as calling sample(tokenIn, amountIn, points, 1)
/// @param tokenIn .
/// @param amountIn .
/// @param points Number of points to return
/// @return Array of TWAP prices
function prices(address tokenIn, uint256 amountIn, uint256 points) external view returns (uint256[] memory);
/// @notice Same as prices with with an additional window argument.
/// Window = 2 means 2 * 30min (or 1 hr) between observations
/// @param tokenIn .
/// @param amountIn .
/// @param points .
/// @param window .
/// @return Array of TWAP prices
function sample(address tokenIn, uint256 amountIn, uint256 points, uint256 window)
external
view
returns (uint256[] memory);
/// @notice This low-level function should be called from a contract which performs important safety checks
/// @param amount0Out Amount of token0 to send to `to`
/// @param amount1Out Amount of token1 to send to `to`
/// @param to Address to recieve the swapped output
/// @param data Additional calldata for flashloans
function swap(uint256 amount0Out, uint256 amount1Out, address to, bytes calldata data) external;
/// @notice This low-level function should be called from a contract which performs important safety checks
/// standard uniswap v2 implementation
/// @param to Address to receive token0 and token1 from burning the pool token
/// @return amount0 Amount of token0 returned
/// @return amount1 Amount of token1 returned
function burn(address to) external returns (uint256 amount0, uint256 amount1);
/// @notice This low-level function should be called by addLiquidity functions in Router.sol, which performs important safety checks
/// standard uniswap v2 implementation
/// @param to Address to receive the minted LP token
/// @return liquidity Amount of LP token minted
function mint(address to) external returns (uint256 liquidity);
/// @notice Update reserves and, on the first call per block, price accumulators
/// @return _reserve0 .
/// @return _reserve1 .
/// @return _blockTimestampLast .
function getReserves() external view returns (uint256 _reserve0, uint256 _reserve1, uint256 _blockTimestampLast);
/// @notice Get the amount of tokenOut given the amount of tokenIn
/// @param amountIn Amount of token in
/// @param tokenIn Address of token
/// @return Amount out
function getAmountOut(uint256 amountIn, address tokenIn) external view returns (uint256);
/// @notice Force balances to match reserves
/// @param to Address to receive any skimmed rewards
function skim(address to) external;
/// @notice Force reserves to match balances
function sync() external;
/// @notice Called on pool creation by PoolFactory
/// @param _token0 Address of token0
/// @param _token1 Address of token1
/// @param _stable True if stable, false if volatile
function initialize(address _token0, address _token1, bool _stable) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IPoolFactory {
event SetFeeManager(address indexed feeManager);
event SetPauser(address indexed pauser);
event SetPauseState(bool indexed state);
event SetPoolAdmin(address indexed poolAdmin);
event PoolCreated(address indexed token0, address indexed token1, bool indexed stable, address pool, uint256);
event SetDefaultFee(bool indexed stable, uint256 fee);
event FeeModuleChanged(address indexed oldFeeModule, address indexed newFeeModule);
error FeeInvalid();
error FeeTooHigh();
error NotFeeManager();
error NotPauser();
error NotPoolAdmin();
error PoolAlreadyExists();
error SameAddress();
error ZeroFee();
error ZeroAddress();
/// @notice Return a single pool created by this factory
/// @return Address of pool
function allPools(uint256 index) external view returns (address);
/// @notice Returns all pools created by this factory
/// @return Array of pool addresses
function allPools() external view returns (address[] memory);
/// @notice returns the number of pools created from this factory
function allPoolsLength() external view returns (uint256);
/// @notice Is a valid pool created by this factory.
/// @param .
function isPool(address pool) external view returns (bool);
/// @notice Return address of pool created by this factory
/// @param tokenA .
/// @param tokenB .
/// @param stable True if stable, false if volatile
function getPool(address tokenA, address tokenB, bool stable) external view returns (address);
/// @notice Support for v3-style pools which wraps around getPool(tokenA,tokenB,stable)
/// @dev fee is converted to stable boolean.
/// @param tokenA .
/// @param tokenB .
/// @param fee 1 if stable, 0 if volatile, else returns address(0)
function getPool(address tokenA, address tokenB, uint24 fee) external view returns (address);
/// @notice Set pool administrator
/// @dev Allowed to change the name and symbol of any pool created by this factory
/// @param _poolAdmin Address of the pool administrator
function setPoolAdmin(address _poolAdmin) external;
/// @notice Set the pauser for the factory contract
/// @dev The pauser can pause swaps on pools associated with the factory. Liquidity will always be withdrawable.
/// @dev Must be called by the pauser
/// @param _pauser Address of the pauser
function setPauser(address _pauser) external;
/// @notice Pause or unpause swaps on pools associated with the factory
/// @param _state True to pause, false to unpause
function setPauseState(bool _state) external;
/// @notice Set the fee manager for the factory contract
/// @dev The fee manager can set fees on pools associated with the factory.
/// @dev Must be called by the fee manager
/// @param _feeManager Address of the fee manager
function setFeeManager(address _feeManager) external;
/// @notice Updates the feeModule of the factory
/// @dev Must be called by the current fee manager
/// @param _feeModule The new feeModule of the factory
function setFeeModule(address _feeModule) external;
/// @notice Set default fee for stable and volatile pools.
/// @dev Throws if higher than maximum fee.
/// Throws if fee is zero.
/// @param _stable Stable or volatile pool.
/// @param _fee .
function setFee(bool _stable, uint256 _fee) external;
/// @notice Returns fee for a pool, as custom fees are possible.
function getFee(address _pool, bool _stable) external view returns (uint256);
/// @notice Create a pool given two tokens and if they're stable/volatile
/// @dev token order does not matter
/// @param tokenA .
/// @param tokenB .
/// @param stable .
function createPool(address tokenA, address tokenB, bool stable) external returns (address pool);
/// @notice Support for v3-style pools which wraps around createPool(tokenA,tokenB,stable)
/// @dev fee is converted to stable boolean
/// @dev token order does not matter
/// @param tokenA .
/// @param tokenB .
/// @param fee 1 if stable, 0 if volatile, else revert
function createPool(address tokenA, address tokenB, uint24 fee) external returns (address pool);
/// @notice The pool implementation used to create pools
/// @return Address of pool implementation
function implementation() external view returns (address);
/// @notice Whether the pools associated with the factory are paused or not.
/// @dev Pause only pauses swaps, liquidity will always be withdrawable.
function isPaused() external view returns (bool);
/// @notice The address of the pauser, can pause swaps on pools associated with factory.
/// @return Address of the pauser
function pauser() external view returns (address);
/// @notice The default fee for all stable pools
/// @return Default stable fee
function stableFee() external view returns (uint256);
/// @notice The default fee for all volatile pools
/// @return Default volatile fee
function volatileFee() external view returns (uint256);
/// @notice Maximum possible fee for default stable or volatile fee
/// @return 3%
function MAX_FEE() external view returns (uint256);
/// @notice Address of the fee manager, can set fees on pools associated with factory.
/// @notice This overrides the default fee for that pool.
/// @return Address of the fee manager
function feeManager() external view returns (address);
/// @notice Address of the fee module of the factory
/// @dev Can be changed by the current fee manager via setFeeModule
/// @return Address of the fee module
function feeModule() external view returns (address);
/// @notice Address of the pool administrator, can change the name and symbol of pools created by factory.
/// @return Address of the pool administrator
function poolAdmin() external view returns (address);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IWETH} from "./external/IWETH.sol";
interface IRouter {
struct Route {
address from;
address to;
bool stable;
}
error ETHTransferFailed();
error Expired();
error InsufficientAmount();
error InsufficientAmountA();
error InsufficientAmountB();
error InsufficientAmountADesired();
error InsufficientAmountBDesired();
error InsufficientLiquidity();
error InsufficientOutputAmount();
error InvalidPath();
error OnlyWETH();
error SameAddresses();
error ZeroAddress();
/// @notice Address of Velodrome v2 pool factory
function factory() external view returns (address);
/// @notice Address of Velodrome v2 pool implementation
function poolImplementation() external view returns (address);
/// @notice Interface of WETH contract used for WETH => ETH wrapping/unwrapping
function weth() external view returns (IWETH);
/// @notice Sort two tokens by which address value is less than the other
/// @param tokenA Address of token to sort
/// @param tokenB Address of token to sort
/// @return token0 Lower address value between tokenA and tokenB
/// @return token1 Higher address value between tokenA and tokenB
function sortTokens(address tokenA, address tokenB) external pure returns (address token0, address token1);
/// @notice Calculate the address of a pool by its' factory.
/// @dev Returns a randomly generated address for a nonexistent pool
/// @param tokenA Address of token to query
/// @param tokenB Address of token to query
/// @param stable True if pool is stable, false if volatile
function poolFor(address tokenA, address tokenB, bool stable) external view returns (address pool);
/// @notice Fetch and sort the reserves for a pool
/// @param tokenA .
/// @param tokenB .
/// @param stable True if pool is stable, false if volatile
/// @return reserveA Amount of reserves of the sorted token A
/// @return reserveB Amount of reserves of the sorted token B
function getReserves(address tokenA, address tokenB, bool stable)
external
view
returns (uint256 reserveA, uint256 reserveB);
/// @notice Perform chained getAmountOut calculations on any number of pools
function getAmountsOut(uint256 amountIn, Route[] memory routes) external view returns (uint256[] memory amounts);
// **** ADD LIQUIDITY ****
/// @notice Quote the amount deposited into a Pool
/// @param tokenA .
/// @param tokenB .
/// @param stable True if pool is stable, false if volatile
/// @param amountADesired Amount of tokenA desired to deposit
/// @param amountBDesired Amount of tokenB desired to deposit
/// @return amountA Amount of tokenA to actually deposit
/// @return amountB Amount of tokenB to actually deposit
/// @return liquidity Amount of liquidity token returned from deposit
function quoteAddLiquidity(
address tokenA,
address tokenB,
bool stable,
uint256 amountADesired,
uint256 amountBDesired
) external view returns (uint256 amountA, uint256 amountB, uint256 liquidity);
/// @notice Quote the amount of liquidity removed from a Pool
/// @param tokenA .
/// @param tokenB .
/// @param stable True if pool is stable, false if volatile
/// @param liquidity Amount of liquidity to remove
/// @return amountA Amount of tokenA received
/// @return amountB Amount of tokenB received
function quoteRemoveLiquidity(address tokenA, address tokenB, bool stable, uint256 liquidity)
external
view
returns (uint256 amountA, uint256 amountB);
/// @notice Add liquidity of two tokens to a Pool
/// @param tokenA .
/// @param tokenB .
/// @param stable True if pool is stable, false if volatile
/// @param amountADesired Amount of tokenA desired to deposit
/// @param amountBDesired Amount of tokenB desired to deposit
/// @param amountAMin Minimum amount of tokenA to deposit
/// @param amountBMin Minimum amount of tokenB to deposit
/// @param to Recipient of liquidity token
/// @param deadline Deadline to receive liquidity
/// @return amountA Amount of tokenA to actually deposit
/// @return amountB Amount of tokenB to actually deposit
/// @return liquidity Amount of liquidity token returned from deposit
function addLiquidity(
address tokenA,
address tokenB,
bool stable,
uint256 amountADesired,
uint256 amountBDesired,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline
) external returns (uint256 amountA, uint256 amountB, uint256 liquidity);
/// @notice Add liquidity of a token and WETH (transferred as ETH) to a Pool
/// @param token .
/// @param stable True if pool is stable, false if volatile
/// @param amountTokenDesired Amount of token desired to deposit
/// @param amountTokenMin Minimum amount of token to deposit
/// @param amountETHMin Minimum amount of ETH to deposit
/// @param to Recipient of liquidity token
/// @param deadline Deadline to add liquidity
/// @return amountToken Amount of token to actually deposit
/// @return amountETH Amount of tokenETH to actually deposit
/// @return liquidity Amount of liquidity token returned from deposit
function addLiquidityETH(
address token,
bool stable,
uint256 amountTokenDesired,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
) external payable returns (uint256 amountToken, uint256 amountETH, uint256 liquidity);
// **** REMOVE LIQUIDITY ****
/// @notice Remove liquidity of two tokens from a Pool
/// @param tokenA .
/// @param tokenB .
/// @param stable True if pool is stable, false if volatile
/// @param liquidity Amount of liquidity to remove
/// @param amountAMin Minimum amount of tokenA to receive
/// @param amountBMin Minimum amount of tokenB to receive
/// @param to Recipient of tokens received
/// @param deadline Deadline to remove liquidity
/// @return amountA Amount of tokenA received
/// @return amountB Amount of tokenB received
function removeLiquidity(
address tokenA,
address tokenB,
bool stable,
uint256 liquidity,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline
) external returns (uint256 amountA, uint256 amountB);
/// @notice Remove liquidity of a token and WETH (returned as ETH) from a Pool
/// @param token .
/// @param stable True if pool is stable, false if volatile
/// @param liquidity Amount of liquidity to remove
/// @param amountTokenMin Minimum amount of token to receive
/// @param amountETHMin Minimum amount of ETH to receive
/// @param to Recipient of liquidity token
/// @param deadline Deadline to receive liquidity
/// @return amountToken Amount of token received
/// @return amountETH Amount of ETH received
function removeLiquidityETH(
address token,
bool stable,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
) external returns (uint256 amountToken, uint256 amountETH);
/// @notice Remove liquidity of a fee-on-transfer token and WETH (returned as ETH) from a Pool
/// @param token .
/// @param stable True if pool is stable, false if volatile
/// @param liquidity Amount of liquidity to remove
/// @param amountTokenMin Minimum amount of token to receive
/// @param amountETHMin Minimum amount of ETH to receive
/// @param to Recipient of liquidity token
/// @param deadline Deadline to receive liquidity
/// @return amountETH Amount of ETH received
function removeLiquidityETHSupportingFeeOnTransferTokens(
address token,
bool stable,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
) external returns (uint256 amountETH);
/// @notice Swap one token for another
/// @param amountIn Amount of token in
/// @param amountOutMin Minimum amount of desired token received
/// @param routes Array of trade routes used in the swap
/// @param to Recipient of the tokens received
/// @param deadline Deadline to receive tokens
/// @return amounts Array of amounts returned per route
function swapExactTokensForTokens(
uint256 amountIn,
uint256 amountOutMin,
Route[] calldata routes,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
/// @notice Swap ETH for a token
/// @param amountOutMin Minimum amount of desired token received
/// @param routes Array of trade routes used in the swap
/// @param to Recipient of the tokens received
/// @param deadline Deadline to receive tokens
/// @return amounts Array of amounts returned per route
function swapExactETHForTokens(uint256 amountOutMin, Route[] calldata routes, address to, uint256 deadline)
external
payable
returns (uint256[] memory amounts);
/// @notice Swap a token for WETH (returned as ETH)
/// @param amountIn Amount of token in
/// @param amountOutMin Minimum amount of desired ETH
/// @param routes Array of trade routes used in the swap
/// @param to Recipient of the tokens received
/// @param deadline Deadline to receive tokens
/// @return amounts Array of amounts returned per route
function swapExactTokensForETH(
uint256 amountIn,
uint256 amountOutMin,
Route[] calldata routes,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IERC20} from "@openzeppelin5/contracts/token/ERC20/IERC20.sol";
interface IWETH is IERC20 {
function deposit() external payable;
function withdraw(uint256 wad) external;
}{
"remappings": [
"@openzeppelin5/contracts/=lib/openzeppelin-contracts/contracts/",
"ds-test/=lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/",
"erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
"forge-std/src/=lib/forge-std/src/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"createX/=lib/createX/src/",
"@nomad-xyz/=lib/ExcessivelySafeCall/",
"@hyperlane/=node_modules/@hyperlane-xyz/",
"@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/",
"@openzeppelin/contracts-upgradeable/=node_modules/@openzeppelin/contracts-upgradeable/",
"ExcessivelySafeCall/=lib/ExcessivelySafeCall/src/",
"openzeppelin/=lib/createX/lib/openzeppelin-contracts/contracts/",
"solady/=lib/createX/lib/solady/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": false,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_factory","type":"address"},{"internalType":"address","name":"_weth","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ETHTransferFailed","type":"error"},{"inputs":[],"name":"Expired","type":"error"},{"inputs":[],"name":"InsufficientAmount","type":"error"},{"inputs":[],"name":"InsufficientAmountA","type":"error"},{"inputs":[],"name":"InsufficientAmountADesired","type":"error"},{"inputs":[],"name":"InsufficientAmountB","type":"error"},{"inputs":[],"name":"InsufficientAmountBDesired","type":"error"},{"inputs":[],"name":"InsufficientLiquidity","type":"error"},{"inputs":[],"name":"InsufficientOutputAmount","type":"error"},{"inputs":[],"name":"InvalidPath","type":"error"},{"inputs":[],"name":"OnlyWETH","type":"error"},{"inputs":[],"name":"SameAddresses","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"uint256","name":"amountADesired","type":"uint256"},{"internalType":"uint256","name":"amountBDesired","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidity","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"uint256","name":"amountTokenDesired","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidityETH","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountETH","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"stable","type":"bool"}],"internalType":"struct IRouter.Route[]","name":"routes","type":"tuple[]"}],"name":"getAmountsOut","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"bool","name":"stable","type":"bool"}],"name":"getReserves","outputs":[{"internalType":"uint256","name":"reserveA","type":"uint256"},{"internalType":"uint256","name":"reserveB","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"bool","name":"stable","type":"bool"}],"name":"poolFor","outputs":[{"internalType":"address","name":"pool","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"uint256","name":"amountADesired","type":"uint256"},{"internalType":"uint256","name":"amountBDesired","type":"uint256"}],"name":"quoteAddLiquidity","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"name":"quoteRemoveLiquidity","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidity","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidityETH","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidityETHSupportingFeeOnTransferTokens","outputs":[{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"}],"name":"sortTokens","outputs":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"stable","type":"bool"}],"internalType":"struct IRouter.Route[]","name":"routes","type":"tuple[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactETHForTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"stable","type":"bool"}],"internalType":"struct IRouter.Route[]","name":"routes","type":"tuple[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForETH","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"stable","type":"bool"}],"internalType":"struct IRouter.Route[]","name":"routes","type":"tuple[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"contract IWETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60e060405234801561000f575f5ffd5b50604051612c91380380612c9183398101604081905261002e916100cd565b6001600160a01b038216608081905260408051635c60da1b60e01b81529051635c60da1b916004808201926020929091908290030181865afa158015610076573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061009a91906100fe565b6001600160a01b0390811660a0521660c0525061011e565b80516001600160a01b03811681146100c8575f5ffd5b919050565b5f5f604083850312156100de575f5ffd5b6100e7836100b2565b91506100f5602084016100b2565b90509250929050565b5f6020828403121561010e575f5ffd5b610117826100b2565b9392505050565b60805160a05160c051612ab66101db5f395f818161010d015281816101fe015281816105420152818161078901528181610cd501528181610de801528181610e71015281816114ab015281816114e001528181611515015281816115a6015281816116c701528181611717015281816118aa015261196101525f818161037f015261090201525f818161034c015281816108c60152818161096e01528181611126015281816112a701528181611e150152611eb40152612ab65ff3fe6080604052600436106100fd575f3560e01c806367ffb66a11610092578063c45a015511610062578063c45a01551461033b578063cefa77991461036e578063d7b0e0a5146103a1578063f41766d8146103c0578063fe411f14146103df575f5ffd5b806367ffb66a146102d75780639881fcb4146102ea57806398a0fb3c14610309578063b7e0d4c014610328575f5ffd5b80634386e63c116100cd5780634386e63c14610220578063544caa561461023f5780635a47ddc31461027e5780635e60dab5146102b8575f5ffd5b80630dede6c41461015157806318a130861461018a57806328eb0b4a146101b65780633fc8cef3146101ed575f5ffd5b3661014d57336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461014b576040516301f180c960e01b815260040160405180910390fd5b005b5f5ffd5b34801561015c575f5ffd5b5061017061016b3660046122f4565b61040c565b604080519283526020830191909152015b60405180910390f35b348015610195575f5ffd5b506101a96101a43660046123b5565b61052c565b6040516101819190612423565b3480156101c1575f5ffd5b506101d56101d0366004612465565b610863565b6040516001600160a01b039091168152602001610181565b3480156101f8575f5ffd5b506101d57f000000000000000000000000000000000000000000000000000000000000000081565b34801561022b575f5ffd5b5061017061023a3660046124ad565b610969565b34801561024a575f5ffd5b5061025e6102593660046124fb565b610ac7565b604080516001600160a01b03938416815292909116602083015201610181565b348015610289575f5ffd5b5061029d610298366004612532565b610b51565b60408051938452602084019290925290820152606001610181565b3480156102c3575f5ffd5b506101706102d2366004612465565b610c14565b6101a96102e53660046125bc565b610cc7565b3480156102f5575f5ffd5b506101a96103043660046126d7565b611002565b348015610314575f5ffd5b5061029d610323366004612799565b6112a1565b61029d6103363660046127f0565b611498565b348015610346575f5ffd5b506101d57f000000000000000000000000000000000000000000000000000000000000000081565b348015610379575f5ffd5b506101d57f000000000000000000000000000000000000000000000000000000000000000081565b3480156103ac575f5ffd5b506101706103bb3660046127f0565b6116b5565b3480156103cb575f5ffd5b506101a96103da3660046123b5565b61178d565b3480156103ea575f5ffd5b506103fe6103f93660046127f0565b611899565b604051908152602001610181565b5f5f82610418816119d6565b5f6104248c8c8c610863565b90506104328133838c6119fa565b60405163226bf2d160e21b81526001600160a01b0387811660048301525f9182918416906389afcb449060240160408051808303815f875af115801561047a573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061049e919061285e565b915091505f6104ad8f8f610ac7565b509050806001600160a01b03168f6001600160a01b0316146104d05781836104d3565b82825b90975095508a8710156104f9576040516323d9bb0560e21b815260040160405180910390fd5b8986101561051a57604051630d32418960e21b815260040160405180910390fd5b50505050509850989650505050505050565b606081610538816119d6565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016868661056f600182612894565b81811061057e5761057e6128a7565b905060600201602001602081019061059691906128bb565b6001600160a01b0316146105bd576040516320db826760e01b815260040160405180910390fd5b610618888787808060200260200160405190810160405280939291908181526020015f905b8282101561060e576105ff606083028601368190038101906128d6565b815260200190600101906105e2565b5050505050611002565b915086826001845161062a9190612894565b8151811061063a5761063a6128a7565b60200260200101511015610661576040516342301c2360e01b815260040160405180910390fd5b61072b86865f818110610676576106766128a7565b61068c92602060609092020190810191506128bb565b3361070c89895f8181106106a2576106a26128a7565b6106b892602060609092020190810191506128bb565b8a8a5f8181106106ca576106ca6128a7565b90506060020160200160208101906106e291906128bb565b8b8b5f8181106106f4576106f46128a7565b90506060020160400160208101906101d091906128f0565b855f8151811061071e5761071e6128a7565b60200260200101516119fa565b610787828787808060200260200160405190810160405280939291908181526020015f905b8282101561077c5761076d606083028601368190038101906128d6565b81526020019060010190610750565b505050505030611aea565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632e1a7d4d83600185516107c59190612894565b815181106107d5576107d56128a7565b60200260200101516040518263ffffffff1660e01b81526004016107fb91815260200190565b5f604051808303815f87803b158015610812575f5ffd5b505af1158015610824573d5f5f3e3d5ffd5b5050505061085884836001855161083b9190612894565b8151811061084b5761084b6128a7565b6020026020010151611d29565b509695505050505050565b5f5f5f6108708686610ac7565b6040516bffffffffffffffffffffffff19606084811b8216602084015283901b16603482015286151560f81b604882015291935091505f9060490160408051601f198184030181529082905280516020909101207f000000000000000000000000000000000000000000000000000000000000000060388301526f5af43d82803e903d91602b57fd5bf3ff60248301527f00000000000000000000000000000000000000000000000000000000000000006014830152733d602d80600a3d3981f3363d3d373d3d3d363d738252605882018190526037600c83012060788301526055604390920191909120909150979650505050505050565b5f5f5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166379bc57d58888886040518463ffffffff1660e01b81526004016109bc9392919061290b565b602060405180830381865afa1580156109d7573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109fb919061292f565b90506001600160a01b038116610a17575f5f9250925050610abe565b5f5f610a24898989610c14565b915091505f836001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a65573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a89919061294a565b905080610a968489612961565b610aa0919061298c565b955080610aad8389612961565b610ab7919061298c565b9450505050505b94509492505050565b5f5f826001600160a01b0316846001600160a01b031603610afb57604051633295f3fd60e21b815260040160405180910390fd5b826001600160a01b0316846001600160a01b031610610b1b578284610b1e565b83835b90925090506001600160a01b038216610b4a5760405163d92e233d60e01b815260040160405180910390fd5b9250929050565b5f5f5f83610b5e816119d6565b610b6d8d8d8d8d8d8d8d611db8565b90945092505f610b7e8e8e8e610863565b9050610b8c8e3383886119fa565b610b988d3383876119fa565b6040516335313c2160e11b81526001600160a01b038881166004830152821690636a627842906024016020604051808303815f875af1158015610bdd573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c01919061294a565b9250505099509950999650505050505050565b5f5f5f610c218686610ac7565b5090505f5f610c31888888610863565b6001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015610c6c573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c9091906129ab565b5091509150826001600160a01b0316886001600160a01b031614610cb5578082610cb8565b81815b90999098509650505050505050565b606081610cd3816119d6565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031686865f818110610d0f57610d0f6128a7565b610d2592602060609092020190810191506128bb565b6001600160a01b031614610d4c576040516320db826760e01b815260040160405180910390fd5b610d9d348787808060200260200160405190810160405280939291908181526020015f905b8282101561060e57610d8e606083028601368190038101906128d6565b81526020019060010190610d71565b9150868260018451610daf9190612894565b81518110610dbf57610dbf6128a7565b60200260200101511015610de6576040516342301c2360e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0835f81518110610e2757610e276128a7565b60200260200101516040518263ffffffff1660e01b81526004015f604051808303818588803b158015610e58575f5ffd5b505af1158015610e6a573d5f5f3e3d5ffd5b50505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb610f0588885f818110610eb357610eb36128a7565b610ec992602060609092020190810191506128bb565b89895f818110610edb57610edb6128a7565b9050606002016020016020810190610ef391906128bb565b8a8a5f8181106106f4576106f46128a7565b845f81518110610f1757610f176128a7565b60200260200101516040518363ffffffff1660e01b8152600401610f509291906001600160a01b03929092168252602082015260400190565b6020604051808303815f875af1158015610f6c573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f9091906129d6565b610f9c57610f9c6129f1565b610ff8828787808060200260200160405190810160405280939291908181526020015f905b82821015610fed57610fde606083028601368190038101906128d6565b81526020019060010190610fc1565b505050505086611aea565b5095945050505050565b6060600182511015611027576040516320db826760e01b815260040160405180910390fd5b8151611034906001612a05565b67ffffffffffffffff81111561104c5761104c61261e565b604051908082528060200260200182016040528015611075578160200160208202803683370190505b50905082815f8151811061108b5761108b6128a7565b602090810291909101015281515f5b81811015611299575f6111048583815181106110b8576110b86128a7565b60200260200101515f01518684815181106110d5576110d56128a7565b6020026020010151602001518785815181106110f3576110f36128a7565b602002602001015160400151610863565b604051635b16ebb760e01b81526001600160a01b0380831660048301529192507f000000000000000000000000000000000000000000000000000000000000000090911690635b16ebb790602401602060405180830381865afa15801561116d573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061119191906129d6565b1561127757806001600160a01b031663f140a35a8584815181106111b7576111b76128a7565b60200260200101518785815181106111d1576111d16128a7565b60200260200101515f01516040518363ffffffff1660e01b815260040161120b9291909182526001600160a01b0316602082015260400190565b602060405180830381865afa158015611226573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061124a919061294a565b84611256846001612a05565b81518110611266576112666128a7565b602002602001018181525050611290565b6040516320db826760e01b815260040160405180910390fd5b5060010161109a565b505092915050565b5f5f5f5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166379bc57d58a8a8a6040518463ffffffff1660e01b81526004016112f59392919061290b565b602060405180830381865afa158015611310573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611334919061292f565b90505f80806001600160a01b038416156113bb57836001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611384573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113a8919061294a565b90506113b58c8c8c610c14565b90935091505b821580156113c7575081155b156113f8578896508795506103e86113e76113e2888a612961565b611ff5565b6113f19190612894565b9450611489565b5f6114048a85856120e0565b905088811161144c5789975095508561144584611421848b612961565b61142b919061298c565b84611436858b612961565b611440919061298c565b612147565b9550611487565b5f6114588a85876120e0565b98508997508890506114838561146e8584612961565b611478919061298c565b85611436868c612961565b9650505b505b50505050955095509592505050565b5f5f5f836114a5816119d6565b6114d48b7f00000000000000000000000000000000000000000000000000000000000000008c8c348d8d611db8565b90945092505f6115058c7f00000000000000000000000000000000000000000000000000000000000000008d610863565b90506115138c3383886119fa565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0856040518263ffffffff1660e01b81526004015f604051808303818588803b15801561156c575f5ffd5b505af115801561157e573d5f5f3e3d5ffd5b505060405163a9059cbb60e01b81526001600160a01b038581166004830152602482018990527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb925060440190506020604051808303815f875af11580156115f0573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061161491906129d6565b611620576116206129f1565b6040516335313c2160e11b81526001600160a01b038881166004830152821690636a627842906024016020604051808303815f875af1158015611665573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611689919061294a565b9250833411156116a6576116a6336116a18634612894565b611d29565b50509750975097945050505050565b5f5f826116c1816119d6565b6116f18a7f00000000000000000000000000000000000000000000000000000000000000008b8b8b8b308b61040c565b90935091506117018a8685612160565b604051632e1a7d4d60e01b8152600481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d906024015f604051808303815f87803b158015611760575f5ffd5b505af1158015611772573d5f5f3e3d5ffd5b505050506117808583611d29565b5097509795505050505050565b606081611799816119d6565b6117ea888787808060200260200160405190810160405280939291908181526020015f905b8282101561060e576117db606083028601368190038101906128d6565b815260200190600101906117be565b91508682600184516117fc9190612894565b8151811061180c5761180c6128a7565b60200260200101511015611833576040516342301c2360e01b815260040160405180910390fd5b61184886865f818110610676576106766128a7565b610858828787808060200260200160405190810160405280939291908181526020015f905b82821015610fed5761188a606083028601368190038101906128d6565b8152602001906001019061186d565b5f816118a4816119d6565b6118d4897f00000000000000000000000000000000000000000000000000000000000000008a8a8a8a308a61040c565b6040516370a0823160e01b815230600482015290935061194b91508a9086906001600160a01b038316906370a0823190602401602060405180830381865afa158015611922573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611946919061294a565b612160565b604051632e1a7d4d60e01b8152600481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d906024015f604051808303815f87803b1580156119aa575f5ffd5b505af11580156119bc573d5f5f3e3d5ffd5b505050506119ca8483611d29565b50979650505050505050565b428110156119f757604051630407b05b60e31b815260040160405180910390fd5b50565b5f846001600160a01b03163b11611a0f575f5ffd5b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b17905291515f92839290881691611a729190612a18565b5f604051808303815f865af19150503d805f8114611aab576040519150601f19603f3d011682016040523d82523d5f602084013e611ab0565b606091505b5091509150818015611ada575080511580611ada575080806020019051810190611ada91906129d6565b611ae2575f5ffd5b505050505050565b81515f5b81811015611d22575f611b3a858381518110611b0c57611b0c6128a7565b60200260200101515f0151868481518110611b2957611b296128a7565b602002602001015160200151610ac7565b5090505f86611b4a846001612a05565b81518110611b5a57611b5a6128a7565b602002602001015190505f5f836001600160a01b0316888681518110611b8257611b826128a7565b60200260200101515f01516001600160a01b031614611ba257825f611ba5565b5f835b915091505f60018951611bb89190612894565b8610611bc45787611c36565b611c3689611bd3886001612a05565b81518110611be357611be36128a7565b60200260200101515f01518a886001611bfc9190612a05565b81518110611c0c57611c0c6128a7565b6020026020010151602001518b896001611c269190612a05565b815181106110f3576110f36128a7565b9050611c88898781518110611c4d57611c4d6128a7565b60200260200101515f01518a8881518110611c6a57611c6a6128a7565b6020026020010151602001518b89815181106110f3576110f36128a7565b6001600160a01b031663022c0d9f8484845f6040519080825280601f01601f191660200182016040528015611cc4576020820181803683370190505b506040518563ffffffff1660e01b8152600401611ce49493929190612a2e565b5f604051808303815f87803b158015611cfb575f5ffd5b505af1158015611d0d573d5f5f3e3d5ffd5b505060019097019650611aee95505050505050565b5050505050565b604080515f808252602082019092526001600160a01b038416908390604051611d529190612a18565b5f6040518083038185875af1925050503d805f8114611d8c576040519150601f19603f3d011682016040523d82523d5f602084013e611d91565b606091505b5050905080611db35760405163b12d13eb60e01b815260040160405180910390fd5b505050565b5f5f83861015611ddb57604051636e35977960e11b815260040160405180910390fd5b82851015611dfc5760405163acee051360e01b815260040160405180910390fd5b6040516379bc57d560e01b81525f906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906379bc57d590611e4e908d908d908d9060040161290b565b602060405180830381865afa158015611e69573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e8d919061292f565b90506001600160a01b038116611f30576040516301b5fcad60e51b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906336bf95a090611eed908d908d908d9060040161290b565b6020604051808303815f875af1158015611f09573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f2d919061292f565b90505b5f5f611f3d8c8c8c610c14565b91509150815f148015611f4e575080155b15611f5e57889450879350611fe6565b5f611f6a8a84846120e0565b9050888111611f9f5786811015611f9457604051630d32418960e21b815260040160405180910390fd5b899550935083611fe4565b5f611fab8a84866120e0565b90508a811115611fbd57611fbd6129f1565b88811015611fde576040516323d9bb0560e21b815260040160405180910390fd5b95508894505b505b50505097509795505050505050565b5f815f0361200457505f919050565b5f600161201084612240565b901c6001901b9050600181848161202957612029612978565b048201901c9050600181848161204157612041612978565b048201901c9050600181848161205957612059612978565b048201901c9050600181848161207157612071612978565b048201901c9050600181848161208957612089612978565b048201901c905060018184816120a1576120a1612978565b048201901c905060018184816120b9576120b9612978565b048201901c90506120d9818285816120d3576120d3612978565b04612147565b9392505050565b5f835f0361210157604051632ca2f52b60e11b815260040160405180910390fd5b82158061210c575081155b1561212a5760405163bb55fd2760e01b815260040160405180910390fd5b826121358386612961565b61213f919061298c565b949350505050565b5f8183106121555781612157565b825b90505b92915050565b5f836001600160a01b03163b11612175575f5ffd5b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291515f928392908716916121d09190612a18565b5f604051808303815f865af19150503d805f8114612209576040519150601f19603f3d011682016040523d82523d5f602084013e61220e565b606091505b509150915081801561223857508051158061223857508080602001905181019061223891906129d6565b611d22575f5ffd5b5f80608083901c1561225457608092831c92015b604083901c1561226657604092831c92015b602083901c1561227857602092831c92015b601083901c1561228a57601092831c92015b600883901c1561229c57600892831c92015b600483901c156122ae57600492831c92015b600283901c156122c057600292831c92015b600183901c1561215a5760010192915050565b6001600160a01b03811681146119f7575f5ffd5b80151581146119f7575f5ffd5b5f5f5f5f5f5f5f5f610100898b03121561230c575f5ffd5b8835612317816122d3565b97506020890135612327816122d3565b96506040890135612337816122e7565b9550606089013594506080890135935060a0890135925060c089013561235c816122d3565b979a969950949793969295919450919260e001359150565b5f5f83601f840112612384575f5ffd5b50813567ffffffffffffffff81111561239b575f5ffd5b602083019150836020606083028501011115610b4a575f5ffd5b5f5f5f5f5f5f60a087890312156123ca575f5ffd5b8635955060208701359450604087013567ffffffffffffffff8111156123ee575f5ffd5b6123fa89828a01612374565b909550935050606087013561240e816122d3565b95989497509295919493608090920135925050565b602080825282518282018190525f918401906040840190835b8181101561245a57835183526020938401939092019160010161243c565b509095945050505050565b5f5f5f60608486031215612477575f5ffd5b8335612482816122d3565b92506020840135612492816122d3565b915060408401356124a2816122e7565b809150509250925092565b5f5f5f5f608085870312156124c0575f5ffd5b84356124cb816122d3565b935060208501356124db816122d3565b925060408501356124eb816122e7565b9396929550929360600135925050565b5f5f6040838503121561250c575f5ffd5b8235612517816122d3565b91506020830135612527816122d3565b809150509250929050565b5f5f5f5f5f5f5f5f5f6101208a8c03121561254b575f5ffd5b8935612556816122d3565b985060208a0135612566816122d3565b975060408a0135612576816122e7565b965060608a0135955060808a0135945060a08a0135935060c08a0135925060e08a01356125a2816122d3565b989b979a5095989497939692955090936101000135919050565b5f5f5f5f5f608086880312156125d0575f5ffd5b85359450602086013567ffffffffffffffff8111156125ed575f5ffd5b6125f988828901612374565b909550935050604086013561260d816122d3565b949793965091946060013592915050565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561265b5761265b61261e565b604052919050565b5f60608284031215612673575f5ffd5b6040516060810167ffffffffffffffff811182821017156126965761269661261e565b60405290508082356126a7816122d3565b815260208301356126b7816122d3565b602082015260408301356126ca816122e7565b6040919091015292915050565b5f5f604083850312156126e8575f5ffd5b82359150602083013567ffffffffffffffff811115612705575f5ffd5b8301601f81018513612715575f5ffd5b803567ffffffffffffffff81111561272f5761272f61261e565b61273e60208260051b01612632565b8082825260208201915060206060840285010192508783111561275f575f5ffd5b6020840193505b8284101561278b576127788885612663565b8252602082019150606084019350612766565b809450505050509250929050565b5f5f5f5f5f60a086880312156127ad575f5ffd5b85356127b8816122d3565b945060208601356127c8816122d3565b935060408601356127d8816122e7565b94979396509394606081013594506080013592915050565b5f5f5f5f5f5f5f60e0888a031215612806575f5ffd5b8735612811816122d3565b96506020880135612821816122e7565b955060408801359450606088013593506080880135925060a0880135612846816122d3565b96999598509396929591949193505060c09091013590565b5f5f6040838503121561286f575f5ffd5b505080516020909101519092909150565b634e487b7160e01b5f52601160045260245ffd5b8181038181111561215a5761215a612880565b634e487b7160e01b5f52603260045260245ffd5b5f602082840312156128cb575f5ffd5b81356120d9816122d3565b5f606082840312156128e6575f5ffd5b6121578383612663565b5f60208284031215612900575f5ffd5b81356120d9816122e7565b6001600160a01b039384168152919092166020820152901515604082015260600190565b5f6020828403121561293f575f5ffd5b81516120d9816122d3565b5f6020828403121561295a575f5ffd5b5051919050565b808202811582820484141761215a5761215a612880565b634e487b7160e01b5f52601260045260245ffd5b5f826129a657634e487b7160e01b5f52601260045260245ffd5b500490565b5f5f5f606084860312156129bd575f5ffd5b5050815160208301516040909301519094929350919050565b5f602082840312156129e6575f5ffd5b81516120d9816122e7565b634e487b7160e01b5f52600160045260245ffd5b8082018082111561215a5761215a612880565b5f82518060208501845e5f920191825250919050565b84815283602082015260018060a01b0383166040820152608060608201525f8251806080840152806020850160a085015e5f60a0828501015260a0601f19601f8301168401019150509594505050505056fea26469706673582212204be651d0a9aafdfc35e6ba3f749de7739ddfe05e5fa91f4726ad079313c3f5e164736f6c634300081b003300000000000000000000000031832f2a97fd20664d76cc421207669b55ce4bc00000000000000000000000004200000000000000000000000000000000000006
Deployed Bytecode
0x6080604052600436106100fd575f3560e01c806367ffb66a11610092578063c45a015511610062578063c45a01551461033b578063cefa77991461036e578063d7b0e0a5146103a1578063f41766d8146103c0578063fe411f14146103df575f5ffd5b806367ffb66a146102d75780639881fcb4146102ea57806398a0fb3c14610309578063b7e0d4c014610328575f5ffd5b80634386e63c116100cd5780634386e63c14610220578063544caa561461023f5780635a47ddc31461027e5780635e60dab5146102b8575f5ffd5b80630dede6c41461015157806318a130861461018a57806328eb0b4a146101b65780633fc8cef3146101ed575f5ffd5b3661014d57336001600160a01b037f0000000000000000000000004200000000000000000000000000000000000006161461014b576040516301f180c960e01b815260040160405180910390fd5b005b5f5ffd5b34801561015c575f5ffd5b5061017061016b3660046122f4565b61040c565b604080519283526020830191909152015b60405180910390f35b348015610195575f5ffd5b506101a96101a43660046123b5565b61052c565b6040516101819190612423565b3480156101c1575f5ffd5b506101d56101d0366004612465565b610863565b6040516001600160a01b039091168152602001610181565b3480156101f8575f5ffd5b506101d57f000000000000000000000000420000000000000000000000000000000000000681565b34801561022b575f5ffd5b5061017061023a3660046124ad565b610969565b34801561024a575f5ffd5b5061025e6102593660046124fb565b610ac7565b604080516001600160a01b03938416815292909116602083015201610181565b348015610289575f5ffd5b5061029d610298366004612532565b610b51565b60408051938452602084019290925290820152606001610181565b3480156102c3575f5ffd5b506101706102d2366004612465565b610c14565b6101a96102e53660046125bc565b610cc7565b3480156102f5575f5ffd5b506101a96103043660046126d7565b611002565b348015610314575f5ffd5b5061029d610323366004612799565b6112a1565b61029d6103363660046127f0565b611498565b348015610346575f5ffd5b506101d57f00000000000000000000000031832f2a97fd20664d76cc421207669b55ce4bc081565b348015610379575f5ffd5b506101d57f00000000000000000000000010499d88bd32af443fc936f67de32be1c8bb374c81565b3480156103ac575f5ffd5b506101706103bb3660046127f0565b6116b5565b3480156103cb575f5ffd5b506101a96103da3660046123b5565b61178d565b3480156103ea575f5ffd5b506103fe6103f93660046127f0565b611899565b604051908152602001610181565b5f5f82610418816119d6565b5f6104248c8c8c610863565b90506104328133838c6119fa565b60405163226bf2d160e21b81526001600160a01b0387811660048301525f9182918416906389afcb449060240160408051808303815f875af115801561047a573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061049e919061285e565b915091505f6104ad8f8f610ac7565b509050806001600160a01b03168f6001600160a01b0316146104d05781836104d3565b82825b90975095508a8710156104f9576040516323d9bb0560e21b815260040160405180910390fd5b8986101561051a57604051630d32418960e21b815260040160405180910390fd5b50505050509850989650505050505050565b606081610538816119d6565b6001600160a01b037f000000000000000000000000420000000000000000000000000000000000000616868661056f600182612894565b81811061057e5761057e6128a7565b905060600201602001602081019061059691906128bb565b6001600160a01b0316146105bd576040516320db826760e01b815260040160405180910390fd5b610618888787808060200260200160405190810160405280939291908181526020015f905b8282101561060e576105ff606083028601368190038101906128d6565b815260200190600101906105e2565b5050505050611002565b915086826001845161062a9190612894565b8151811061063a5761063a6128a7565b60200260200101511015610661576040516342301c2360e01b815260040160405180910390fd5b61072b86865f818110610676576106766128a7565b61068c92602060609092020190810191506128bb565b3361070c89895f8181106106a2576106a26128a7565b6106b892602060609092020190810191506128bb565b8a8a5f8181106106ca576106ca6128a7565b90506060020160200160208101906106e291906128bb565b8b8b5f8181106106f4576106f46128a7565b90506060020160400160208101906101d091906128f0565b855f8151811061071e5761071e6128a7565b60200260200101516119fa565b610787828787808060200260200160405190810160405280939291908181526020015f905b8282101561077c5761076d606083028601368190038101906128d6565b81526020019060010190610750565b505050505030611aea565b7f00000000000000000000000042000000000000000000000000000000000000066001600160a01b0316632e1a7d4d83600185516107c59190612894565b815181106107d5576107d56128a7565b60200260200101516040518263ffffffff1660e01b81526004016107fb91815260200190565b5f604051808303815f87803b158015610812575f5ffd5b505af1158015610824573d5f5f3e3d5ffd5b5050505061085884836001855161083b9190612894565b8151811061084b5761084b6128a7565b6020026020010151611d29565b509695505050505050565b5f5f5f6108708686610ac7565b6040516bffffffffffffffffffffffff19606084811b8216602084015283901b16603482015286151560f81b604882015291935091505f9060490160408051601f198184030181529082905280516020909101207f00000000000000000000000031832f2a97fd20664d76cc421207669b55ce4bc060388301526f5af43d82803e903d91602b57fd5bf3ff60248301527f00000000000000000000000010499d88bd32af443fc936f67de32be1c8bb374c6014830152733d602d80600a3d3981f3363d3d373d3d3d363d738252605882018190526037600c83012060788301526055604390920191909120909150979650505050505050565b5f5f5f7f00000000000000000000000031832f2a97fd20664d76cc421207669b55ce4bc06001600160a01b03166379bc57d58888886040518463ffffffff1660e01b81526004016109bc9392919061290b565b602060405180830381865afa1580156109d7573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109fb919061292f565b90506001600160a01b038116610a17575f5f9250925050610abe565b5f5f610a24898989610c14565b915091505f836001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a65573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a89919061294a565b905080610a968489612961565b610aa0919061298c565b955080610aad8389612961565b610ab7919061298c565b9450505050505b94509492505050565b5f5f826001600160a01b0316846001600160a01b031603610afb57604051633295f3fd60e21b815260040160405180910390fd5b826001600160a01b0316846001600160a01b031610610b1b578284610b1e565b83835b90925090506001600160a01b038216610b4a5760405163d92e233d60e01b815260040160405180910390fd5b9250929050565b5f5f5f83610b5e816119d6565b610b6d8d8d8d8d8d8d8d611db8565b90945092505f610b7e8e8e8e610863565b9050610b8c8e3383886119fa565b610b988d3383876119fa565b6040516335313c2160e11b81526001600160a01b038881166004830152821690636a627842906024016020604051808303815f875af1158015610bdd573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c01919061294a565b9250505099509950999650505050505050565b5f5f5f610c218686610ac7565b5090505f5f610c31888888610863565b6001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015610c6c573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c9091906129ab565b5091509150826001600160a01b0316886001600160a01b031614610cb5578082610cb8565b81815b90999098509650505050505050565b606081610cd3816119d6565b7f00000000000000000000000042000000000000000000000000000000000000066001600160a01b031686865f818110610d0f57610d0f6128a7565b610d2592602060609092020190810191506128bb565b6001600160a01b031614610d4c576040516320db826760e01b815260040160405180910390fd5b610d9d348787808060200260200160405190810160405280939291908181526020015f905b8282101561060e57610d8e606083028601368190038101906128d6565b81526020019060010190610d71565b9150868260018451610daf9190612894565b81518110610dbf57610dbf6128a7565b60200260200101511015610de6576040516342301c2360e01b815260040160405180910390fd5b7f00000000000000000000000042000000000000000000000000000000000000066001600160a01b031663d0e30db0835f81518110610e2757610e276128a7565b60200260200101516040518263ffffffff1660e01b81526004015f604051808303818588803b158015610e58575f5ffd5b505af1158015610e6a573d5f5f3e3d5ffd5b50505050507f00000000000000000000000042000000000000000000000000000000000000066001600160a01b031663a9059cbb610f0588885f818110610eb357610eb36128a7565b610ec992602060609092020190810191506128bb565b89895f818110610edb57610edb6128a7565b9050606002016020016020810190610ef391906128bb565b8a8a5f8181106106f4576106f46128a7565b845f81518110610f1757610f176128a7565b60200260200101516040518363ffffffff1660e01b8152600401610f509291906001600160a01b03929092168252602082015260400190565b6020604051808303815f875af1158015610f6c573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f9091906129d6565b610f9c57610f9c6129f1565b610ff8828787808060200260200160405190810160405280939291908181526020015f905b82821015610fed57610fde606083028601368190038101906128d6565b81526020019060010190610fc1565b505050505086611aea565b5095945050505050565b6060600182511015611027576040516320db826760e01b815260040160405180910390fd5b8151611034906001612a05565b67ffffffffffffffff81111561104c5761104c61261e565b604051908082528060200260200182016040528015611075578160200160208202803683370190505b50905082815f8151811061108b5761108b6128a7565b602090810291909101015281515f5b81811015611299575f6111048583815181106110b8576110b86128a7565b60200260200101515f01518684815181106110d5576110d56128a7565b6020026020010151602001518785815181106110f3576110f36128a7565b602002602001015160400151610863565b604051635b16ebb760e01b81526001600160a01b0380831660048301529192507f00000000000000000000000031832f2a97fd20664d76cc421207669b55ce4bc090911690635b16ebb790602401602060405180830381865afa15801561116d573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061119191906129d6565b1561127757806001600160a01b031663f140a35a8584815181106111b7576111b76128a7565b60200260200101518785815181106111d1576111d16128a7565b60200260200101515f01516040518363ffffffff1660e01b815260040161120b9291909182526001600160a01b0316602082015260400190565b602060405180830381865afa158015611226573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061124a919061294a565b84611256846001612a05565b81518110611266576112666128a7565b602002602001018181525050611290565b6040516320db826760e01b815260040160405180910390fd5b5060010161109a565b505092915050565b5f5f5f5f7f00000000000000000000000031832f2a97fd20664d76cc421207669b55ce4bc06001600160a01b03166379bc57d58a8a8a6040518463ffffffff1660e01b81526004016112f59392919061290b565b602060405180830381865afa158015611310573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611334919061292f565b90505f80806001600160a01b038416156113bb57836001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611384573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113a8919061294a565b90506113b58c8c8c610c14565b90935091505b821580156113c7575081155b156113f8578896508795506103e86113e76113e2888a612961565b611ff5565b6113f19190612894565b9450611489565b5f6114048a85856120e0565b905088811161144c5789975095508561144584611421848b612961565b61142b919061298c565b84611436858b612961565b611440919061298c565b612147565b9550611487565b5f6114588a85876120e0565b98508997508890506114838561146e8584612961565b611478919061298c565b85611436868c612961565b9650505b505b50505050955095509592505050565b5f5f5f836114a5816119d6565b6114d48b7f00000000000000000000000042000000000000000000000000000000000000068c8c348d8d611db8565b90945092505f6115058c7f00000000000000000000000042000000000000000000000000000000000000068d610863565b90506115138c3383886119fa565b7f00000000000000000000000042000000000000000000000000000000000000066001600160a01b031663d0e30db0856040518263ffffffff1660e01b81526004015f604051808303818588803b15801561156c575f5ffd5b505af115801561157e573d5f5f3e3d5ffd5b505060405163a9059cbb60e01b81526001600160a01b038581166004830152602482018990527f000000000000000000000000420000000000000000000000000000000000000616935063a9059cbb925060440190506020604051808303815f875af11580156115f0573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061161491906129d6565b611620576116206129f1565b6040516335313c2160e11b81526001600160a01b038881166004830152821690636a627842906024016020604051808303815f875af1158015611665573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611689919061294a565b9250833411156116a6576116a6336116a18634612894565b611d29565b50509750975097945050505050565b5f5f826116c1816119d6565b6116f18a7f00000000000000000000000042000000000000000000000000000000000000068b8b8b8b308b61040c565b90935091506117018a8685612160565b604051632e1a7d4d60e01b8152600481018390527f00000000000000000000000042000000000000000000000000000000000000066001600160a01b031690632e1a7d4d906024015f604051808303815f87803b158015611760575f5ffd5b505af1158015611772573d5f5f3e3d5ffd5b505050506117808583611d29565b5097509795505050505050565b606081611799816119d6565b6117ea888787808060200260200160405190810160405280939291908181526020015f905b8282101561060e576117db606083028601368190038101906128d6565b815260200190600101906117be565b91508682600184516117fc9190612894565b8151811061180c5761180c6128a7565b60200260200101511015611833576040516342301c2360e01b815260040160405180910390fd5b61184886865f818110610676576106766128a7565b610858828787808060200260200160405190810160405280939291908181526020015f905b82821015610fed5761188a606083028601368190038101906128d6565b8152602001906001019061186d565b5f816118a4816119d6565b6118d4897f00000000000000000000000042000000000000000000000000000000000000068a8a8a8a308a61040c565b6040516370a0823160e01b815230600482015290935061194b91508a9086906001600160a01b038316906370a0823190602401602060405180830381865afa158015611922573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611946919061294a565b612160565b604051632e1a7d4d60e01b8152600481018390527f00000000000000000000000042000000000000000000000000000000000000066001600160a01b031690632e1a7d4d906024015f604051808303815f87803b1580156119aa575f5ffd5b505af11580156119bc573d5f5f3e3d5ffd5b505050506119ca8483611d29565b50979650505050505050565b428110156119f757604051630407b05b60e31b815260040160405180910390fd5b50565b5f846001600160a01b03163b11611a0f575f5ffd5b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b17905291515f92839290881691611a729190612a18565b5f604051808303815f865af19150503d805f8114611aab576040519150601f19603f3d011682016040523d82523d5f602084013e611ab0565b606091505b5091509150818015611ada575080511580611ada575080806020019051810190611ada91906129d6565b611ae2575f5ffd5b505050505050565b81515f5b81811015611d22575f611b3a858381518110611b0c57611b0c6128a7565b60200260200101515f0151868481518110611b2957611b296128a7565b602002602001015160200151610ac7565b5090505f86611b4a846001612a05565b81518110611b5a57611b5a6128a7565b602002602001015190505f5f836001600160a01b0316888681518110611b8257611b826128a7565b60200260200101515f01516001600160a01b031614611ba257825f611ba5565b5f835b915091505f60018951611bb89190612894565b8610611bc45787611c36565b611c3689611bd3886001612a05565b81518110611be357611be36128a7565b60200260200101515f01518a886001611bfc9190612a05565b81518110611c0c57611c0c6128a7565b6020026020010151602001518b896001611c269190612a05565b815181106110f3576110f36128a7565b9050611c88898781518110611c4d57611c4d6128a7565b60200260200101515f01518a8881518110611c6a57611c6a6128a7565b6020026020010151602001518b89815181106110f3576110f36128a7565b6001600160a01b031663022c0d9f8484845f6040519080825280601f01601f191660200182016040528015611cc4576020820181803683370190505b506040518563ffffffff1660e01b8152600401611ce49493929190612a2e565b5f604051808303815f87803b158015611cfb575f5ffd5b505af1158015611d0d573d5f5f3e3d5ffd5b505060019097019650611aee95505050505050565b5050505050565b604080515f808252602082019092526001600160a01b038416908390604051611d529190612a18565b5f6040518083038185875af1925050503d805f8114611d8c576040519150601f19603f3d011682016040523d82523d5f602084013e611d91565b606091505b5050905080611db35760405163b12d13eb60e01b815260040160405180910390fd5b505050565b5f5f83861015611ddb57604051636e35977960e11b815260040160405180910390fd5b82851015611dfc5760405163acee051360e01b815260040160405180910390fd5b6040516379bc57d560e01b81525f906001600160a01b037f00000000000000000000000031832f2a97fd20664d76cc421207669b55ce4bc016906379bc57d590611e4e908d908d908d9060040161290b565b602060405180830381865afa158015611e69573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e8d919061292f565b90506001600160a01b038116611f30576040516301b5fcad60e51b81526001600160a01b037f00000000000000000000000031832f2a97fd20664d76cc421207669b55ce4bc016906336bf95a090611eed908d908d908d9060040161290b565b6020604051808303815f875af1158015611f09573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f2d919061292f565b90505b5f5f611f3d8c8c8c610c14565b91509150815f148015611f4e575080155b15611f5e57889450879350611fe6565b5f611f6a8a84846120e0565b9050888111611f9f5786811015611f9457604051630d32418960e21b815260040160405180910390fd5b899550935083611fe4565b5f611fab8a84866120e0565b90508a811115611fbd57611fbd6129f1565b88811015611fde576040516323d9bb0560e21b815260040160405180910390fd5b95508894505b505b50505097509795505050505050565b5f815f0361200457505f919050565b5f600161201084612240565b901c6001901b9050600181848161202957612029612978565b048201901c9050600181848161204157612041612978565b048201901c9050600181848161205957612059612978565b048201901c9050600181848161207157612071612978565b048201901c9050600181848161208957612089612978565b048201901c905060018184816120a1576120a1612978565b048201901c905060018184816120b9576120b9612978565b048201901c90506120d9818285816120d3576120d3612978565b04612147565b9392505050565b5f835f0361210157604051632ca2f52b60e11b815260040160405180910390fd5b82158061210c575081155b1561212a5760405163bb55fd2760e01b815260040160405180910390fd5b826121358386612961565b61213f919061298c565b949350505050565b5f8183106121555781612157565b825b90505b92915050565b5f836001600160a01b03163b11612175575f5ffd5b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291515f928392908716916121d09190612a18565b5f604051808303815f865af19150503d805f8114612209576040519150601f19603f3d011682016040523d82523d5f602084013e61220e565b606091505b509150915081801561223857508051158061223857508080602001905181019061223891906129d6565b611d22575f5ffd5b5f80608083901c1561225457608092831c92015b604083901c1561226657604092831c92015b602083901c1561227857602092831c92015b601083901c1561228a57601092831c92015b600883901c1561229c57600892831c92015b600483901c156122ae57600492831c92015b600283901c156122c057600292831c92015b600183901c1561215a5760010192915050565b6001600160a01b03811681146119f7575f5ffd5b80151581146119f7575f5ffd5b5f5f5f5f5f5f5f5f610100898b03121561230c575f5ffd5b8835612317816122d3565b97506020890135612327816122d3565b96506040890135612337816122e7565b9550606089013594506080890135935060a0890135925060c089013561235c816122d3565b979a969950949793969295919450919260e001359150565b5f5f83601f840112612384575f5ffd5b50813567ffffffffffffffff81111561239b575f5ffd5b602083019150836020606083028501011115610b4a575f5ffd5b5f5f5f5f5f5f60a087890312156123ca575f5ffd5b8635955060208701359450604087013567ffffffffffffffff8111156123ee575f5ffd5b6123fa89828a01612374565b909550935050606087013561240e816122d3565b95989497509295919493608090920135925050565b602080825282518282018190525f918401906040840190835b8181101561245a57835183526020938401939092019160010161243c565b509095945050505050565b5f5f5f60608486031215612477575f5ffd5b8335612482816122d3565b92506020840135612492816122d3565b915060408401356124a2816122e7565b809150509250925092565b5f5f5f5f608085870312156124c0575f5ffd5b84356124cb816122d3565b935060208501356124db816122d3565b925060408501356124eb816122e7565b9396929550929360600135925050565b5f5f6040838503121561250c575f5ffd5b8235612517816122d3565b91506020830135612527816122d3565b809150509250929050565b5f5f5f5f5f5f5f5f5f6101208a8c03121561254b575f5ffd5b8935612556816122d3565b985060208a0135612566816122d3565b975060408a0135612576816122e7565b965060608a0135955060808a0135945060a08a0135935060c08a0135925060e08a01356125a2816122d3565b989b979a5095989497939692955090936101000135919050565b5f5f5f5f5f608086880312156125d0575f5ffd5b85359450602086013567ffffffffffffffff8111156125ed575f5ffd5b6125f988828901612374565b909550935050604086013561260d816122d3565b949793965091946060013592915050565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561265b5761265b61261e565b604052919050565b5f60608284031215612673575f5ffd5b6040516060810167ffffffffffffffff811182821017156126965761269661261e565b60405290508082356126a7816122d3565b815260208301356126b7816122d3565b602082015260408301356126ca816122e7565b6040919091015292915050565b5f5f604083850312156126e8575f5ffd5b82359150602083013567ffffffffffffffff811115612705575f5ffd5b8301601f81018513612715575f5ffd5b803567ffffffffffffffff81111561272f5761272f61261e565b61273e60208260051b01612632565b8082825260208201915060206060840285010192508783111561275f575f5ffd5b6020840193505b8284101561278b576127788885612663565b8252602082019150606084019350612766565b809450505050509250929050565b5f5f5f5f5f60a086880312156127ad575f5ffd5b85356127b8816122d3565b945060208601356127c8816122d3565b935060408601356127d8816122e7565b94979396509394606081013594506080013592915050565b5f5f5f5f5f5f5f60e0888a031215612806575f5ffd5b8735612811816122d3565b96506020880135612821816122e7565b955060408801359450606088013593506080880135925060a0880135612846816122d3565b96999598509396929591949193505060c09091013590565b5f5f6040838503121561286f575f5ffd5b505080516020909101519092909150565b634e487b7160e01b5f52601160045260245ffd5b8181038181111561215a5761215a612880565b634e487b7160e01b5f52603260045260245ffd5b5f602082840312156128cb575f5ffd5b81356120d9816122d3565b5f606082840312156128e6575f5ffd5b6121578383612663565b5f60208284031215612900575f5ffd5b81356120d9816122e7565b6001600160a01b039384168152919092166020820152901515604082015260600190565b5f6020828403121561293f575f5ffd5b81516120d9816122d3565b5f6020828403121561295a575f5ffd5b5051919050565b808202811582820484141761215a5761215a612880565b634e487b7160e01b5f52601260045260245ffd5b5f826129a657634e487b7160e01b5f52601260045260245ffd5b500490565b5f5f5f606084860312156129bd575f5ffd5b5050815160208301516040909301519094929350919050565b5f602082840312156129e6575f5ffd5b81516120d9816122e7565b634e487b7160e01b5f52600160045260245ffd5b8082018082111561215a5761215a612880565b5f82518060208501845e5f920191825250919050565b84815283602082015260018060a01b0383166040820152608060608201525f8251806080840152806020850160a085015e5f60a0828501015260a0601f19601f8301168401019150509594505050505056fea26469706673582212204be651d0a9aafdfc35e6ba3f749de7739ddfe05e5fa91f4726ad079313c3f5e164736f6c634300081b0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000031832f2a97fd20664d76cc421207669b55ce4bc00000000000000000000000004200000000000000000000000000000000000006
-----Decoded View---------------
Arg [0] : _factory (address): 0x31832f2a97Fd20664D76Cc421207669b55CE4BC0
Arg [1] : _weth (address): 0x4200000000000000000000000000000000000006
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 00000000000000000000000031832f2a97fd20664d76cc421207669b55ce4bc0
Arg [1] : 0000000000000000000000004200000000000000000000000000000000000006
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|---|---|---|---|---|
| BASE | 100.00% | $3,110.45 | 0.00000845 | $0.026282 |
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.