Source Code
Overview
HYPE Balance
HYPE Value
$0.00| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 1588292 | 305 days ago | Contract Creation | 0 HYPE |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
SovereignPool
Compiler Version
v0.8.19+commit.7dd6d404
Optimization Enabled:
Yes with 10000 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {Math} from "../../lib/openzeppelin-contracts/contracts/utils/math/Math.sol";
import {IERC20} from "../../lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "../../lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";
import {Constants} from "../utils/Constants.sol";
import {ReentrancyGuard} from "../utils/ReentrancyGuard.sol";
import {ISwapFeeModule, SwapFeeModuleData} from "../swap-fee-modules/interfaces/ISwapFeeModule.sol";
import {ISovereignPool} from "./interfaces/ISovereignPool.sol";
import {ISovereignPoolSwapCallback} from "./interfaces/ISovereignPoolSwapCallback.sol";
import {IVerifierModule} from "./interfaces/IVerifierModule.sol";
import {ALMLiquidityQuoteInput, ALMLiquidityQuote} from "../ALM/structs/SovereignALMStructs.sol";
import {ISovereignVaultMinimal} from "./interfaces/ISovereignVaultMinimal.sol";
import {ISovereignALM} from "../ALM/interfaces/ISovereignALM.sol";
import {ISovereignOracle} from "../oracles/interfaces/ISovereignOracle.sol";
import {SovereignPoolConstructorArgs, SwapCache, SovereignPoolSwapParams} from "./structs/SovereignPoolStructs.sol";
import {IFlashBorrower} from "./interfaces/IFlashBorrower.sol";
/**
* @notice Valantis Sovereign Pool
* @dev Sovereign Pools contain the following Modules:
* - Swap Fee Module (Optional): Calculates swap fees.
* - Algorithmic Liquidity Module (ALM): Contains any kind of DEX logic.
* - Oracle Module (Optional): Can checkpoint swap data in order to
* build time-weighted price and/or volatility estimates.
* - Verifier Module (Optional): Manages custom access conditions for swaps, deposits and withdrawals.
* - Sovereign Vault (Optional): Allows LPs to store the funds in this contract instead of the pool.
* This allows for easier interoperability with other protocols and multi-token pool support.
* If not specified, the pool itself will hold the LPs' reserves.
*/
contract SovereignPool is ISovereignPool, ReentrancyGuard {
using SafeERC20 for IERC20;
/**
*
* ENUMS
*
*/
/**
* @notice Verifier access types.
*/
enum AccessType {
SWAP,
DEPOSIT,
WITHDRAW
}
/**
*
* CUSTOM ERRORS
*
*/
error SovereignPool__ALMAlreadySet();
error SovereignPool__excessiveToken0AbsErrorTolerance();
error SovereignPool__excessiveToken1AbsErrorTolerance();
error SovereignPool__onlyALM();
error SovereignPool__onlyGauge();
error SovereignPool__onlyPoolManager();
error SovereignPool__onlyProtocolFactory();
error SovereignPool__sameTokenNotAllowed();
error SovereignPool__ZeroAddress();
error SovereignPool__depositLiquidity_depositDisabled();
error SovereignPool__depositLiquidity_excessiveToken0ErrorOnTransfer();
error SovereignPool__depositLiquidity_excessiveToken1ErrorOnTransfer();
error SovereignPool__depositLiquidity_incorrectTokenAmount();
error SovereignPool__depositLiquidity_insufficientToken0Amount();
error SovereignPool__depositLiquidity_insufficientToken1Amount();
error SovereignPool__depositLiquidity_zeroTotalDepositAmount();
error SovereignPool__getReserves_invalidReservesLength();
error SovereignPool__setGauge_gaugeAlreadySet();
error SovereignPool__setGauge_invalidAddress();
error SovereignPool__setPoolManagerFeeBips_excessivePoolManagerFee();
error SovereignPool__setSovereignOracle_oracleDisabled();
error SovereignPool__setSovereignOracle_sovereignOracleAlreadySet();
error SovereignPool__swap_excessiveSwapFee();
error SovereignPool__swap_expired();
error SovereignPool__swap_invalidLiquidityQuote();
error SovereignPool__swap_invalidPoolTokenOut();
error SovereignPool__swap_invalidRecipient();
error SovereignPool__swap_insufficientAmountIn();
error SovereignPool__swap_invalidSwapTokenOut();
error SovereignPool__swap_zeroAmountInOrOut();
error SovereignPool__setSwapFeeModule_timelock();
error SovereignPool__withdrawLiquidity_withdrawDisabled();
error SovereignPool__withdrawLiquidity_insufficientReserve0();
error SovereignPool__withdrawLiquidity_insufficientReserve1();
error SovereignPool__withdrawLiquidity_invalidRecipient();
error SovereignPool___claimPoolManagerFees_invalidFeeReceived();
error SovereignPool___claimPoolManagerFees_invalidProtocolFee();
error SovereignPool___handleTokenInOnSwap_excessiveTokenInErrorOnTransfer();
error SovereignPool___handleTokenInOnSwap_invalidTokenInAmount();
error SovereignPool___verifyPermission_onlyPermissionedAccess(address sender, uint8 accessType);
/**
*
* CONSTANTS
*
*/
/**
* @notice Maximum swap fee is 50% of input amount.
* @dev See docs for a more detailed explanation about how swap fees are applied.
*/
uint256 private constant _MAX_SWAP_FEE_BIPS = 10_000;
/**
* @notice Factor of one or 100% representation in Basis points
*/
uint256 private constant _FACTOR_ONE = 10_000;
/**
* @notice `poolManager` can collect up to 50% of swap fees.
*/
uint256 private constant _MAX_POOL_MANAGER_FEE_BIPS = 5_000;
/**
* @notice Maximum allowed error tolerance on rebase token transfers.
* @dev See: https://github.com/lidofinance/lido-dao/issues/442.
*/
uint256 private constant _MAX_ABS_ERROR_TOLERANCE = 10;
/**
* @dev ERC-3156 onFlashLoan callback return data on success.
*/
bytes32 private constant _CALLBACK_SUCCESS = keccak256("ERC3156FlashBorrower.onFlashLoan");
/**
*
* IMMUTABLES
*
*/
/**
* @notice Address of Sovereign Vault (Optional), where token reserves will be kept.
* @dev If set as this pool's address, it will work as a typical two token pool.
* Otherwise it can be set as any external vault or singleton.
* @dev When sovereignVault is not this pool's address:
* - Reserves cannot be kept in the pool, hence `depositLiquidity` and `flashLoan` are disabled.
* - During swaps, input token must be transferred to `sovereignVault`.
* - During swaps, input token can only be token0 or token1.
* But if `sovereignVault != address(this)`, output token can be any other token.
*/
address public immutable sovereignVault;
/**
* @notice Address of Protocol Factory.
*/
address public immutable protocolFactory;
/**
* @notice Default pool swap fee in basis-points (bips).
* @dev Can be overriden by whitelisting a Swap Fee Module.
* @dev See docs for a more detailed explanation about how swap fees are applied.
*/
uint256 public immutable defaultSwapFeeBips;
/**
* @notice Verifier Module (Optional).
* @dev Verifies custom authentication conditions on deposits, withdrawals and swaps.
*/
IVerifierModule private immutable _verifierModule;
/**
* @notice Tokens supported by this pool.
* @dev These are not necessarily the only tokens
* available to trade against this pool:
*
* If `sovereignVault` == address(this):
* In this case only `_token0` and `_token1` can be exchanged.
* If `sovereignVault` != address(this):
* In this case `_token0` and `token1` can be the input token for a swap,
* but any other token can be quoted as the output token (given by calling `getTokens`).
*/
IERC20 private immutable _token0;
IERC20 private immutable _token1;
/**
* @notice True if token0 is a rebase token.
*/
bool public immutable isToken0Rebase;
/**
* @notice True if token1 is a rebase token.
*/
bool public immutable isToken1Rebase;
/**
* @notice Maximum absolute error allowed on token0 transfers.
* @dev Only relevant if token0 is a rebase token.
* See: https://github.com/lidofinance/lido-dao/issues/442.
*/
uint256 public immutable token0AbsErrorTolerance;
/**
* @notice Maximum absolute error allowed on token1 transfers.
* @dev Only relevant if token1 is a rebase token.
* See: https://github.com/lidofinance/lido-dao/issues/442.
*/
uint256 public immutable token1AbsErrorTolerance;
/**
*
* STORAGE
*
*/
/**
* @notice Address of Sovereign ALM position bound to this pool.
* @dev Settable by `poolManager` only once.
*/
address public alm;
/**
* @notice Address of Gauge bound to this pool.
* @dev Settable by `protocolFactory` only once.
*/
address public gauge;
/**
* @notice Address of Pool Manager.
* @dev Can optionally set modules and parameters in this pool.
*/
address public poolManager;
/**
* @notice Fraction of swap fees that go into `poolManager`, in bips.
* @dev Remaining fraction goes to LPs.
*/
uint256 public poolManagerFeeBips;
/**
* @notice Total token0 and token1 fees accrued by `poolManager`.
*/
uint256 public feePoolManager0;
uint256 public feePoolManager1;
/**
* @notice token0 and token1 fees donated to Gauges by `poolManager`.
*/
uint256 public feeProtocol0;
uint256 public feeProtocol1;
/**
* @notice Block timestamp at or after which Swap Fee Module can be updated by `poolManager`.
* @dev This is meant to function as a time-lock to prevent `poolManager` from front-run user swaps,
* which could rapidly increase swap fees at arbitrary block times.
*/
uint256 public swapFeeModuleUpdateTimestamp;
/**
* @notice token0 and token1 LP reserves.
*/
uint256 private _reserve0;
uint256 private _reserve1;
/**
* @notice Sovereign Oracle Module (Optional).
* @dev Can accumulate swap data checkpoints and act as an on-chain price or volatility oracle.
*/
ISovereignOracle private _sovereignOracleModule;
/**
* @notice Swap Fee Module (Optional).
* @dev Defines custom logic to compute swap fees.
* @dev If not specified, a constant `defaultSwapFeeBips` will be used.
* @dev See docs for a more detailed explanation about how swap fees are applied.
*/
ISwapFeeModule private _swapFeeModule;
/**
*
* MODIFIERS
*
*/
modifier onlyALM() {
_onlyALM();
_;
}
modifier onlyProtocolFactory() {
_onlyProtocolFactory();
_;
}
modifier onlyPoolManager() {
_onlyPoolManager();
_;
}
modifier onlyGauge() {
_onlyGauge();
_;
}
/**
*
* CONSTRUCTOR
*
*/
constructor(SovereignPoolConstructorArgs memory args) {
if (args.token0 == args.token1) {
revert SovereignPool__sameTokenNotAllowed();
}
if (args.token0 == address(0) || args.token1 == address(0)) {
revert SovereignPool__ZeroAddress();
}
sovereignVault = args.sovereignVault == address(0) ? address(this) : args.sovereignVault;
_verifierModule = IVerifierModule(args.verifierModule);
_token0 = IERC20(args.token0);
_token1 = IERC20(args.token1);
protocolFactory = args.protocolFactory;
poolManager = args.poolManager;
isToken0Rebase = args.isToken0Rebase;
isToken1Rebase = args.isToken1Rebase;
// Irrelevant in case of non-rebase tokens
if (args.token0AbsErrorTolerance > _MAX_ABS_ERROR_TOLERANCE) {
revert SovereignPool__excessiveToken0AbsErrorTolerance();
}
if (args.token1AbsErrorTolerance > _MAX_ABS_ERROR_TOLERANCE) {
revert SovereignPool__excessiveToken1AbsErrorTolerance();
}
token0AbsErrorTolerance = args.token0AbsErrorTolerance;
token1AbsErrorTolerance = args.token1AbsErrorTolerance;
defaultSwapFeeBips =
args.defaultSwapFeeBips <= _MAX_SWAP_FEE_BIPS ? args.defaultSwapFeeBips : _MAX_SWAP_FEE_BIPS;
// Initialize timestamp at which Swap Fee Module can be set
swapFeeModuleUpdateTimestamp = block.timestamp;
}
/**
*
* VIEW FUNCTIONS
*
*/
/**
* @notice Returns array of tokens available to be swapped against this Sovereign Pool (as tokenOut).
* @dev In case `sovereignVault == address(this)`, only token0 and token1 are available.
* Otherwise, the pool queries `sovereignVault` to retrieve them.
*/
function getTokens() external view override returns (address[] memory tokens) {
if (sovereignVault == address(this)) {
// In this case only token0 and token1 can be swapped
tokens = new address[](2);
tokens[0] = address(_token0);
tokens[1] = address(_token1);
} else {
// Data validation should be performed by either caller or `sovereignVault`
tokens = ISovereignVaultMinimal(sovereignVault).getTokensForPool(address(this));
}
}
/**
* @notice Returns `token0` and `token1` reserves, respectively.
* @dev Reserves are measured differently in case of rebase tokens.
* WARNING: With rebase tokens, balances (hence reserves) can be easily manipulated.
* External contracts MUST be aware and take the right precautions.
* @dev In case `sovereignVault` is not the pool, reserves are queried from `sovereignVault`.
* @dev This function only queries reserves for `token0` and `token1`.
* In case `sovereignVault` supports other tokens, reserves should be queried from it directly.
* @dev This is exposed for convenience. The pool makes no assumptions regarding the way an
* external `sovereignVault` updates reserves internally.
*/
function getReserves() public view override returns (uint256, uint256) {
if (sovereignVault == address(this)) {
return (_getReservesForToken(true), _getReservesForToken(false));
} else {
address[] memory tokens = new address[](2);
tokens[0] = address(_token0);
tokens[1] = address(_token1);
uint256[] memory reserves = ISovereignVaultMinimal(sovereignVault).getReservesForPool(address(this), tokens);
// Only token0 and token1 reserves should be returned
if (reserves.length != 2) {
revert SovereignPool__getReserves_invalidReservesLength();
}
return (reserves[0], reserves[1]);
}
}
/**
* @notice Returns pool manager fee in amount of token0 and token1.
*/
function getPoolManagerFees() public view override returns (uint256, uint256) {
return (feePoolManager0, feePoolManager1);
}
/**
* @notice Returns True if this pool contains at least one rebase token.
*/
function isRebaseTokenPool() external view override returns (bool) {
return isToken0Rebase || isToken1Rebase;
}
/**
* @notice Returns the address of token0.
*/
function token0() external view override returns (address) {
return address(_token0);
}
/**
* @notice Returns the address of token1.
*/
function token1() external view override returns (address) {
return address(_token1);
}
/**
* @notice Returns address of Oracle module in this pool.
*/
function sovereignOracleModule() external view override returns (address) {
return address(_sovereignOracleModule);
}
/**
* @notice Returns the address of the swapFeeModule in this pool.
*/
function swapFeeModule() external view override returns (address) {
return address(_swapFeeModule);
}
/**
* @notice Returns the address of the verifier module in this pool.
*/
function verifierModule() external view override returns (address) {
return address(_verifierModule);
}
/**
* @notice Exposes the status of reentrancy lock.
* @dev ALMs and other external smart contracts can use it for reentrancy protection.
* Mainly useful for read-only reentrancy protection.
*/
function isLocked() external view override returns (bool) {
return _status == _ENTERED;
}
/**
*
* EXTERNAL FUNCTIONS
*
*/
/**
* @notice Sets address of `poolManager`.
* @dev Settable by `poolManager`.
* @param _manager Address of new pool manager.
*/
function setPoolManager(address _manager) external override onlyPoolManager nonReentrant {
poolManager = _manager;
if (_manager == address(0)) {
poolManagerFeeBips = 0;
// It will be assumed pool is not going to contribute anything to protocol fees.
_claimPoolManagerFees(0, 0, msg.sender);
emit PoolManagerFeeSet(0);
}
emit PoolManagerSet(_manager);
}
/**
* @notice Set fee in BIPS for `poolManager`.
* @dev Must not be greater than MAX_POOL_MANAGER_FEE_BIPS.
* @dev Settable by `poolManager`.
* @param _poolManagerFeeBips fee to set in BIPS.
*/
function setPoolManagerFeeBips(uint256 _poolManagerFeeBips) external override onlyPoolManager nonReentrant {
if (_poolManagerFeeBips > _MAX_POOL_MANAGER_FEE_BIPS) {
revert SovereignPool__setPoolManagerFeeBips_excessivePoolManagerFee();
}
poolManagerFeeBips = _poolManagerFeeBips;
emit PoolManagerFeeSet(_poolManagerFeeBips);
}
/**
* @notice Set Sovereign Oracle Module in this pool.
* @dev Can only be set once by `poolManager`.
* @param sovereignOracle Address of Sovereign Oracle Module instance.
*/
function setSovereignOracle(address sovereignOracle) external override onlyPoolManager nonReentrant {
if (sovereignOracle == address(0)) {
revert SovereignPool__ZeroAddress();
}
if (address(sovereignVault) != address(this)) revert SovereignPool__setSovereignOracle_oracleDisabled();
if (address(_sovereignOracleModule) != address(0)) {
revert SovereignPool__setSovereignOracle_sovereignOracleAlreadySet();
}
_sovereignOracleModule = ISovereignOracle(sovereignOracle);
emit SovereignOracleSet(sovereignOracle);
}
/**
* @notice Set Gauge in this pool.
* @dev Can only be set once by `protocolFactory`.
* @param _gauge Address of Gauge instance.
*/
function setGauge(address _gauge) external override onlyProtocolFactory nonReentrant {
if (gauge != address(0)) {
revert SovereignPool__setGauge_gaugeAlreadySet();
}
if (_gauge == address(0)) {
revert SovereignPool__setGauge_invalidAddress();
}
gauge = _gauge;
emit GaugeSet(_gauge);
}
/**
* @notice Set Swap Fee Module for this pool.
* @dev Only callable by `poolManager`.
* @dev If set as address(0), a constant default swap fee will be applied.
* @dev It contains a 3 days timelock, to prevent `poolManager` from front-running
* swaps by rapidly increasing swap fees too frequently.
* @param swapFeeModule_ Address of Swap Fee Module to whitelist.
*/
function setSwapFeeModule(address swapFeeModule_) external override onlyPoolManager nonReentrant {
// Swap Fee Module cannot be updated too frequently (at most once every 3 days)
if (block.timestamp < swapFeeModuleUpdateTimestamp) {
revert SovereignPool__setSwapFeeModule_timelock();
}
_swapFeeModule = ISwapFeeModule(swapFeeModule_);
// Update timestamp at which the next Swap Fee Module update can occur
swapFeeModuleUpdateTimestamp = block.timestamp + 3 days;
emit SwapFeeModuleSet(swapFeeModule_);
}
/**
* @notice Set ALM for this pool.
* @dev Only callable by `poolManager`.
* @dev Can only be called once.
* @param _alm Address of ALM to whitelist.
*/
function setALM(address _alm) external override onlyPoolManager nonReentrant {
if (_alm == address(0)) {
revert SovereignPool__ZeroAddress();
}
if (alm != address(0)) {
revert SovereignPool__ALMAlreadySet();
}
alm = _alm;
emit ALMSet(_alm);
}
function flashLoan(bool _isTokenZero, IFlashBorrower _receiver, uint256 _amount, bytes calldata _data)
external
nonReentrant
{
// We disable flash-loans,
// since reserves are not meant to be stored in the pool
if (sovereignVault != address(this)) revert ValantisPool__flashLoan_flashLoanDisabled();
IERC20 flashToken = _isTokenZero ? _token0 : _token1;
bool isRebaseFlashToken = _isTokenZero ? isToken0Rebase : isToken1Rebase;
// Flash-loans for rebase tokens are disabled.
// Easy to manipulate token reserves would significantly
// increase the attack surface for contracts that rely on this pool
if (isRebaseFlashToken) {
revert ValantisPool__flashLoan_rebaseTokenNotAllowed();
}
uint256 poolPreBalance = flashToken.balanceOf(address(this));
flashToken.safeTransfer(address(_receiver), _amount);
if (_receiver.onFlashLoan(msg.sender, address(flashToken), _amount, _data) != _CALLBACK_SUCCESS) {
revert ValantisPool__flashloan_callbackFailed();
}
flashToken.safeTransferFrom(address(_receiver), address(this), _amount);
if (flashToken.balanceOf(address(this)) != poolPreBalance) {
revert ValantisPool__flashLoan_flashLoanNotRepaid();
}
emit Flashloan(msg.sender, address(_receiver), _amount, address(flashToken));
}
/**
* @notice Claim share of fees accrued by this pool
* And optionally share some with the protocol.
* @dev Only callable by `poolManager`.
* @param _feeProtocol0Bips Amount of `token0` fees to be shared with protocol.
* @param _feeProtocol1Bips Amount of `token1` fees to be shared with protocol.
*/
function claimPoolManagerFees(uint256 _feeProtocol0Bips, uint256 _feeProtocol1Bips)
external
override
nonReentrant
onlyPoolManager
returns (uint256 feePoolManager0Received, uint256 feePoolManager1Received)
{
(feePoolManager0Received, feePoolManager1Received) =
_claimPoolManagerFees(_feeProtocol0Bips, _feeProtocol1Bips, msg.sender);
}
/**
* @notice Claim accrued protocol fees, if any.
* @dev Only callable by `gauge`.
*/
function claimProtocolFees() external override nonReentrant onlyGauge returns (uint256, uint256) {
uint256 feeProtocol0Cache = feeProtocol0;
uint256 feeProtocol1Cache = feeProtocol1;
if (feeProtocol0Cache > 0) {
feeProtocol0 = 0;
_token0.safeTransfer(msg.sender, feeProtocol0Cache);
}
if (feeProtocol1Cache > 0) {
feeProtocol1 = 0;
_token1.safeTransfer(msg.sender, feeProtocol1Cache);
}
return (feeProtocol0Cache, feeProtocol1Cache);
}
/**
* @notice Swap against the ALM Position in this pool.
* @param _swapParams Struct containing all params.
* isSwapCallback If this swap should claim funds using a callback.
* isZeroToOne Direction of the swap.
* amountIn Input amount to swap.
* amountOutMin Minimum output token amount required.
* deadline Block timestamp after which the swap is no longer valid.
* recipient Recipient address for output token.
* swapTokenOut Address of output token.
* If `sovereignVault != address(this)` it can be other tokens apart from token0 or token1.
* swapContext Struct containing ALM's external, Verifier's and Swap Callback's context data.
* @return amountInUsed Amount of input token filled by this swap.
* @return amountOut Amount of output token provided by this swap.
*/
function swap(SovereignPoolSwapParams calldata _swapParams)
external
override
nonReentrant
returns (uint256 amountInUsed, uint256 amountOut)
{
if (block.timestamp > _swapParams.deadline) {
revert SovereignPool__swap_expired();
}
// Cannot swap zero input token amount
if (_swapParams.amountIn == 0) {
revert SovereignPool__swap_insufficientAmountIn();
}
if (_swapParams.recipient == address(0)) {
revert SovereignPool__swap_invalidRecipient();
}
SwapCache memory swapCache = SwapCache({
swapFeeModule: _swapFeeModule,
tokenInPool: _swapParams.isZeroToOne ? _token0 : _token1,
tokenOutPool: _swapParams.isZeroToOne ? _token1 : _token0,
amountInWithoutFee: 0
});
if (_swapParams.swapTokenOut == address(0) || _swapParams.swapTokenOut == address(swapCache.tokenInPool)) {
revert SovereignPool__swap_invalidSwapTokenOut();
}
// If reserves are kept in the pool, only token0 <-> token1 swaps are allowed
if (sovereignVault == address(this) && _swapParams.swapTokenOut != address(swapCache.tokenOutPool)) {
revert SovereignPool__swap_invalidPoolTokenOut();
}
bytes memory verifierData;
if (address(_verifierModule) != address(0)) {
// Query Verifier Module to authenticate the swap
verifierData =
_verifyPermission(msg.sender, _swapParams.swapContext.verifierContext, uint8(AccessType.SWAP));
}
// Calculate swap fee in bips
SwapFeeModuleData memory swapFeeModuleData;
if (address(swapCache.swapFeeModule) != address(0)) {
swapFeeModuleData = swapCache.swapFeeModule.getSwapFeeInBips(
address(swapCache.tokenInPool),
address(swapCache.tokenOutPool),
_swapParams.amountIn,
msg.sender,
_swapParams.swapContext.swapFeeModuleContext
);
if (swapFeeModuleData.feeInBips > _MAX_SWAP_FEE_BIPS) {
revert SovereignPool__swap_excessiveSwapFee();
}
} else {
swapFeeModuleData = SwapFeeModuleData({feeInBips: defaultSwapFeeBips, internalContext: new bytes(0)});
}
// Since we do not yet know how much of `amountIn` will be filled,
// this quantity is calculated in such a way that `msg.sender`
// will be charged `feeInBips` of whatever the amount of tokenIn filled
// ends up being (see docs for more details)
swapCache.amountInWithoutFee =
Math.mulDiv(_swapParams.amountIn, _MAX_SWAP_FEE_BIPS, _MAX_SWAP_FEE_BIPS + swapFeeModuleData.feeInBips);
ALMLiquidityQuote memory liquidityQuote = ISovereignALM(alm).getLiquidityQuote(
ALMLiquidityQuoteInput({
isZeroToOne: _swapParams.isZeroToOne,
amountInMinusFee: swapCache.amountInWithoutFee,
feeInBips: swapFeeModuleData.feeInBips,
sender: msg.sender,
recipient: _swapParams.recipient,
tokenOutSwap: _swapParams.swapTokenOut
}),
_swapParams.swapContext.externalContext,
verifierData
);
amountOut = liquidityQuote.amountOut;
if (
!_checkLiquidityQuote(
_swapParams.isZeroToOne,
swapCache.amountInWithoutFee,
liquidityQuote.amountInFilled,
amountOut,
_swapParams.amountOutMin
)
) {
revert SovereignPool__swap_invalidLiquidityQuote();
}
// If amountOut or amountInFilled is 0, we do not transfer any input token
if (amountOut == 0 || liquidityQuote.amountInFilled == 0) {
revert SovereignPool__swap_zeroAmountInOrOut();
}
// Calculate the actual swap fee to be charged in input token (`effectiveFee`),
// now that we know the tokenIn amount filled
uint256 effectiveFee;
if (liquidityQuote.amountInFilled != swapCache.amountInWithoutFee) {
effectiveFee = Math.mulDiv(
liquidityQuote.amountInFilled, swapFeeModuleData.feeInBips, _MAX_SWAP_FEE_BIPS, Math.Rounding.Up
);
amountInUsed = liquidityQuote.amountInFilled + effectiveFee;
} else {
// Using above formula in case amountInWithoutFee == amountInFilled introduces rounding errors
effectiveFee = _swapParams.amountIn - swapCache.amountInWithoutFee;
amountInUsed = _swapParams.amountIn;
}
_handleTokenInTransfersOnSwap(
_swapParams.isZeroToOne,
_swapParams.isSwapCallback,
swapCache.tokenInPool,
amountInUsed,
effectiveFee,
_swapParams.swapContext.swapCallbackContext
);
// Update internal state and oracle module.
// In case of rebase tokens, `amountInUsed` and `amountOut` might not match
// the exact balance deltas due to rounding errors.
_updatePoolStateOnSwap(_swapParams.isZeroToOne, amountInUsed, amountOut, effectiveFee);
if (
address(_sovereignOracleModule) != address(0) && _swapParams.swapTokenOut == address(swapCache.tokenOutPool)
&& amountInUsed > 0
) {
_sovereignOracleModule.writeOracleUpdate(_swapParams.isZeroToOne, amountInUsed, effectiveFee, amountOut);
}
// Transfer `amountOut to recipient
_handleTokenOutTransferOnSwap(IERC20(_swapParams.swapTokenOut), _swapParams.recipient, amountOut);
// Update state for Swap fee module,
// only performed if internalContext is non-empty
if (
address(swapCache.swapFeeModule) != address(0)
&& keccak256(swapFeeModuleData.internalContext) != keccak256(new bytes(0))
) {
swapCache.swapFeeModule.callbackOnSwapEnd(effectiveFee, amountInUsed, amountOut, swapFeeModuleData);
}
// Perform post-swap callback to liquidity module if necessary
if (liquidityQuote.isCallbackOnSwap) {
ISovereignALM(alm).onSwapCallback(_swapParams.isZeroToOne, amountInUsed, amountOut);
}
emit Swap(msg.sender, _swapParams.isZeroToOne, amountInUsed, effectiveFee, amountOut);
}
/**
* @notice Deposit liquidity into an ALM Position.
* @dev Only callable by its respective active ALM Position.
* @param _amount0 Amount of token0 to deposit.
* @param _amount1 Amount of token1 to deposit.
* @param _verificationContext Bytes containing verification data required in case of permissioned pool.
* @param _depositData Bytes encoded data for deposit callback.
* @return amount0Deposited Amount of token0 deposited.
* @return amount1Deposited Amount of token1 deposited.
*/
function depositLiquidity(
uint256 _amount0,
uint256 _amount1,
address _sender,
bytes calldata _verificationContext,
bytes calldata _depositData
) external override onlyALM nonReentrant returns (uint256 amount0Deposited, uint256 amount1Deposited) {
// We disable deposits,
// since reserves are not meant to be stored in the pool
if (sovereignVault != address(this)) revert SovereignPool__depositLiquidity_depositDisabled();
// At least one token amount must be positive
if (_amount0 | _amount1 == 0) {
revert SovereignPool__depositLiquidity_zeroTotalDepositAmount();
}
if (address(_verifierModule) != address(0)) {
_verifyPermission(_sender, _verificationContext, uint8(AccessType.DEPOSIT));
}
uint256 token0PreBalance = _token0.balanceOf(address(this));
uint256 token1PreBalance = _token1.balanceOf(address(this));
ISovereignALM(msg.sender).onDepositLiquidityCallback(_amount0, _amount1, _depositData);
amount0Deposited = _token0.balanceOf(address(this)) - token0PreBalance;
amount1Deposited = _token1.balanceOf(address(this)) - token1PreBalance;
// Post-deposit checks for token0
// _amount0 == 0 is interpreted as not depositing token0
if (_amount0 != 0) {
if (isToken0Rebase) {
uint256 amount0AbsDiff =
amount0Deposited < _amount0 ? _amount0 - amount0Deposited : amount0Deposited - _amount0;
if (amount0AbsDiff > token0AbsErrorTolerance) {
revert SovereignPool__depositLiquidity_excessiveToken0ErrorOnTransfer();
}
} else {
if (amount0Deposited != _amount0) revert SovereignPool__depositLiquidity_insufficientToken0Amount();
_reserve0 += amount0Deposited;
}
} else if (amount0Deposited > 0) {
revert SovereignPool__depositLiquidity_incorrectTokenAmount();
}
// Post-deposit checks for token1
// _amount1 == 0 is interpreted as not depositing token1
if (_amount1 != 0) {
if (isToken1Rebase) {
uint256 amount1AbsDiff =
amount1Deposited < _amount1 ? _amount1 - amount1Deposited : amount1Deposited - _amount1;
if (amount1AbsDiff > token1AbsErrorTolerance) {
revert SovereignPool__depositLiquidity_excessiveToken1ErrorOnTransfer();
}
} else {
if (amount1Deposited != _amount1) revert SovereignPool__depositLiquidity_insufficientToken1Amount();
_reserve1 += amount1Deposited;
}
} else if (amount1Deposited > 0) {
revert SovereignPool__depositLiquidity_incorrectTokenAmount();
}
emit DepositLiquidity(amount0Deposited, amount1Deposited);
}
/**
* @notice Withdraw liquidity from this pool to an ALM Position.
* @dev Only callable by ALM Position.
* @param _amount0 Amount of token0 reserves to withdraw.
* @param _amount1 Amount of token1 reserves to withdraw.
* @param _recipient Address of recipient.
* @param _verificationContext Bytes containing verfication data required in case of permissioned pool.
*/
function withdrawLiquidity(
uint256 _amount0,
uint256 _amount1,
address _sender,
address _recipient,
bytes calldata _verificationContext
) external override nonReentrant onlyALM {
if (_recipient == address(0)) {
revert SovereignPool__withdrawLiquidity_invalidRecipient();
}
// We disable withdrawals,
// since reserves are not meant to be stored in the pool
if (sovereignVault != address(this)) revert SovereignPool__withdrawLiquidity_withdrawDisabled();
if (address(_verifierModule) != address(0)) {
_verifyPermission(_sender, _verificationContext, uint8(AccessType.WITHDRAW));
}
if (_amount0 > _getReservesForToken(true)) {
revert SovereignPool__withdrawLiquidity_insufficientReserve0();
}
if (_amount1 > _getReservesForToken(false)) {
revert SovereignPool__withdrawLiquidity_insufficientReserve1();
}
// Already checked above
unchecked {
if (!isToken0Rebase) _reserve0 -= _amount0;
if (!isToken1Rebase) _reserve1 -= _amount1;
}
if (_amount0 > 0) {
_token0.safeTransfer(_recipient, _amount0);
}
if (_amount1 > 0) {
_token1.safeTransfer(_recipient, _amount1);
}
emit WithdrawLiquidity(_recipient, _amount0, _amount1);
}
/**
*
* PRIVATE FUNCTIONS
*
*/
function _claimPoolManagerFees(uint256 _feeProtocol0Bips, uint256 _feeProtocol1Bips, address _recipient)
private
returns (uint256 feePoolManager0Received, uint256 feePoolManager1Received)
{
if (_feeProtocol0Bips > _FACTOR_ONE || _feeProtocol1Bips > _FACTOR_ONE) {
revert SovereignPool___claimPoolManagerFees_invalidProtocolFee();
}
(feePoolManager0Received, feePoolManager1Received) = getPoolManagerFees();
// Attempt to claim pool manager fees from `sovereignVault`
// This is necessary since in this case reserves are not kept in this pool
if (sovereignVault != address(this)) {
uint256 token0PreBalance = _token0.balanceOf(address(this));
uint256 token1PreBalance = _token1.balanceOf(address(this));
ISovereignVaultMinimal(sovereignVault).claimPoolManagerFees(
feePoolManager0Received, feePoolManager1Received
);
uint256 fee0ReceivedCache = _token0.balanceOf(address(this)) - token0PreBalance;
uint256 fee1ReceivedCache = _token1.balanceOf(address(this)) - token1PreBalance;
// Cannot transfer in excess, otherwise it would be possible to manipulate this pool's
// fair share of earned swap fees
if (fee0ReceivedCache > feePoolManager0Received || fee1ReceivedCache > feePoolManager1Received) {
revert SovereignPool___claimPoolManagerFees_invalidFeeReceived();
}
feePoolManager0Received = fee0ReceivedCache;
feePoolManager1Received = fee1ReceivedCache;
}
uint256 protocolFee0 = Math.mulDiv(_feeProtocol0Bips, feePoolManager0Received, _FACTOR_ONE);
uint256 protocolFee1 = Math.mulDiv(_feeProtocol1Bips, feePoolManager1Received, _FACTOR_ONE);
feeProtocol0 += protocolFee0;
feeProtocol1 += protocolFee1;
feePoolManager0 = 0;
feePoolManager1 = 0;
feePoolManager0Received -= protocolFee0;
feePoolManager1Received -= protocolFee1;
if (feePoolManager0Received > 0) {
_token0.safeTransfer(_recipient, feePoolManager0Received);
}
if (feePoolManager1Received > 0) {
_token1.safeTransfer(_recipient, feePoolManager1Received);
}
emit PoolManagerFeesClaimed(feePoolManager0Received, feePoolManager1Received);
}
function _verifyPermission(address sender, bytes calldata verificationContext, uint8 accessType)
private
returns (bytes memory verifierData)
{
bool success;
(success, verifierData) = _verifierModule.verify(sender, verificationContext, accessType);
if (!success) {
revert SovereignPool___verifyPermission_onlyPermissionedAccess(sender, accessType);
}
}
function _handleTokenInTransfersOnSwap(
bool isZeroToOne,
bool isSwapCallback,
IERC20 token,
uint256 amountInUsed,
uint256 effectiveFee,
bytes calldata _swapCallbackContext
) private {
uint256 preBalance = token.balanceOf(sovereignVault);
if (isSwapCallback) {
ISovereignPoolSwapCallback(msg.sender).sovereignPoolSwapCallback(
address(token), amountInUsed, _swapCallbackContext
);
} else {
token.safeTransferFrom(msg.sender, sovereignVault, amountInUsed);
}
uint256 amountInReceived = token.balanceOf(sovereignVault) - preBalance;
bool isTokenInRebase = isZeroToOne ? isToken0Rebase : isToken1Rebase;
if (isTokenInRebase) {
uint256 tokenInAbsDiff =
amountInUsed > amountInReceived ? amountInUsed - amountInReceived : amountInReceived - amountInUsed;
uint256 tokenInAbsErrorTolerance = isZeroToOne ? token0AbsErrorTolerance : token1AbsErrorTolerance;
if (tokenInAbsDiff > tokenInAbsErrorTolerance) {
revert SovereignPool___handleTokenInOnSwap_excessiveTokenInErrorOnTransfer();
}
} else {
if (amountInReceived != amountInUsed) revert SovereignPool___handleTokenInOnSwap_invalidTokenInAmount();
}
if (isTokenInRebase && sovereignVault == address(this) && poolManager != address(0)) {
// We transfer manager fee to `poolManager`
uint256 poolManagerFee = Math.mulDiv(effectiveFee, poolManagerFeeBips, _FACTOR_ONE);
if (poolManagerFee > 0) {
token.safeTransfer(poolManager, poolManagerFee);
}
}
}
function _handleTokenOutTransferOnSwap(IERC20 swapTokenOut, address recipient, uint256 amountOut) private {
if (sovereignVault == address(this)) {
// In this case, tokenOut should be transferred from this pool to `recipient`
swapTokenOut.safeTransfer(recipient, amountOut);
} else {
// If `sovereignVault` is not this pool,
// ALM must have already approved this pool to send `amountOut` to `recipient`
swapTokenOut.safeTransferFrom(sovereignVault, recipient, amountOut);
}
}
function _updatePoolStateOnSwap(bool isZeroToOne, uint256 amountInUsed, uint256 amountOut, uint256 effectiveFee)
private
{
if (isZeroToOne) {
if (!isToken0Rebase) {
uint256 poolManagerFee = Math.mulDiv(effectiveFee, poolManagerFeeBips, _FACTOR_ONE);
if (sovereignVault == address(this)) _reserve0 += (amountInUsed - poolManagerFee);
if (poolManagerFee > 0) feePoolManager0 += poolManagerFee;
}
if (sovereignVault == address(this) && !isToken1Rebase) {
_reserve1 -= amountOut;
}
} else {
if (sovereignVault == address(this) && !isToken0Rebase) {
_reserve0 -= amountOut;
}
if (!isToken1Rebase) {
uint256 poolManagerFee = Math.mulDiv(effectiveFee, poolManagerFeeBips, _FACTOR_ONE);
if (sovereignVault == address(this)) _reserve1 += (amountInUsed - poolManagerFee);
if (poolManagerFee > 0) feePoolManager1 += poolManagerFee;
}
}
}
function _onlyALM() private view {
if (msg.sender != alm) {
revert SovereignPool__onlyALM();
}
}
function _onlyProtocolFactory() private view {
if (msg.sender != protocolFactory) {
revert SovereignPool__onlyProtocolFactory();
}
}
function _onlyPoolManager() private view {
if (msg.sender != poolManager) {
revert SovereignPool__onlyPoolManager();
}
}
function _onlyGauge() private view {
if (msg.sender != gauge) {
revert SovereignPool__onlyGauge();
}
}
function _getReservesForToken(bool isToken0) private view returns (uint256 reserve) {
if (isToken0) {
if (isToken0Rebase) {
reserve = _token0.balanceOf(address(this));
} else {
reserve = _reserve0;
}
} else {
if (isToken1Rebase) {
reserve = _token1.balanceOf(address(this));
} else {
reserve = _reserve1;
}
}
}
function _checkLiquidityQuote(
bool isZeroToOne,
uint256 amountInWithoutFee,
uint256 amountInFilled,
uint256 amountOut,
uint256 amountOutMin
) private view returns (bool) {
// We only compare against pool reserves if they are meant to be stored in it
if (sovereignVault == address(this)) {
if (amountOut > _getReservesForToken(!isZeroToOne)) {
return false;
}
}
if (amountOut < amountOutMin) {
return false;
}
if (amountInFilled > amountInWithoutFee) {
return false;
}
return true;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {IValantisPool} from "../interfaces/IValantisPool.sol";
import {PoolLocks} from "../structs/ReentrancyGuardStructs.sol";
import {SovereignPoolSwapContextData, SovereignPoolSwapParams} from "../structs/SovereignPoolStructs.sol";
interface ISovereignPool is IValantisPool {
event SwapFeeModuleSet(address swapFeeModule);
event ALMSet(address alm);
event GaugeSet(address gauge);
event PoolManagerSet(address poolManager);
event PoolManagerFeeSet(uint256 poolManagerFeeBips);
event SovereignOracleSet(address sovereignOracle);
event PoolManagerFeesClaimed(uint256 amount0, uint256 amount1);
event DepositLiquidity(uint256 amount0, uint256 amount1);
event WithdrawLiquidity(address indexed recipient, uint256 amount0, uint256 amount1);
event Swap(address indexed sender, bool isZeroToOne, uint256 amountIn, uint256 fee, uint256 amountOut);
function getTokens() external view returns (address[] memory tokens);
function sovereignVault() external view returns (address);
function protocolFactory() external view returns (address);
function gauge() external view returns (address);
function poolManager() external view returns (address);
function sovereignOracleModule() external view returns (address);
function swapFeeModule() external view returns (address);
function verifierModule() external view returns (address);
function isLocked() external view returns (bool);
function isRebaseTokenPool() external view returns (bool);
function poolManagerFeeBips() external view returns (uint256);
function defaultSwapFeeBips() external view returns (uint256);
function swapFeeModuleUpdateTimestamp() external view returns (uint256);
function alm() external view returns (address);
function getPoolManagerFees() external view returns (uint256 poolManagerFee0, uint256 poolManagerFee1);
function getReserves() external view returns (uint256 reserve0, uint256 reserve1);
function setPoolManager(address _manager) external;
function setGauge(address _gauge) external;
function setPoolManagerFeeBips(uint256 _poolManagerFeeBips) external;
function setSovereignOracle(address sovereignOracle) external;
function setSwapFeeModule(address _swapFeeModule) external;
function setALM(address _alm) external;
function swap(SovereignPoolSwapParams calldata _swapParams) external returns (uint256, uint256);
function depositLiquidity(
uint256 _amount0,
uint256 _amount1,
address _sender,
bytes calldata _verificationContext,
bytes calldata _depositData
) external returns (uint256 amount0Deposited, uint256 amount1Deposited);
function withdrawLiquidity(
uint256 _amount0,
uint256 _amount1,
address _sender,
address _recipient,
bytes calldata _verificationContext
) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
interface ISovereignPoolSwapCallback {
/**
* @notice Function called by Sovereign Pool during a swap, to transfer the funds.
* @dev This function is only called if isSwapCallback is set to true in swapParams.
* @param _tokenIn The address of the token that the user wants to swap.
* @param _amountInUsed The amount of the tokenIn used for the swap.
* @param _swapCallbackContext Arbitrary bytes data which can be sent to the swap callback.
*/
function sovereignPoolSwapCallback(address _tokenIn, uint256 _amountInUsed, bytes calldata _swapCallbackContext)
external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(IERC20 token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Compatible with tokens that require the approval to be set to
* 0 before setting it to a non-zero value.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
* Revert on invalid signature.
*/
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return
success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1, "Math: mulDiv overflow");
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {ALMLiquidityQuoteInput, ALMLiquidityQuote} from "../structs/SovereignALMStructs.sol";
/**
* @title Sovereign ALM interface
* @notice All ALMs bound to a Sovereign Pool must implement it.
*/
interface ISovereignALM {
/**
* @notice Called by the Sovereign pool to request a liquidity quote from the ALM.
* @param _almLiquidityQuoteInput Contains fundamental data about the swap.
* @param _externalContext Data received by the pool from the user.
* @param _verifierData Verification data received by the pool from the verifier module
* @return almLiquidityQuote Liquidity quote containing tokenIn and tokenOut amounts filled.
*/
function getLiquidityQuote(
ALMLiquidityQuoteInput memory _almLiquidityQuoteInput,
bytes calldata _externalContext,
bytes calldata _verifierData
) external returns (ALMLiquidityQuote memory);
/**
* @notice Callback function for `depositLiquidity` .
* @param _amount0 Amount of token0 being deposited.
* @param _amount1 Amount of token1 being deposited.
* @param _data Context data passed by the ALM, while calling `depositLiquidity`.
*/
function onDepositLiquidityCallback(uint256 _amount0, uint256 _amount1, bytes memory _data) external;
/**
* @notice Callback to ALM after swap into liquidity pool.
* @dev Only callable by pool.
* @param _isZeroToOne Direction of swap.
* @param _amountIn Amount of tokenIn in swap.
* @param _amountOut Amount of tokenOut in swap.
*/
function onSwapCallback(bool _isZeroToOne, uint256 _amountIn, uint256 _amountOut) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
struct ALMLiquidityQuoteInput {
bool isZeroToOne;
uint256 amountInMinusFee;
uint256 feeInBips;
address sender;
address recipient;
address tokenOutSwap;
}
struct ALMLiquidityQuote {
bool isCallbackOnSwap;
uint256 amountOut;
uint256 amountInFilled;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
interface ISovereignOracle {
/**
* @notice Returns the address of the pool associated with the oracle.
* @return pool The address of the pool.
*/
function pool() external view returns (address);
/**
* @notice Writes an update to the oracle after a swap in the Sovereign Pool.
* @param isZeroToOne True if the swap is from token0 to token1, false otherwise.
* @param amountInMinusFee The amount of the tokenIn used minus fees.
* @param fee The fee amount.
* @param amountOut The amount of the tokenOut transferred to the user.
*/
function writeOracleUpdate(bool isZeroToOne, uint256 amountInMinusFee, uint256 fee, uint256 amountOut) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
interface IFlashBorrower {
/**
* @dev Receive a flash loan.
* @param initiator The initiator of the loan.
* @param token The loan currency.
* @param amount The amount of tokens lent.
* @param data Arbitrary data structure, intended to contain user-defined parameters.
* @return The keccak256 hash of "ERC3156FlashBorrower.onFlashLoan"
*/
function onFlashLoan(address initiator, address token, uint256 amount, bytes calldata data)
external
returns (bytes32);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
/**
* @title Minimal interface for Sovereign Pool's custom vault.
* @dev Sovereign Pools can choose to store their token0 and token1
* reserves in this contract.
* Sovereign Vault allows LPs to define where funds should be stored
* on deposits, withdrawals and swaps. Examples:
* - A custom LP vault which can provide liquidity to multiple pools on request.
* - A singleton contract.
* - Any external protocol that provides liquidity to incoming swaps on request.
* Moreover, it supports any number of tokens.
* @dev This is meant to be a minimal interface, containing only the functions
* required for Sovereign Pools to interact with.
*/
interface ISovereignVaultMinimal {
/**
* @notice Returns array of tokens which can be swapped against for a given Sovereign Pool.
* @param _pool Sovereign Pool to query tokens for.
*/
function getTokensForPool(address _pool) external view returns (address[] memory);
/**
* @notice Returns reserve amounts available for a given Sovereign Pool.
* @param _pool Sovereign Pool to query token reserves for.
* @param _tokens Token addresses to query reserves for.
* @dev The full array of available tokens can be retrieved by calling `getTokensForPool` beforehand.
*/
function getReservesForPool(address _pool, address[] calldata _tokens) external view returns (uint256[] memory);
/**
* @notice Allows pool to attempt to claim due amount of `poolManager` fees.
* @dev Only callable by a Sovereign Pool.
* @dev This is required, since on every swap, input token amounts are transferred
* from user into `sovereignVault`, to save on gas. Hence manager fees
* can only be claimed via this separate call.
* @param _feePoolManager0 Amount of token0 due to `poolManager`.
* @param _feePoolManager1 Amount of token1 due to `poolManager`.
*/
function claimPoolManagerFees(uint256 _feePoolManager0, uint256 _feePoolManager1) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {IFlashBorrower} from "./IFlashBorrower.sol";
interface IValantisPool {
/**
*
* EVENTS
*
*/
event Flashloan(address indexed initiator, address indexed receiver, uint256 amount, address token);
/**
*
* ERRORS
*
*/
error ValantisPool__flashloan_callbackFailed();
error ValantisPool__flashLoan_flashLoanDisabled();
error ValantisPool__flashLoan_flashLoanNotRepaid();
error ValantisPool__flashLoan_rebaseTokenNotAllowed();
/**
*
* VIEW FUNCTIONS
*
*/
/**
* @notice Address of ERC20 token0 of the pool.
*/
function token0() external view returns (address);
/**
* @notice Address of ERC20 token1 of the pool.
*/
function token1() external view returns (address);
/**
*
* EXTERNAL FUNCTIONS
*
*/
/**
* @notice Claim share of protocol fees accrued by this pool.
* @dev Can only be claimed by `gauge` of the pool.
*/
function claimProtocolFees() external returns (uint256, uint256);
/**
* @notice Claim share of fees accrued by this pool
* And optionally share some with the protocol.
* @dev Only callable by `poolManager`.
* @param _feeProtocol0Bips Percent of `token0` fees to be shared with protocol.
* @param _feeProtocol1Bips Percent of `token1` fees to be shared with protocol.
*/
function claimPoolManagerFees(uint256 _feeProtocol0Bips, uint256 _feeProtocol1Bips)
external
returns (uint256 feePoolManager0Received, uint256 feePoolManager1Received);
/**
* @notice Sets the gauge contract address for the pool.
* @dev Only callable by `protocolFactory`.
* @dev Once a gauge is set it cannot be changed again.
* @param _gauge address of the gauge.
*/
function setGauge(address _gauge) external;
/**
* @notice Allows anyone to flash loan any amount of tokens from the pool.
* @param _isTokenZero True if token0 is being flash loaned, False otherwise.
* @param _receiver Address of the flash loan receiver.
* @param _amount Amount of tokens to be flash loaned.
* @param _data Bytes encoded data for flash loan callback.
*/
function flashLoan(bool _isTokenZero, IFlashBorrower _receiver, uint256 _amount, bytes calldata _data) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
interface IVerifierModule {
/**
* @notice Used to verify user access to important pool functions.
* @param _user The address of the user.
* @param _verificationContext Arbitrary bytes data which can be sent to the verifier module.
* @param accessType The type of function being called, can be - SWAP(0), DEPOSIT(1), or WITHDRAW(2).
* @return success True if the user is verified, false otherwise.
* @return returnData Additional data which can be passed along to the LM in case of a swap.
*/
function verify(address _user, bytes calldata _verificationContext, uint8 accessType)
external
returns (bool success, bytes memory returnData);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
enum Lock {
WITHDRAWAL,
DEPOSIT,
SWAP,
SPOT_PRICE_TICK
}
struct PoolLocks {
/**
* @notice Locks all functions that require any withdrawal of funds from the pool
* This involves the following functions -
* withdrawLiquidity
* claimProtocolFees
* claimPoolManagerFees
*/
uint8 withdrawals;
/**
* @notice Only locks the deposit function
*/
uint8 deposit;
/**
* @notice Only locks the swap function
*/
uint8 swap;
/**
* @notice Only locks the spotPriceTick function
*/
uint8 spotPriceTick;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {IERC20} from "../../../lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import {ISwapFeeModule} from "../../swap-fee-modules/interfaces/ISwapFeeModule.sol";
struct SovereignPoolConstructorArgs {
address token0;
address token1;
address protocolFactory;
address poolManager;
address sovereignVault;
address verifierModule;
bool isToken0Rebase;
bool isToken1Rebase;
uint256 token0AbsErrorTolerance;
uint256 token1AbsErrorTolerance;
uint256 defaultSwapFeeBips;
}
struct SovereignPoolSwapContextData {
bytes externalContext;
bytes verifierContext;
bytes swapCallbackContext;
bytes swapFeeModuleContext;
}
struct SwapCache {
ISwapFeeModule swapFeeModule;
IERC20 tokenInPool;
IERC20 tokenOutPool;
uint256 amountInWithoutFee;
}
struct SovereignPoolSwapParams {
bool isSwapCallback;
bool isZeroToOne;
uint256 amountIn;
uint256 amountOutMin;
uint256 deadline;
address recipient;
address swapTokenOut;
SovereignPoolSwapContextData swapContext;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
/**
* @notice Struct returned by the swapFeeModule during the getSwapFeeInBips call.
* feeInBips: The swap fee in bips.
* internalContext: Arbitrary bytes context data.
*/
struct SwapFeeModuleData {
uint256 feeInBips;
bytes internalContext;
}
interface ISwapFeeModuleMinimal {
/**
* @notice Returns the swap fee in bips for both Universal & Sovereign Pools.
* @param _tokenIn The address of the token that the user wants to swap.
* @param _tokenOut The address of the token that the user wants to receive.
* @param _amountIn The amount of tokenIn being swapped.
* @param _user The address of the user.
* @param _swapFeeModuleContext Arbitrary bytes data which can be sent to the swap fee module.
* @return swapFeeModuleData A struct containing the swap fee in bips, and internal context data.
*/
function getSwapFeeInBips(
address _tokenIn,
address _tokenOut,
uint256 _amountIn,
address _user,
bytes memory _swapFeeModuleContext
) external returns (SwapFeeModuleData memory swapFeeModuleData);
}
interface ISwapFeeModule is ISwapFeeModuleMinimal {
/**
* @notice Callback function called by the pool after the swap has finished. ( Universal Pools )
* @param _effectiveFee The effective fee charged for the swap.
* @param _spotPriceTick The spot price tick after the swap.
* @param _amountInUsed The amount of tokenIn used for the swap.
* @param _amountOut The amount of the tokenOut transferred to the user.
* @param _swapFeeModuleData The context data returned by getSwapFeeInBips.
*/
function callbackOnSwapEnd(
uint256 _effectiveFee,
int24 _spotPriceTick,
uint256 _amountInUsed,
uint256 _amountOut,
SwapFeeModuleData memory _swapFeeModuleData
) external;
/**
* @notice Callback function called by the pool after the swap has finished. ( Sovereign Pools )
* @param _effectiveFee The effective fee charged for the swap.
* @param _amountInUsed The amount of tokenIn used for the swap.
* @param _amountOut The amount of the tokenOut transferred to the user.
* @param _swapFeeModuleData The context data returned by getSwapFeeInBips.
*/
function callbackOnSwapEnd(
uint256 _effectiveFee,
uint256 _amountInUsed,
uint256 _amountOut,
SwapFeeModuleData memory _swapFeeModuleData
) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
library Constants {
uint256 public constant Q128 = 1 << 128;
uint256 public constant Q64 = 1 << 64;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
/**
* @notice Adapted from:
* https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.8.3/contracts/security/ReentrancyGuard.sol
* @dev Uses internal variables and functions
* so that child contracts can be explicit about view-function reentrancy risk.
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 internal constant _NOT_ENTERED = 1;
uint256 internal constant _ENTERED = 2;
uint256 internal _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() internal {
// On the first call to nonReentrant, _status will be _NOT_ENTERED
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function _nonReentrantAfter() internal {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
}{
"evmVersion": "paris",
"libraries": {},
"metadata": {
"appendCBOR": true,
"bytecodeHash": "ipfs",
"useLiteralContent": false
},
"optimizer": {
"enabled": true,
"runs": 10000
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"remappings": [
"forge-std/=lib/forge-std/src/",
"ds-test/=lib/forge-std/lib/ds-test/src/",
"erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"openzeppelin/=lib/openzeppelin-contracts/contracts/"
],
"viaIR": false
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"address","name":"protocolFactory","type":"address"},{"internalType":"address","name":"poolManager","type":"address"},{"internalType":"address","name":"sovereignVault","type":"address"},{"internalType":"address","name":"verifierModule","type":"address"},{"internalType":"bool","name":"isToken0Rebase","type":"bool"},{"internalType":"bool","name":"isToken1Rebase","type":"bool"},{"internalType":"uint256","name":"token0AbsErrorTolerance","type":"uint256"},{"internalType":"uint256","name":"token1AbsErrorTolerance","type":"uint256"},{"internalType":"uint256","name":"defaultSwapFeeBips","type":"uint256"}],"internalType":"struct SovereignPoolConstructorArgs","name":"args","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"SovereignPool__ALMAlreadySet","type":"error"},{"inputs":[],"name":"SovereignPool__ZeroAddress","type":"error"},{"inputs":[],"name":"SovereignPool___claimPoolManagerFees_invalidFeeReceived","type":"error"},{"inputs":[],"name":"SovereignPool___claimPoolManagerFees_invalidProtocolFee","type":"error"},{"inputs":[],"name":"SovereignPool___handleTokenInOnSwap_excessiveTokenInErrorOnTransfer","type":"error"},{"inputs":[],"name":"SovereignPool___handleTokenInOnSwap_invalidTokenInAmount","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint8","name":"accessType","type":"uint8"}],"name":"SovereignPool___verifyPermission_onlyPermissionedAccess","type":"error"},{"inputs":[],"name":"SovereignPool__depositLiquidity_depositDisabled","type":"error"},{"inputs":[],"name":"SovereignPool__depositLiquidity_excessiveToken0ErrorOnTransfer","type":"error"},{"inputs":[],"name":"SovereignPool__depositLiquidity_excessiveToken1ErrorOnTransfer","type":"error"},{"inputs":[],"name":"SovereignPool__depositLiquidity_incorrectTokenAmount","type":"error"},{"inputs":[],"name":"SovereignPool__depositLiquidity_insufficientToken0Amount","type":"error"},{"inputs":[],"name":"SovereignPool__depositLiquidity_insufficientToken1Amount","type":"error"},{"inputs":[],"name":"SovereignPool__depositLiquidity_zeroTotalDepositAmount","type":"error"},{"inputs":[],"name":"SovereignPool__excessiveToken0AbsErrorTolerance","type":"error"},{"inputs":[],"name":"SovereignPool__excessiveToken1AbsErrorTolerance","type":"error"},{"inputs":[],"name":"SovereignPool__getReserves_invalidReservesLength","type":"error"},{"inputs":[],"name":"SovereignPool__onlyALM","type":"error"},{"inputs":[],"name":"SovereignPool__onlyGauge","type":"error"},{"inputs":[],"name":"SovereignPool__onlyPoolManager","type":"error"},{"inputs":[],"name":"SovereignPool__onlyProtocolFactory","type":"error"},{"inputs":[],"name":"SovereignPool__sameTokenNotAllowed","type":"error"},{"inputs":[],"name":"SovereignPool__setGauge_gaugeAlreadySet","type":"error"},{"inputs":[],"name":"SovereignPool__setGauge_invalidAddress","type":"error"},{"inputs":[],"name":"SovereignPool__setPoolManagerFeeBips_excessivePoolManagerFee","type":"error"},{"inputs":[],"name":"SovereignPool__setSovereignOracle_oracleDisabled","type":"error"},{"inputs":[],"name":"SovereignPool__setSovereignOracle_sovereignOracleAlreadySet","type":"error"},{"inputs":[],"name":"SovereignPool__setSwapFeeModule_timelock","type":"error"},{"inputs":[],"name":"SovereignPool__swap_excessiveSwapFee","type":"error"},{"inputs":[],"name":"SovereignPool__swap_expired","type":"error"},{"inputs":[],"name":"SovereignPool__swap_insufficientAmountIn","type":"error"},{"inputs":[],"name":"SovereignPool__swap_invalidLiquidityQuote","type":"error"},{"inputs":[],"name":"SovereignPool__swap_invalidPoolTokenOut","type":"error"},{"inputs":[],"name":"SovereignPool__swap_invalidRecipient","type":"error"},{"inputs":[],"name":"SovereignPool__swap_invalidSwapTokenOut","type":"error"},{"inputs":[],"name":"SovereignPool__swap_zeroAmountInOrOut","type":"error"},{"inputs":[],"name":"SovereignPool__withdrawLiquidity_insufficientReserve0","type":"error"},{"inputs":[],"name":"SovereignPool__withdrawLiquidity_insufficientReserve1","type":"error"},{"inputs":[],"name":"SovereignPool__withdrawLiquidity_invalidRecipient","type":"error"},{"inputs":[],"name":"SovereignPool__withdrawLiquidity_withdrawDisabled","type":"error"},{"inputs":[],"name":"ValantisPool__flashLoan_flashLoanDisabled","type":"error"},{"inputs":[],"name":"ValantisPool__flashLoan_flashLoanNotRepaid","type":"error"},{"inputs":[],"name":"ValantisPool__flashLoan_rebaseTokenNotAllowed","type":"error"},{"inputs":[],"name":"ValantisPool__flashloan_callbackFailed","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"alm","type":"address"}],"name":"ALMSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1","type":"uint256"}],"name":"DepositLiquidity","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"initiator","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"token","type":"address"}],"name":"Flashloan","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"gauge","type":"address"}],"name":"GaugeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"poolManagerFeeBips","type":"uint256"}],"name":"PoolManagerFeeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1","type":"uint256"}],"name":"PoolManagerFeesClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"poolManager","type":"address"}],"name":"PoolManagerSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sovereignOracle","type":"address"}],"name":"SovereignOracleSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bool","name":"isZeroToOne","type":"bool"},{"indexed":false,"internalType":"uint256","name":"amountIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOut","type":"uint256"}],"name":"Swap","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"swapFeeModule","type":"address"}],"name":"SwapFeeModuleSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1","type":"uint256"}],"name":"WithdrawLiquidity","type":"event"},{"inputs":[],"name":"alm","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_feeProtocol0Bips","type":"uint256"},{"internalType":"uint256","name":"_feeProtocol1Bips","type":"uint256"}],"name":"claimPoolManagerFees","outputs":[{"internalType":"uint256","name":"feePoolManager0Received","type":"uint256"},{"internalType":"uint256","name":"feePoolManager1Received","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimProtocolFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"defaultSwapFeeBips","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount0","type":"uint256"},{"internalType":"uint256","name":"_amount1","type":"uint256"},{"internalType":"address","name":"_sender","type":"address"},{"internalType":"bytes","name":"_verificationContext","type":"bytes"},{"internalType":"bytes","name":"_depositData","type":"bytes"}],"name":"depositLiquidity","outputs":[{"internalType":"uint256","name":"amount0Deposited","type":"uint256"},{"internalType":"uint256","name":"amount1Deposited","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"feePoolManager0","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feePoolManager1","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeProtocol0","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeProtocol1","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_isTokenZero","type":"bool"},{"internalType":"contract IFlashBorrower","name":"_receiver","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"flashLoan","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"gauge","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPoolManagerFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getReserves","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTokens","outputs":[{"internalType":"address[]","name":"tokens","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isLocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isRebaseTokenPool","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isToken0Rebase","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isToken1Rebase","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolManagerFeeBips","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFactory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_alm","type":"address"}],"name":"setALM","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_gauge","type":"address"}],"name":"setGauge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_manager","type":"address"}],"name":"setPoolManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_poolManagerFeeBips","type":"uint256"}],"name":"setPoolManagerFeeBips","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sovereignOracle","type":"address"}],"name":"setSovereignOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"swapFeeModule_","type":"address"}],"name":"setSwapFeeModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sovereignOracleModule","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sovereignVault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bool","name":"isSwapCallback","type":"bool"},{"internalType":"bool","name":"isZeroToOne","type":"bool"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"address","name":"swapTokenOut","type":"address"},{"components":[{"internalType":"bytes","name":"externalContext","type":"bytes"},{"internalType":"bytes","name":"verifierContext","type":"bytes"},{"internalType":"bytes","name":"swapCallbackContext","type":"bytes"},{"internalType":"bytes","name":"swapFeeModuleContext","type":"bytes"}],"internalType":"struct SovereignPoolSwapContextData","name":"swapContext","type":"tuple"}],"internalType":"struct SovereignPoolSwapParams","name":"_swapParams","type":"tuple"}],"name":"swap","outputs":[{"internalType":"uint256","name":"amountInUsed","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"swapFeeModule","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"swapFeeModuleUpdateTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token0","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token0AbsErrorTolerance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token1","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token1AbsErrorTolerance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"verifierModule","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount0","type":"uint256"},{"internalType":"uint256","name":"_amount1","type":"uint256"},{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"bytes","name":"_verificationContext","type":"bytes"}],"name":"withdrawLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
6101c06040523480156200001257600080fd5b5060405162004c3138038062004c3183398101604081905262000035916200022f565b6001600055602081015181516001600160a01b039182169116036200006d57604051633666f5ad60e11b815260040160405180910390fd5b80516001600160a01b0316158062000090575060208101516001600160a01b0316155b15620000af576040516383c6c53360e01b815260040160405180910390fd5b60808101516001600160a01b031615620000ce578060800151620000d0565b305b6001600160a01b0390811660805260a082810151821660e0908152835183166101009081526020850151841661012052604085015184169092526060840151600380546001600160a01b031916919094161790925560c083015115156101405290820151151561016052810151600a10156200015f57604051630f33766d60e21b815260040160405180910390fd5b600a8161012001511115620001875760405163483569e560e11b815260040160405180910390fd5b610100810151610180526101208101516101a0526101408101516127101015620001b457612710620001bb565b8061014001515b60c052504260095562000309565b60405161016081016001600160401b0381118282101715620001fb57634e487b7160e01b600052604160045260246000fd5b60405290565b80516001600160a01b03811681146200021957600080fd5b919050565b805180151581146200021957600080fd5b600061016082840312156200024357600080fd5b6200024d620001c9565b620002588362000201565b8152620002686020840162000201565b60208201526200027b6040840162000201565b60408201526200028e6060840162000201565b6060820152620002a16080840162000201565b6080820152620002b460a0840162000201565b60a0820152620002c760c084016200021e565b60c0820152620002da60e084016200021e565b60e082015261010083810151908201526101208084015190820152610140928301519281019290925250919050565b60805160a05160c05160e05161010051610120516101405161016051610180516101a0516146a66200058b60003960008181610346015281816117a00152612e8f01526000818161039a015281816116620152612eb50152600081816104740152818161175601528181611cfc01528181612193015281816125b20152818161284001528181612e14015281816130c6015261317e01526000818161030f0152818161161801528181611ccd015281816121b90152818161258b0152818161278301528181612e3a01528181612fea015261313e0152600081816105a6015281816106d301528181610952015281816109e501528181611401015281816115990152818161194d01528181611d76015281816121420152818161267f01528181612879015281816135b20152818161377601526138fa0152600081816102d20152818161067f01528181610978015281816109bf0152818161136b015281816114f90152818161190e01528181611d3c015281816121680152818161262b015281816127bc0152818161351c015281816136dc01526138c00152600081816103be01528181610b350152818161131701528181611c0901526129360152600081816105820152610cac0152600081816105e201526133e601526000818161055b015281816106130152818161074601528181610a9f0152818161127901528181611ba701528181611fc6015281816120d9015281816125dc0152818161270201528181612b5a01528181612c4301528181612d4b01528181612d8701528181612f5b01528181613023015281816130930152818161310b015281816131b70152818161322d01528181613282015281816134df015261365601526146a66000f3fe608060405234801561001057600080fd5b50600436106102925760003560e01c80638a7dbaa211610160578063a8f0aa42116100d8578063c22c20841161008c578063dc4c90d311610071578063dc4c90d3146105ca578063f489048a146105dd578063fa9f1cf41461060457600080fd5b8063c22c20841461057d578063d21220a7146105a457600080fd5b8063b0de1fe2116100bd578063b0de1fe21461053a578063b8f6eb8a14610543578063baad44eb1461055657600080fd5b8063a8f0aa421461051c578063aa6ca8081461052557600080fd5b80639e25bc7d1161012f578063a040d22311610114578063a040d223146104f5578063a4e2d634146104fe578063a6f19c841461050957600080fd5b80639e25bc7d146104da5780639f3a3a67146104ed57600080fd5b80638a7dbaa2146104965780638d6d9599146104a95780638fa03de7146104bc57806395c4d51e146104cf57600080fd5b806341506fc11161020e578063712290c0116101c2578063780ef175116101a7578063780ef175146104495780637aef67151461045c5780637b4f8c651461046f57600080fd5b8063712290c01461042557806373f4ea121461043857600080fd5b80634a7d0369116101f35780634a7d0369146103f557806355a68ed3146103fd57806361b9c3ec1461041257600080fd5b806341506fc1146103bc57806341a41e9e146103e257600080fd5b80631d163adf116102655780632ddf0fa11161024a5780632ddf0fa114610379578063373290091461038257806339ba11f61461039557600080fd5b80631d163adf1461034157806323c43a511461036857600080fd5b806302a1b32c146102975780630902f1ac146102b35780630dfe1681146102d05780631645118b1461030a575b600080fd5b6102a060085481565b6040519081526020015b60405180910390f35b6102bb61060d565b604080519283526020830191909152016102aa565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016102aa565b6103317f000000000000000000000000000000000000000000000000000000000000000081565b60405190151581526020016102aa565b6102a07f000000000000000000000000000000000000000000000000000000000000000081565b600d546001600160a01b03166102f2565b6102a060045481565b6102bb610390366004613c0e565b610843565b6102a07f000000000000000000000000000000000000000000000000000000000000000081565b7f00000000000000000000000000000000000000000000000000000000000000006102f2565b6102bb6103f0366004613ca1565b611264565b6102bb6118dd565b61041061040b366004613d37565b611983565b005b610410610420366004613d37565b611a8d565b610410610433366004613d54565b611b55565b600c546001600160a01b03166102f2565b6102bb610457366004613dd0565b611df3565b61041061046a366004613d37565b611e27565b6103317f000000000000000000000000000000000000000000000000000000000000000081565b6104106104a4366004613df2565b611ef3565b6104106104b7366004613d37565b611f74565b6104106104ca366004613e19565b6120cf565b6005546006546102bb565b6104106104e8366004613d37565b61248e565b610331612587565b6102a060095481565b600054600214610331565b6002546102f2906001600160a01b031681565b6102a060065481565b61052d6125d7565b6040516102aa9190613ed0565b6102a060075481565b6001546102f2906001600160a01b031681565b6102f27f000000000000000000000000000000000000000000000000000000000000000081565b6102a07f000000000000000000000000000000000000000000000000000000000000000081565b7f00000000000000000000000000000000000000000000000000000000000000006102f2565b6003546102f2906001600160a01b031681565b6102f27f000000000000000000000000000000000000000000000000000000000000000081565b6102a060055481565b600080307f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03160361065c5761064a6001612779565b6106546000612779565b915091509091565b6040805160028082526060820183526000926020830190803683370190505090507f0000000000000000000000000000000000000000000000000000000000000000816000815181106106b1576106b1613f12565b60200260200101906001600160a01b031690816001600160a01b0316815250507f00000000000000000000000000000000000000000000000000000000000000008160018151811061070557610705613f12565b6001600160a01b0392831660209182029290920101526040517f9ffdefad0000000000000000000000000000000000000000000000000000000081526000917f00000000000000000000000000000000000000000000000000000000000000001690639ffdefad9061077d9030908690600401613f41565b600060405180830381865afa15801561079a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526107c29190810190613fb8565b905080516002146107ff576040517f77452a8200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060008151811061081257610812613f12565b60200260200101518160018151811061082d5761082d613f12565b60200260200101519350935050509091565b9091565b60008061084e6128b8565b826080013542111561088c576040517f4c78bac800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82604001356000036108ca576040517fccc5071100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006108dc60c0850160a08601613d37565b6001600160a01b03160361091c576040517f24fb866e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051608081018252600d546001600160a01b0316815260009160208083019161094c91908801908801614043565b610976577f0000000000000000000000000000000000000000000000000000000000000000610998565b7f00000000000000000000000000000000000000000000000000000000000000005b6001600160a01b031681526020018560200160208101906109b99190614043565b6109e3577f0000000000000000000000000000000000000000000000000000000000000000610a05565b7f00000000000000000000000000000000000000000000000000000000000000005b6001600160a01b0316815260006020909101819052909150610a2d60e0860160c08701613d37565b6001600160a01b03161480610a66575060208101516001600160a01b0316610a5b60e0860160c08701613d37565b6001600160a01b0316145b15610a9d576040517f5746343e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031630148015610afa575060408101516001600160a01b0316610aee60e0860160c08701613d37565b6001600160a01b031614155b15610b31576040517f6a3d76f400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60607f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031615610b8b57610b8833610b7360e0880188614060565b610b8190602081019061409e565b6000612930565b90505b60408051808201909152600081526060602082015282516001600160a01b031615610ca05782600001516001600160a01b0316634c7b5106846020015185604001518960400135338b8060e00190610be39190614060565b610bf190606081019061409e565b6040518763ffffffff1660e01b8152600401610c129695949392919061415d565b6000604051808303816000875af1158015610c31573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610c59919081019061422c565b905061271081600001511115610c9b576040517f3e79e9d600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610ce3565b506040805180820182527f000000000000000000000000000000000000000000000000000000000000000081528151600081526020808201909352918101919091525b610d0586604001356127108360000151612710610d0091906142e8565b612a25565b60608401526001546040805160c0810182526000926001600160a01b03169163ede5e58491908190610d3c908c0160208d01614043565b151581526060808901516020830152865160408301523390820152608001610d6a60c08c0160a08d01613d37565b6001600160a01b03168152602001610d8860e08c0160c08d01613d37565b6001600160a01b03169052610da060e08b018b614060565b610daa908061409e565b876040518563ffffffff1660e01b8152600401610dca9493929190614327565b6060604051808303816000875af1158015610de9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e0d919061439c565b905080602001519450610e41876020016020810190610e2c9190614043565b85606001518360400151888b60600135612b55565b610e77576040517f457868f600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b841580610e8657506040810151155b15610ebd576040517f55d450f000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008460600151826040015114610efe57610ee5826040015184600001516127106001612bcd565b9050808260400151610ef791906142e8565b9650610f1b565b6060850151610f119060408a01356143fe565b9050876040013596505b610f62610f2e60408a0160208b01614043565b610f3b60208b018b614043565b60208801518a85610f4f60e08f018f614060565b610f5d90604081019061409e565b612c2c565b610f7d610f7560408a0160208b01614043565b888884612fe2565b600c546001600160a01b031615801590610fbb575060408501516001600160a01b0316610fb060e08a0160c08b01613d37565b6001600160a01b0316145b8015610fc75750600087115b1561106c57600c546001600160a01b031663819c3f42610fed60408b0160208c01614043565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681529015156004820152602481018a90526044810184905260648101899052608401600060405180830381600087803b15801561105357600080fd5b505af1158015611067573d6000803e3d6000fd5b505050505b61109561107f60e08a0160c08b01613d37565b61108f60c08b0160a08c01613d37565b8861322a565b84516001600160a01b0316158015906110d157506040805160008082526020820190925290508051906020012083602001518051906020012014155b156111575784516040517f280f19cf0000000000000000000000000000000000000000000000000000000081526001600160a01b039091169063280f19cf906111249084908b908b908990600401614411565b600060405180830381600087803b15801561113e57600080fd5b505af1158015611152573d6000803e3d6000fd5b505050505b8151156111f7576001546001600160a01b031663a3f3d72261117f60408b0160208c01614043565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681529015156004820152602481018a905260448101899052606401600060405180830381600087803b1580156111de57600080fd5b505af11580156111f2573d6000803e3d6000fd5b505050505b337f176648f1f11cda284c124490086be42a926ddf0ae887ebe7b1d6b337d894275661122960408b0160208c01614043565b604080519115158252602082018b905281018490526060810189905260800160405180910390a2505050505061125f6001600055565b915091565b60008061126f6132a8565b6112776128b8565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031630146112d9576040517f3e009a4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b878917600003611315576040517ffbfc52fd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031615611353576113518787876001612930565b505b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156113ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113de9190614449565b6040516370a0823160e01b81523060048201529091506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015611448573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061146c9190614449565b6040517f2d4b23bd0000000000000000000000000000000000000000000000000000000081529091503390632d4b23bd906114b1908e908e908b908b90600401614462565b600060405180830381600087803b1580156114cb57600080fd5b505af11580156114df573d6000803e3d6000fd5b50506040516370a0823160e01b81523060048201528492507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031691506370a0823190602401602060405180830381865afa158015611549573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061156d9190614449565b61157791906143fe565b6040516370a0823160e01b815230600482015290945081906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa1580156115e0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116049190614449565b61160e91906143fe565b92508a15611716577f0000000000000000000000000000000000000000000000000000000000000000156116c05760008b85106116545761164f8c866143fe565b61165e565b61165e858d6143fe565b90507f00000000000000000000000000000000000000000000000000000000000000008111156116ba576040517fc794db5300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5061174e565b8a84146116f9576040517f245c1efb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83600a600082825461170b91906142e8565b9091555061174e9050565b831561174e576040517f57330e8900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8915611854577f0000000000000000000000000000000000000000000000000000000000000000156117fe5760008a84106117925761178d8b856143fe565b61179c565b61179c848c6143fe565b90507f00000000000000000000000000000000000000000000000000000000000000008111156117f8576040517fbdd9a55300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5061188c565b898314611837576040517ffb702a7900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82600b600082825461184991906142e8565b9091555061188c9050565b821561188c576040517f57330e8900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051858152602081018590527f5b479c5a76f3eddfff87849b354aee2a3fbdafd3c2c1a95561143bd2ec1f1e64910160405180910390a150506118d16001600055565b97509795505050505050565b6000806118e86128b8565b6118f06132ee565b60075460085481156119355760006007556119356001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163384613332565b80156119745760006008556119746001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163383613332565b909250905061083f6001600055565b61198b6133db565b6119936128b8565b6002546001600160a01b0316156119d6576040517f4937cf5100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038116611a16576040517f68dbb6bb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040519081527fb947d28129d3b40272a411eeee3a2842c6335a0f0269abf492e8c20218bf02b0906020015b60405180910390a1611a8a6001600055565b50565b611a9561343d565b611a9d6128b8565b600954421015611ad9576040517f39000a0500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038316179055611b19426203f4806142e8565b6009556040516001600160a01b03821681527fe0d3edb906e9f17a6c8342bada5bdd7051f42bbed87eec9af9e69cd75ad98bd290602001611a78565b611b5d6128b8565b611b656132a8565b6001600160a01b038316611ba5576040517f8cfd9a7700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163014611c07576040517fb0bb65d700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031615611c4557611c438483836002612930565b505b611c4f6001612779565b861115611c88576040517f4d8313ce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611c926000612779565b851115611ccb576040517f8738d6cc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f0000000000000000000000000000000000000000000000000000000000000000611cfa57600a805487900390555b7f0000000000000000000000000000000000000000000000000000000000000000611d2957600b805486900390555b8515611d6357611d636001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168488613332565b8415611d9d57611d9d6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168487613332565b60408051878152602081018790526001600160a01b038516917fac927268ea9ae2e55027e6ab727fc2db8e3ea48c56c658223a1074567e4298c0910160405180910390a2611deb6001600055565b505050505050565b600080611dfe6128b8565b611e0661343d565b611e11848433613481565b9092509050611e206001600055565b9250929050565b611e2f61343d565b611e376128b8565b600380547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038316908117909155611eba5760006004819055611e83908033613481565b5050604051600081527f67c138aed690b53f8472c70911848132b03f2e8c321a03e5db379ad5e08502059060200160405180910390a15b6040516001600160a01b03821681527f181b126158932b45e642aeb48f81b946563bf584a35e78d6a25b013c8d41ff8f90602001611a78565b611efb61343d565b611f036128b8565b611388811115611f3f576040517f39f0f92c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60048190556040518181527f67c138aed690b53f8472c70911848132b03f2e8c321a03e5db379ad5e085020590602001611a78565b611f7c61343d565b611f846128b8565b6001600160a01b038116611fc4576040517f83c6c53300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163014612026576040517fe9c9ef7800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c546001600160a01b031615612069576040517f5d906c2900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040519081527f307a86fd6204dd9b6a270c57d048c5f259625d260f8c03d1915a9fe6bc2708f090602001611a78565b6120d76128b8565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163014612139576040517fabf0792900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600085612166577f0000000000000000000000000000000000000000000000000000000000000000612188565b7f00000000000000000000000000000000000000000000000000000000000000005b90506000866121b7577f00000000000000000000000000000000000000000000000000000000000000006121d9565b7f00000000000000000000000000000000000000000000000000000000000000005b90508015612213576040517f785aa4db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516370a0823160e01b81523060048201526000906001600160a01b038416906370a0823190602401602060405180830381865afa15801561225a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061227e9190614449565b90506122946001600160a01b0384168888613332565b6040517fc00c8b6c0000000000000000000000000000000000000000000000000000000081527f439148f0bbc682ca079e46d6e2c2f0c1e3b820f1a291b069d8882abf8cf18dd9906001600160a01b0389169063c00c8b6c9061230390339088908c908c908c9060040161448c565b6020604051808303816000875af1158015612322573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123469190614449565b1461237d576040517ff1b70e9a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6123926001600160a01b038416883089613964565b6040516370a0823160e01b815230600482015281906001600160a01b038516906370a0823190602401602060405180830381865afa1580156123d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123fc9190614449565b14612433576040517ff633e4db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080518781526001600160a01b03858116602083015289169133917fe875cf27c62067457025fb9b52111f2679e19907e5a1dcf2d8092afcd67cdc3a910160405180910390a35050506124876001600055565b5050505050565b61249661343d565b61249e6128b8565b6001600160a01b0381166124de576040517f83c6c53300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001546001600160a01b031615612521576040517f58c30fc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040519081527f1d56850f49455a17df2bb41dd638797cdd462d3b4034b169d7979c2df141355490602001611a78565b60007f0000000000000000000000000000000000000000000000000000000000000000806125d257507f00000000000000000000000000000000000000000000000000000000000000005b905090565b6060307f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316036126d45760408051600280825260608201835290916020830190803683370190505090507f00000000000000000000000000000000000000000000000000000000000000008160008151811061265d5761265d613f12565b60200260200101906001600160a01b031690816001600160a01b0316815250507f0000000000000000000000000000000000000000000000000000000000000000816001815181106126b1576126b1613f12565b60200260200101906001600160a01b031690816001600160a01b03168152505090565b6040517f0b6f5afe0000000000000000000000000000000000000000000000000000000081523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690630b6f5afe90602401600060405180830381865afa158015612751573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526125d291908101906144bf565b6000811561283e577f000000000000000000000000000000000000000000000000000000000000000015612836576040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a08231906024015b602060405180830381865afa15801561280c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128309190614449565b92915050565b5050600a5490565b7f0000000000000000000000000000000000000000000000000000000000000000156128b0576040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a08231906024016127ef565b5050600b5490565b600260005403612929576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b6002600055565b606060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663c0aa3cf8878787876040518563ffffffff1660e01b8152600401612986949392919061454e565b6000604051808303816000875af11580156129a5573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526129cd9190810190614585565b9250905080612a1c576040517f3f16fa200000000000000000000000000000000000000000000000000000000081526001600160a01b038716600482015260ff84166024820152604401612920565b50949350505050565b600080807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85870985870292508281108382030391505080600003612a7d57838281612a7357612a736145d6565b0492505050612b4e565b808411612ae6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4d6174683a206d756c446976206f766572666c6f7700000000000000000000006044820152606401612920565b600084868809851960019081018716968790049682860381900495909211909303600082900391909104909201919091029190911760038402600290811880860282030280860282030280860282030280860282030280860282030280860290910302029150505b9392505050565b6000307f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031603612ba057612b918615612779565b831115612ba057506000612bc4565b81831015612bb057506000612bc4565b84841115612bc057506000612bc4565b5060015b95945050505050565b600080612bdb868686612a25565b90506001836002811115612bf157612bf1614103565b148015612c0e575060008480612c0957612c096145d6565b868809115b15612c2157612c1e6001826142e8565b90505b90505b949350505050565b6040516370a0823160e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152600091908716906370a0823190602401602060405180830381865afa158015612c96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cba9190614449565b90508615612d3b576040517f9fbd86ad0000000000000000000000000000000000000000000000000000000081523390639fbd86ad90612d04908990899088908890600401614605565b600060405180830381600087803b158015612d1e57600080fd5b505af1158015612d32573d6000803e3d6000fd5b50505050612d70565b612d706001600160a01b038716337f000000000000000000000000000000000000000000000000000000000000000088613964565b6040516370a0823160e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015260009183918916906370a0823190602401602060405180830381865afa158015612ddb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dff9190614449565b612e0991906143fe565b9050600089612e38577f0000000000000000000000000000000000000000000000000000000000000000612e5a565b7f00000000000000000000000000000000000000000000000000000000000000005b90508015612f18576000828811612e7a57612e7588846143fe565b612e84565b612e8483896143fe565b905060008b612eb3577f0000000000000000000000000000000000000000000000000000000000000000612ed5565b7f00000000000000000000000000000000000000000000000000000000000000005b905080821115612f11576040517f07ba54e500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050612f51565b868214612f51576040517f45df38c100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b808015612f8657507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031630145b8015612f9c57506003546001600160a01b031615155b15612fd6576000612fb287600454612710612a25565b90508015612fd457600354612fd4906001600160a01b038b8116911683613332565b505b50505050505050505050565b8315613109577f000000000000000000000000000000000000000000000000000000000000000061309157600061301e82600454612710612a25565b9050307f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316036130715761305a81856143fe565b600a600082825461306b91906142e8565b90915550505b801561308f57806005600082825461308991906142e8565b90915550505b505b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316301480156130e757507f0000000000000000000000000000000000000000000000000000000000000000155b156131045781600b60008282546130fe91906143fe565b90915550505b613224565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163014801561315f57507f0000000000000000000000000000000000000000000000000000000000000000155b1561317c5781600a600082825461317691906143fe565b90915550505b7f00000000000000000000000000000000000000000000000000000000000000006132245760006131b282600454612710612a25565b9050307f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031603613205576131ee81856143fe565b600b60008282546131ff91906142e8565b90915550505b801561248757806006600082825461321d91906142e8565b9091555050505b50505050565b307f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316036132735761326e6001600160a01b0384168383613332565b505050565b61326e6001600160a01b0384167f00000000000000000000000000000000000000000000000000000000000000008484613964565b6001546001600160a01b031633146132ec576040517fef410f2f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b6002546001600160a01b031633146132ec576040517f6dfbb74500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b03831660248201526044810182905261326e9084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091526139b5565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146132ec576040517fcadb26b700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6003546001600160a01b031633146132ec576040517f6c54e96000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080612710851180613495575061271084115b156134cc576040517f50d83c0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050600554600654306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614613839576040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561356b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061358f9190614449565b6040516370a0823160e01b81523060048201529091506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa1580156135f9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061361d9190614449565b6040517f780ef17500000000000000000000000000000000000000000000000000000000815260048101869052602481018590529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063780ef17590604401600060405180830381600087803b1580156136a257600080fd5b505af11580156136b6573d6000803e3d6000fd5b50506040516370a0823160e01b8152306004820152600092508491506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015613723573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137479190614449565b61375191906143fe565b6040516370a0823160e01b815230600482015290915060009083906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa1580156137bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137e19190614449565b6137eb91906143fe565b9050858211806137fa57508481115b15613831576040517fcae2d53800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b909450925050505b60006138488684612710612a25565b905060006138598684612710612a25565b9050816007600082825461386d91906142e8565b92505081905550806008600082825461388691906142e8565b90915550506000600581905560065561389f82856143fe565b93506138ab81846143fe565b925083156138e7576138e76001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168686613332565b8215613921576139216001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168685613332565b60408051858152602081018590527f9354b101c687c179e9516ece0f8b0cebbfdc205da033d49eb2b9598548ed75c2910160405180910390a15050935093915050565b6040516001600160a01b03808516602483015283166044820152606481018290526132249085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401613377565b6000613a0a826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613ab79092919063ffffffff16565b9050805160001480613a2b575080806020019051810190613a2b919061462e565b61326e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401612920565b6060612c24848460008585600080866001600160a01b03168587604051613ade919061464b565b60006040518083038185875af1925050503d8060008114613b1b576040519150601f19603f3d011682016040523d82523d6000602084013e613b20565b606091505b5091509150613b3187838387613b3c565b979650505050505050565b60608315613bc5578251600003613bbe576001600160a01b0385163b613bbe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401612920565b5081612c24565b612c248383815115613bda5781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612920919061465d565b600060208284031215613c2057600080fd5b813567ffffffffffffffff811115613c3757600080fd5b82016101008185031215612b4e57600080fd5b6001600160a01b0381168114611a8a57600080fd5b60008083601f840112613c7157600080fd5b50813567ffffffffffffffff811115613c8957600080fd5b602083019150836020828501011115611e2057600080fd5b600080600080600080600060a0888a031215613cbc57600080fd5b87359650602088013595506040880135613cd581613c4a565b9450606088013567ffffffffffffffff80821115613cf257600080fd5b613cfe8b838c01613c5f565b909650945060808a0135915080821115613d1757600080fd5b50613d248a828b01613c5f565b989b979a50959850939692959293505050565b600060208284031215613d4957600080fd5b8135612b4e81613c4a565b60008060008060008060a08789031215613d6d57600080fd5b86359550602087013594506040870135613d8681613c4a565b93506060870135613d9681613c4a565b9250608087013567ffffffffffffffff811115613db257600080fd5b613dbe89828a01613c5f565b979a9699509497509295939492505050565b60008060408385031215613de357600080fd5b50508035926020909101359150565b600060208284031215613e0457600080fd5b5035919050565b8015158114611a8a57600080fd5b600080600080600060808688031215613e3157600080fd5b8535613e3c81613e0b565b94506020860135613e4c81613c4a565b935060408601359250606086013567ffffffffffffffff811115613e6f57600080fd5b613e7b88828901613c5f565b969995985093965092949392505050565b600081518084526020808501945080840160005b83811015613ec55781516001600160a01b031687529582019590820190600101613ea0565b509495945050505050565b602081526000612b4e6020830184613e8c565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6001600160a01b0383168152604060208201526000612c246040830184613e8c565b604051601f8201601f1916810167ffffffffffffffff81118282101715613f8c57613f8c613ee3565b604052919050565b600067ffffffffffffffff821115613fae57613fae613ee3565b5060051b60200190565b60006020808385031215613fcb57600080fd5b825167ffffffffffffffff811115613fe257600080fd5b8301601f81018513613ff357600080fd5b805161400661400182613f94565b613f63565b81815260059190911b8201830190838101908783111561402557600080fd5b928401925b82841015613b315783518252928401929084019061402a565b60006020828403121561405557600080fd5b8135612b4e81613e0b565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8183360301811261409457600080fd5b9190910192915050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126140d357600080fd5b83018035915067ffffffffffffffff8211156140ee57600080fd5b602001915036819003821315611e2057600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b818352818160208501375060006020828401015260006020601f19601f840116840101905092915050565b60006001600160a01b038089168352808816602084015286604084015280861660608401525060a0608083015261419860a083018486614132565b98975050505050505050565b60005b838110156141bf5781810151838201526020016141a7565b50506000910152565b600082601f8301126141d957600080fd5b815167ffffffffffffffff8111156141f3576141f3613ee3565b6142066020601f19601f84011601613f63565b81815284602083860101111561421b57600080fd5b612c248260208301602087016141a4565b60006020828403121561423e57600080fd5b815167ffffffffffffffff8082111561425657600080fd5b908301906040828603121561426a57600080fd5b60405160408101818110838211171561428557614285613ee3565b6040528251815260208301518281111561429e57600080fd5b6142aa878286016141c8565b60208301525095945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115612830576128306142b9565b600081518084526143138160208601602086016141a4565b601f01601f19169290920160200192915050565b6000610100865115158352602087015160208401526040870151604084015260608701516001600160a01b0380821660608601528060808a01511660808601528060a08a01511660a086015250508060c08401526143888184018688614132565b905082810360e0840152613b3181856142fb565b6000606082840312156143ae57600080fd5b6040516060810181811067ffffffffffffffff821117156143d1576143d1613ee3565b60405282516143df81613e0b565b8152602083810151908201526040928301519281019290925250919050565b81810381811115612830576128306142b9565b848152836020820152826040820152608060608201528151608082015260006020830151604060a0840152613b3160c08401826142fb565b60006020828403121561445b57600080fd5b5051919050565b848152836020820152606060408201526000614482606083018486614132565b9695505050505050565b60006001600160a01b03808816835280871660208401525084604083015260806060830152613b31608083018486614132565b600060208083850312156144d257600080fd5b825167ffffffffffffffff8111156144e957600080fd5b8301601f810185136144fa57600080fd5b805161450861400182613f94565b81815260059190911b8201830190838101908783111561452757600080fd5b928401925b82841015613b3157835161453f81613c4a565b8252928401929084019061452c565b6001600160a01b0385168152606060208201526000614571606083018587614132565b905060ff8316604083015295945050505050565b6000806040838503121561459857600080fd5b82516145a381613e0b565b602084015190925067ffffffffffffffff8111156145c057600080fd5b6145cc858286016141c8565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6001600160a01b0385168152836020820152606060408201526000614482606083018486614132565b60006020828403121561464057600080fd5b8151612b4e81613e0b565b600082516140948184602087016141a4565b602081526000612b4e60208301846142fb56fea2646970667358221220bac9c9f27dddcabfb96853f619924df101582a572473d612a72a468749966dc364736f6c63430008130033000000000000000000000000ffaa4a3d97fe9107cef8a3f48c069f577ff76cc100000000000000000000000055555555555555555555555555555555555555550000000000000000000000007e028ac56cb2af75292f3d967978189698c247320000000000000000000000005c30c174475171d2372a22cd88f3e5cdb8097e9b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106102925760003560e01c80638a7dbaa211610160578063a8f0aa42116100d8578063c22c20841161008c578063dc4c90d311610071578063dc4c90d3146105ca578063f489048a146105dd578063fa9f1cf41461060457600080fd5b8063c22c20841461057d578063d21220a7146105a457600080fd5b8063b0de1fe2116100bd578063b0de1fe21461053a578063b8f6eb8a14610543578063baad44eb1461055657600080fd5b8063a8f0aa421461051c578063aa6ca8081461052557600080fd5b80639e25bc7d1161012f578063a040d22311610114578063a040d223146104f5578063a4e2d634146104fe578063a6f19c841461050957600080fd5b80639e25bc7d146104da5780639f3a3a67146104ed57600080fd5b80638a7dbaa2146104965780638d6d9599146104a95780638fa03de7146104bc57806395c4d51e146104cf57600080fd5b806341506fc11161020e578063712290c0116101c2578063780ef175116101a7578063780ef175146104495780637aef67151461045c5780637b4f8c651461046f57600080fd5b8063712290c01461042557806373f4ea121461043857600080fd5b80634a7d0369116101f35780634a7d0369146103f557806355a68ed3146103fd57806361b9c3ec1461041257600080fd5b806341506fc1146103bc57806341a41e9e146103e257600080fd5b80631d163adf116102655780632ddf0fa11161024a5780632ddf0fa114610379578063373290091461038257806339ba11f61461039557600080fd5b80631d163adf1461034157806323c43a511461036857600080fd5b806302a1b32c146102975780630902f1ac146102b35780630dfe1681146102d05780631645118b1461030a575b600080fd5b6102a060085481565b6040519081526020015b60405180910390f35b6102bb61060d565b604080519283526020830191909152016102aa565b7f000000000000000000000000ffaa4a3d97fe9107cef8a3f48c069f577ff76cc15b6040516001600160a01b0390911681526020016102aa565b6103317f000000000000000000000000000000000000000000000000000000000000000181565b60405190151581526020016102aa565b6102a07f000000000000000000000000000000000000000000000000000000000000000081565b600d546001600160a01b03166102f2565b6102a060045481565b6102bb610390366004613c0e565b610843565b6102a07f000000000000000000000000000000000000000000000000000000000000000a81565b7f00000000000000000000000000000000000000000000000000000000000000006102f2565b6102bb6103f0366004613ca1565b611264565b6102bb6118dd565b61041061040b366004613d37565b611983565b005b610410610420366004613d37565b611a8d565b610410610433366004613d54565b611b55565b600c546001600160a01b03166102f2565b6102bb610457366004613dd0565b611df3565b61041061046a366004613d37565b611e27565b6103317f000000000000000000000000000000000000000000000000000000000000000181565b6104106104a4366004613df2565b611ef3565b6104106104b7366004613d37565b611f74565b6104106104ca366004613e19565b6120cf565b6005546006546102bb565b6104106104e8366004613d37565b61248e565b610331612587565b6102a060095481565b600054600214610331565b6002546102f2906001600160a01b031681565b6102a060065481565b61052d6125d7565b6040516102aa9190613ed0565b6102a060075481565b6001546102f2906001600160a01b031681565b6102f27f000000000000000000000000431ea546dd38f0f67e58a4785ddfc06c562ba76281565b6102a07f000000000000000000000000000000000000000000000000000000000000000081565b7f00000000000000000000000055555555555555555555555555555555555555556102f2565b6003546102f2906001600160a01b031681565b6102f27f0000000000000000000000007e028ac56cb2af75292f3d967978189698c2473281565b6102a060055481565b600080307f000000000000000000000000431ea546dd38f0f67e58a4785ddfc06c562ba7626001600160a01b03160361065c5761064a6001612779565b6106546000612779565b915091509091565b6040805160028082526060820183526000926020830190803683370190505090507f000000000000000000000000ffaa4a3d97fe9107cef8a3f48c069f577ff76cc1816000815181106106b1576106b1613f12565b60200260200101906001600160a01b031690816001600160a01b0316815250507f00000000000000000000000055555555555555555555555555555555555555558160018151811061070557610705613f12565b6001600160a01b0392831660209182029290920101526040517f9ffdefad0000000000000000000000000000000000000000000000000000000081526000917f000000000000000000000000431ea546dd38f0f67e58a4785ddfc06c562ba7621690639ffdefad9061077d9030908690600401613f41565b600060405180830381865afa15801561079a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526107c29190810190613fb8565b905080516002146107ff576040517f77452a8200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060008151811061081257610812613f12565b60200260200101518160018151811061082d5761082d613f12565b60200260200101519350935050509091565b9091565b60008061084e6128b8565b826080013542111561088c576040517f4c78bac800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82604001356000036108ca576040517fccc5071100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006108dc60c0850160a08601613d37565b6001600160a01b03160361091c576040517f24fb866e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051608081018252600d546001600160a01b0316815260009160208083019161094c91908801908801614043565b610976577f0000000000000000000000005555555555555555555555555555555555555555610998565b7f000000000000000000000000ffaa4a3d97fe9107cef8a3f48c069f577ff76cc15b6001600160a01b031681526020018560200160208101906109b99190614043565b6109e3577f000000000000000000000000ffaa4a3d97fe9107cef8a3f48c069f577ff76cc1610a05565b7f00000000000000000000000055555555555555555555555555555555555555555b6001600160a01b0316815260006020909101819052909150610a2d60e0860160c08701613d37565b6001600160a01b03161480610a66575060208101516001600160a01b0316610a5b60e0860160c08701613d37565b6001600160a01b0316145b15610a9d576040517f5746343e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000431ea546dd38f0f67e58a4785ddfc06c562ba7626001600160a01b031630148015610afa575060408101516001600160a01b0316610aee60e0860160c08701613d37565b6001600160a01b031614155b15610b31576040517f6a3d76f400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60607f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031615610b8b57610b8833610b7360e0880188614060565b610b8190602081019061409e565b6000612930565b90505b60408051808201909152600081526060602082015282516001600160a01b031615610ca05782600001516001600160a01b0316634c7b5106846020015185604001518960400135338b8060e00190610be39190614060565b610bf190606081019061409e565b6040518763ffffffff1660e01b8152600401610c129695949392919061415d565b6000604051808303816000875af1158015610c31573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610c59919081019061422c565b905061271081600001511115610c9b576040517f3e79e9d600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610ce3565b506040805180820182527f000000000000000000000000000000000000000000000000000000000000000081528151600081526020808201909352918101919091525b610d0586604001356127108360000151612710610d0091906142e8565b612a25565b60608401526001546040805160c0810182526000926001600160a01b03169163ede5e58491908190610d3c908c0160208d01614043565b151581526060808901516020830152865160408301523390820152608001610d6a60c08c0160a08d01613d37565b6001600160a01b03168152602001610d8860e08c0160c08d01613d37565b6001600160a01b03169052610da060e08b018b614060565b610daa908061409e565b876040518563ffffffff1660e01b8152600401610dca9493929190614327565b6060604051808303816000875af1158015610de9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e0d919061439c565b905080602001519450610e41876020016020810190610e2c9190614043565b85606001518360400151888b60600135612b55565b610e77576040517f457868f600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b841580610e8657506040810151155b15610ebd576040517f55d450f000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008460600151826040015114610efe57610ee5826040015184600001516127106001612bcd565b9050808260400151610ef791906142e8565b9650610f1b565b6060850151610f119060408a01356143fe565b9050876040013596505b610f62610f2e60408a0160208b01614043565b610f3b60208b018b614043565b60208801518a85610f4f60e08f018f614060565b610f5d90604081019061409e565b612c2c565b610f7d610f7560408a0160208b01614043565b888884612fe2565b600c546001600160a01b031615801590610fbb575060408501516001600160a01b0316610fb060e08a0160c08b01613d37565b6001600160a01b0316145b8015610fc75750600087115b1561106c57600c546001600160a01b031663819c3f42610fed60408b0160208c01614043565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681529015156004820152602481018a90526044810184905260648101899052608401600060405180830381600087803b15801561105357600080fd5b505af1158015611067573d6000803e3d6000fd5b505050505b61109561107f60e08a0160c08b01613d37565b61108f60c08b0160a08c01613d37565b8861322a565b84516001600160a01b0316158015906110d157506040805160008082526020820190925290508051906020012083602001518051906020012014155b156111575784516040517f280f19cf0000000000000000000000000000000000000000000000000000000081526001600160a01b039091169063280f19cf906111249084908b908b908990600401614411565b600060405180830381600087803b15801561113e57600080fd5b505af1158015611152573d6000803e3d6000fd5b505050505b8151156111f7576001546001600160a01b031663a3f3d72261117f60408b0160208c01614043565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681529015156004820152602481018a905260448101899052606401600060405180830381600087803b1580156111de57600080fd5b505af11580156111f2573d6000803e3d6000fd5b505050505b337f176648f1f11cda284c124490086be42a926ddf0ae887ebe7b1d6b337d894275661122960408b0160208c01614043565b604080519115158252602082018b905281018490526060810189905260800160405180910390a2505050505061125f6001600055565b915091565b60008061126f6132a8565b6112776128b8565b7f000000000000000000000000431ea546dd38f0f67e58a4785ddfc06c562ba7626001600160a01b031630146112d9576040517f3e009a4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b878917600003611315576040517ffbfc52fd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031615611353576113518787876001612930565b505b6040516370a0823160e01b81523060048201526000907f000000000000000000000000ffaa4a3d97fe9107cef8a3f48c069f577ff76cc16001600160a01b0316906370a0823190602401602060405180830381865afa1580156113ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113de9190614449565b6040516370a0823160e01b81523060048201529091506000906001600160a01b037f000000000000000000000000555555555555555555555555555555555555555516906370a0823190602401602060405180830381865afa158015611448573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061146c9190614449565b6040517f2d4b23bd0000000000000000000000000000000000000000000000000000000081529091503390632d4b23bd906114b1908e908e908b908b90600401614462565b600060405180830381600087803b1580156114cb57600080fd5b505af11580156114df573d6000803e3d6000fd5b50506040516370a0823160e01b81523060048201528492507f000000000000000000000000ffaa4a3d97fe9107cef8a3f48c069f577ff76cc16001600160a01b031691506370a0823190602401602060405180830381865afa158015611549573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061156d9190614449565b61157791906143fe565b6040516370a0823160e01b815230600482015290945081906001600160a01b037f000000000000000000000000555555555555555555555555555555555555555516906370a0823190602401602060405180830381865afa1580156115e0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116049190614449565b61160e91906143fe565b92508a15611716577f0000000000000000000000000000000000000000000000000000000000000001156116c05760008b85106116545761164f8c866143fe565b61165e565b61165e858d6143fe565b90507f000000000000000000000000000000000000000000000000000000000000000a8111156116ba576040517fc794db5300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5061174e565b8a84146116f9576040517f245c1efb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83600a600082825461170b91906142e8565b9091555061174e9050565b831561174e576040517f57330e8900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8915611854577f0000000000000000000000000000000000000000000000000000000000000001156117fe5760008a84106117925761178d8b856143fe565b61179c565b61179c848c6143fe565b90507f00000000000000000000000000000000000000000000000000000000000000008111156117f8576040517fbdd9a55300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5061188c565b898314611837576040517ffb702a7900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82600b600082825461184991906142e8565b9091555061188c9050565b821561188c576040517f57330e8900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051858152602081018590527f5b479c5a76f3eddfff87849b354aee2a3fbdafd3c2c1a95561143bd2ec1f1e64910160405180910390a150506118d16001600055565b97509795505050505050565b6000806118e86128b8565b6118f06132ee565b60075460085481156119355760006007556119356001600160a01b037f000000000000000000000000ffaa4a3d97fe9107cef8a3f48c069f577ff76cc1163384613332565b80156119745760006008556119746001600160a01b037f0000000000000000000000005555555555555555555555555555555555555555163383613332565b909250905061083f6001600055565b61198b6133db565b6119936128b8565b6002546001600160a01b0316156119d6576040517f4937cf5100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038116611a16576040517f68dbb6bb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040519081527fb947d28129d3b40272a411eeee3a2842c6335a0f0269abf492e8c20218bf02b0906020015b60405180910390a1611a8a6001600055565b50565b611a9561343d565b611a9d6128b8565b600954421015611ad9576040517f39000a0500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038316179055611b19426203f4806142e8565b6009556040516001600160a01b03821681527fe0d3edb906e9f17a6c8342bada5bdd7051f42bbed87eec9af9e69cd75ad98bd290602001611a78565b611b5d6128b8565b611b656132a8565b6001600160a01b038316611ba5576040517f8cfd9a7700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000431ea546dd38f0f67e58a4785ddfc06c562ba7626001600160a01b03163014611c07576040517fb0bb65d700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031615611c4557611c438483836002612930565b505b611c4f6001612779565b861115611c88576040517f4d8313ce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611c926000612779565b851115611ccb576040517f8738d6cc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f0000000000000000000000000000000000000000000000000000000000000001611cfa57600a805487900390555b7f0000000000000000000000000000000000000000000000000000000000000001611d2957600b805486900390555b8515611d6357611d636001600160a01b037f000000000000000000000000ffaa4a3d97fe9107cef8a3f48c069f577ff76cc1168488613332565b8415611d9d57611d9d6001600160a01b037f0000000000000000000000005555555555555555555555555555555555555555168487613332565b60408051878152602081018790526001600160a01b038516917fac927268ea9ae2e55027e6ab727fc2db8e3ea48c56c658223a1074567e4298c0910160405180910390a2611deb6001600055565b505050505050565b600080611dfe6128b8565b611e0661343d565b611e11848433613481565b9092509050611e206001600055565b9250929050565b611e2f61343d565b611e376128b8565b600380547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038316908117909155611eba5760006004819055611e83908033613481565b5050604051600081527f67c138aed690b53f8472c70911848132b03f2e8c321a03e5db379ad5e08502059060200160405180910390a15b6040516001600160a01b03821681527f181b126158932b45e642aeb48f81b946563bf584a35e78d6a25b013c8d41ff8f90602001611a78565b611efb61343d565b611f036128b8565b611388811115611f3f576040517f39f0f92c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60048190556040518181527f67c138aed690b53f8472c70911848132b03f2e8c321a03e5db379ad5e085020590602001611a78565b611f7c61343d565b611f846128b8565b6001600160a01b038116611fc4576040517f83c6c53300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000431ea546dd38f0f67e58a4785ddfc06c562ba7626001600160a01b03163014612026576040517fe9c9ef7800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c546001600160a01b031615612069576040517f5d906c2900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040519081527f307a86fd6204dd9b6a270c57d048c5f259625d260f8c03d1915a9fe6bc2708f090602001611a78565b6120d76128b8565b7f000000000000000000000000431ea546dd38f0f67e58a4785ddfc06c562ba7626001600160a01b03163014612139576040517fabf0792900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600085612166577f0000000000000000000000005555555555555555555555555555555555555555612188565b7f000000000000000000000000ffaa4a3d97fe9107cef8a3f48c069f577ff76cc15b90506000866121b7577f00000000000000000000000000000000000000000000000000000000000000016121d9565b7f00000000000000000000000000000000000000000000000000000000000000015b90508015612213576040517f785aa4db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516370a0823160e01b81523060048201526000906001600160a01b038416906370a0823190602401602060405180830381865afa15801561225a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061227e9190614449565b90506122946001600160a01b0384168888613332565b6040517fc00c8b6c0000000000000000000000000000000000000000000000000000000081527f439148f0bbc682ca079e46d6e2c2f0c1e3b820f1a291b069d8882abf8cf18dd9906001600160a01b0389169063c00c8b6c9061230390339088908c908c908c9060040161448c565b6020604051808303816000875af1158015612322573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123469190614449565b1461237d576040517ff1b70e9a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6123926001600160a01b038416883089613964565b6040516370a0823160e01b815230600482015281906001600160a01b038516906370a0823190602401602060405180830381865afa1580156123d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123fc9190614449565b14612433576040517ff633e4db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080518781526001600160a01b03858116602083015289169133917fe875cf27c62067457025fb9b52111f2679e19907e5a1dcf2d8092afcd67cdc3a910160405180910390a35050506124876001600055565b5050505050565b61249661343d565b61249e6128b8565b6001600160a01b0381166124de576040517f83c6c53300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001546001600160a01b031615612521576040517f58c30fc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040519081527f1d56850f49455a17df2bb41dd638797cdd462d3b4034b169d7979c2df141355490602001611a78565b60007f0000000000000000000000000000000000000000000000000000000000000001806125d257507f00000000000000000000000000000000000000000000000000000000000000015b905090565b6060307f000000000000000000000000431ea546dd38f0f67e58a4785ddfc06c562ba7626001600160a01b0316036126d45760408051600280825260608201835290916020830190803683370190505090507f000000000000000000000000ffaa4a3d97fe9107cef8a3f48c069f577ff76cc18160008151811061265d5761265d613f12565b60200260200101906001600160a01b031690816001600160a01b0316815250507f0000000000000000000000005555555555555555555555555555555555555555816001815181106126b1576126b1613f12565b60200260200101906001600160a01b031690816001600160a01b03168152505090565b6040517f0b6f5afe0000000000000000000000000000000000000000000000000000000081523060048201527f000000000000000000000000431ea546dd38f0f67e58a4785ddfc06c562ba7626001600160a01b031690630b6f5afe90602401600060405180830381865afa158015612751573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526125d291908101906144bf565b6000811561283e577f000000000000000000000000000000000000000000000000000000000000000115612836576040516370a0823160e01b81523060048201527f000000000000000000000000ffaa4a3d97fe9107cef8a3f48c069f577ff76cc16001600160a01b0316906370a08231906024015b602060405180830381865afa15801561280c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128309190614449565b92915050565b5050600a5490565b7f0000000000000000000000000000000000000000000000000000000000000001156128b0576040516370a0823160e01b81523060048201527f00000000000000000000000055555555555555555555555555555555555555556001600160a01b0316906370a08231906024016127ef565b5050600b5490565b600260005403612929576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b6002600055565b606060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663c0aa3cf8878787876040518563ffffffff1660e01b8152600401612986949392919061454e565b6000604051808303816000875af11580156129a5573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526129cd9190810190614585565b9250905080612a1c576040517f3f16fa200000000000000000000000000000000000000000000000000000000081526001600160a01b038716600482015260ff84166024820152604401612920565b50949350505050565b600080807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85870985870292508281108382030391505080600003612a7d57838281612a7357612a736145d6565b0492505050612b4e565b808411612ae6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4d6174683a206d756c446976206f766572666c6f7700000000000000000000006044820152606401612920565b600084868809851960019081018716968790049682860381900495909211909303600082900391909104909201919091029190911760038402600290811880860282030280860282030280860282030280860282030280860282030280860290910302029150505b9392505050565b6000307f000000000000000000000000431ea546dd38f0f67e58a4785ddfc06c562ba7626001600160a01b031603612ba057612b918615612779565b831115612ba057506000612bc4565b81831015612bb057506000612bc4565b84841115612bc057506000612bc4565b5060015b95945050505050565b600080612bdb868686612a25565b90506001836002811115612bf157612bf1614103565b148015612c0e575060008480612c0957612c096145d6565b868809115b15612c2157612c1e6001826142e8565b90505b90505b949350505050565b6040516370a0823160e01b81526001600160a01b037f000000000000000000000000431ea546dd38f0f67e58a4785ddfc06c562ba76281166004830152600091908716906370a0823190602401602060405180830381865afa158015612c96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cba9190614449565b90508615612d3b576040517f9fbd86ad0000000000000000000000000000000000000000000000000000000081523390639fbd86ad90612d04908990899088908890600401614605565b600060405180830381600087803b158015612d1e57600080fd5b505af1158015612d32573d6000803e3d6000fd5b50505050612d70565b612d706001600160a01b038716337f000000000000000000000000431ea546dd38f0f67e58a4785ddfc06c562ba76288613964565b6040516370a0823160e01b81526001600160a01b037f000000000000000000000000431ea546dd38f0f67e58a4785ddfc06c562ba7628116600483015260009183918916906370a0823190602401602060405180830381865afa158015612ddb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dff9190614449565b612e0991906143fe565b9050600089612e38577f0000000000000000000000000000000000000000000000000000000000000001612e5a565b7f00000000000000000000000000000000000000000000000000000000000000015b90508015612f18576000828811612e7a57612e7588846143fe565b612e84565b612e8483896143fe565b905060008b612eb3577f0000000000000000000000000000000000000000000000000000000000000000612ed5565b7f000000000000000000000000000000000000000000000000000000000000000a5b905080821115612f11576040517f07ba54e500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050612f51565b868214612f51576040517f45df38c100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b808015612f8657507f000000000000000000000000431ea546dd38f0f67e58a4785ddfc06c562ba7626001600160a01b031630145b8015612f9c57506003546001600160a01b031615155b15612fd6576000612fb287600454612710612a25565b90508015612fd457600354612fd4906001600160a01b038b8116911683613332565b505b50505050505050505050565b8315613109577f000000000000000000000000000000000000000000000000000000000000000161309157600061301e82600454612710612a25565b9050307f000000000000000000000000431ea546dd38f0f67e58a4785ddfc06c562ba7626001600160a01b0316036130715761305a81856143fe565b600a600082825461306b91906142e8565b90915550505b801561308f57806005600082825461308991906142e8565b90915550505b505b7f000000000000000000000000431ea546dd38f0f67e58a4785ddfc06c562ba7626001600160a01b0316301480156130e757507f0000000000000000000000000000000000000000000000000000000000000001155b156131045781600b60008282546130fe91906143fe565b90915550505b613224565b7f000000000000000000000000431ea546dd38f0f67e58a4785ddfc06c562ba7626001600160a01b03163014801561315f57507f0000000000000000000000000000000000000000000000000000000000000001155b1561317c5781600a600082825461317691906143fe565b90915550505b7f00000000000000000000000000000000000000000000000000000000000000016132245760006131b282600454612710612a25565b9050307f000000000000000000000000431ea546dd38f0f67e58a4785ddfc06c562ba7626001600160a01b031603613205576131ee81856143fe565b600b60008282546131ff91906142e8565b90915550505b801561248757806006600082825461321d91906142e8565b9091555050505b50505050565b307f000000000000000000000000431ea546dd38f0f67e58a4785ddfc06c562ba7626001600160a01b0316036132735761326e6001600160a01b0384168383613332565b505050565b61326e6001600160a01b0384167f000000000000000000000000431ea546dd38f0f67e58a4785ddfc06c562ba7628484613964565b6001546001600160a01b031633146132ec576040517fef410f2f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b6002546001600160a01b031633146132ec576040517f6dfbb74500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b03831660248201526044810182905261326e9084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091526139b5565b336001600160a01b037f0000000000000000000000007e028ac56cb2af75292f3d967978189698c2473216146132ec576040517fcadb26b700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6003546001600160a01b031633146132ec576040517f6c54e96000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080612710851180613495575061271084115b156134cc576040517f50d83c0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050600554600654306001600160a01b037f000000000000000000000000431ea546dd38f0f67e58a4785ddfc06c562ba7621614613839576040516370a0823160e01b81523060048201526000907f000000000000000000000000ffaa4a3d97fe9107cef8a3f48c069f577ff76cc16001600160a01b0316906370a0823190602401602060405180830381865afa15801561356b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061358f9190614449565b6040516370a0823160e01b81523060048201529091506000906001600160a01b037f000000000000000000000000555555555555555555555555555555555555555516906370a0823190602401602060405180830381865afa1580156135f9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061361d9190614449565b6040517f780ef17500000000000000000000000000000000000000000000000000000000815260048101869052602481018590529091507f000000000000000000000000431ea546dd38f0f67e58a4785ddfc06c562ba7626001600160a01b03169063780ef17590604401600060405180830381600087803b1580156136a257600080fd5b505af11580156136b6573d6000803e3d6000fd5b50506040516370a0823160e01b8152306004820152600092508491506001600160a01b037f000000000000000000000000ffaa4a3d97fe9107cef8a3f48c069f577ff76cc116906370a0823190602401602060405180830381865afa158015613723573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137479190614449565b61375191906143fe565b6040516370a0823160e01b815230600482015290915060009083906001600160a01b037f000000000000000000000000555555555555555555555555555555555555555516906370a0823190602401602060405180830381865afa1580156137bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137e19190614449565b6137eb91906143fe565b9050858211806137fa57508481115b15613831576040517fcae2d53800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b909450925050505b60006138488684612710612a25565b905060006138598684612710612a25565b9050816007600082825461386d91906142e8565b92505081905550806008600082825461388691906142e8565b90915550506000600581905560065561389f82856143fe565b93506138ab81846143fe565b925083156138e7576138e76001600160a01b037f000000000000000000000000ffaa4a3d97fe9107cef8a3f48c069f577ff76cc1168686613332565b8215613921576139216001600160a01b037f0000000000000000000000005555555555555555555555555555555555555555168685613332565b60408051858152602081018590527f9354b101c687c179e9516ece0f8b0cebbfdc205da033d49eb2b9598548ed75c2910160405180910390a15050935093915050565b6040516001600160a01b03808516602483015283166044820152606481018290526132249085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401613377565b6000613a0a826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613ab79092919063ffffffff16565b9050805160001480613a2b575080806020019051810190613a2b919061462e565b61326e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401612920565b6060612c24848460008585600080866001600160a01b03168587604051613ade919061464b565b60006040518083038185875af1925050503d8060008114613b1b576040519150601f19603f3d011682016040523d82523d6000602084013e613b20565b606091505b5091509150613b3187838387613b3c565b979650505050505050565b60608315613bc5578251600003613bbe576001600160a01b0385163b613bbe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401612920565b5081612c24565b612c248383815115613bda5781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612920919061465d565b600060208284031215613c2057600080fd5b813567ffffffffffffffff811115613c3757600080fd5b82016101008185031215612b4e57600080fd5b6001600160a01b0381168114611a8a57600080fd5b60008083601f840112613c7157600080fd5b50813567ffffffffffffffff811115613c8957600080fd5b602083019150836020828501011115611e2057600080fd5b600080600080600080600060a0888a031215613cbc57600080fd5b87359650602088013595506040880135613cd581613c4a565b9450606088013567ffffffffffffffff80821115613cf257600080fd5b613cfe8b838c01613c5f565b909650945060808a0135915080821115613d1757600080fd5b50613d248a828b01613c5f565b989b979a50959850939692959293505050565b600060208284031215613d4957600080fd5b8135612b4e81613c4a565b60008060008060008060a08789031215613d6d57600080fd5b86359550602087013594506040870135613d8681613c4a565b93506060870135613d9681613c4a565b9250608087013567ffffffffffffffff811115613db257600080fd5b613dbe89828a01613c5f565b979a9699509497509295939492505050565b60008060408385031215613de357600080fd5b50508035926020909101359150565b600060208284031215613e0457600080fd5b5035919050565b8015158114611a8a57600080fd5b600080600080600060808688031215613e3157600080fd5b8535613e3c81613e0b565b94506020860135613e4c81613c4a565b935060408601359250606086013567ffffffffffffffff811115613e6f57600080fd5b613e7b88828901613c5f565b969995985093965092949392505050565b600081518084526020808501945080840160005b83811015613ec55781516001600160a01b031687529582019590820190600101613ea0565b509495945050505050565b602081526000612b4e6020830184613e8c565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6001600160a01b0383168152604060208201526000612c246040830184613e8c565b604051601f8201601f1916810167ffffffffffffffff81118282101715613f8c57613f8c613ee3565b604052919050565b600067ffffffffffffffff821115613fae57613fae613ee3565b5060051b60200190565b60006020808385031215613fcb57600080fd5b825167ffffffffffffffff811115613fe257600080fd5b8301601f81018513613ff357600080fd5b805161400661400182613f94565b613f63565b81815260059190911b8201830190838101908783111561402557600080fd5b928401925b82841015613b315783518252928401929084019061402a565b60006020828403121561405557600080fd5b8135612b4e81613e0b565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8183360301811261409457600080fd5b9190910192915050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126140d357600080fd5b83018035915067ffffffffffffffff8211156140ee57600080fd5b602001915036819003821315611e2057600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b818352818160208501375060006020828401015260006020601f19601f840116840101905092915050565b60006001600160a01b038089168352808816602084015286604084015280861660608401525060a0608083015261419860a083018486614132565b98975050505050505050565b60005b838110156141bf5781810151838201526020016141a7565b50506000910152565b600082601f8301126141d957600080fd5b815167ffffffffffffffff8111156141f3576141f3613ee3565b6142066020601f19601f84011601613f63565b81815284602083860101111561421b57600080fd5b612c248260208301602087016141a4565b60006020828403121561423e57600080fd5b815167ffffffffffffffff8082111561425657600080fd5b908301906040828603121561426a57600080fd5b60405160408101818110838211171561428557614285613ee3565b6040528251815260208301518281111561429e57600080fd5b6142aa878286016141c8565b60208301525095945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115612830576128306142b9565b600081518084526143138160208601602086016141a4565b601f01601f19169290920160200192915050565b6000610100865115158352602087015160208401526040870151604084015260608701516001600160a01b0380821660608601528060808a01511660808601528060a08a01511660a086015250508060c08401526143888184018688614132565b905082810360e0840152613b3181856142fb565b6000606082840312156143ae57600080fd5b6040516060810181811067ffffffffffffffff821117156143d1576143d1613ee3565b60405282516143df81613e0b565b8152602083810151908201526040928301519281019290925250919050565b81810381811115612830576128306142b9565b848152836020820152826040820152608060608201528151608082015260006020830151604060a0840152613b3160c08401826142fb565b60006020828403121561445b57600080fd5b5051919050565b848152836020820152606060408201526000614482606083018486614132565b9695505050505050565b60006001600160a01b03808816835280871660208401525084604083015260806060830152613b31608083018486614132565b600060208083850312156144d257600080fd5b825167ffffffffffffffff8111156144e957600080fd5b8301601f810185136144fa57600080fd5b805161450861400182613f94565b81815260059190911b8201830190838101908783111561452757600080fd5b928401925b82841015613b3157835161453f81613c4a565b8252928401929084019061452c565b6001600160a01b0385168152606060208201526000614571606083018587614132565b905060ff8316604083015295945050505050565b6000806040838503121561459857600080fd5b82516145a381613e0b565b602084015190925067ffffffffffffffff8111156145c057600080fd5b6145cc858286016141c8565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6001600160a01b0385168152836020820152606060408201526000614482606083018486614132565b60006020828403121561464057600080fd5b8151612b4e81613e0b565b600082516140948184602087016141a4565b602081526000612b4e60208301846142fb56fea2646970667358221220bac9c9f27dddcabfb96853f619924df101582a572473d612a72a468749966dc364736f6c63430008130033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000ffaa4a3d97fe9107cef8a3f48c069f577ff76cc100000000000000000000000055555555555555555555555555555555555555550000000000000000000000007e028ac56cb2af75292f3d967978189698c247320000000000000000000000005c30c174475171d2372a22cd88f3e5cdb8097e9b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : args (tuple):
Arg [1] : token0 (address): 0xfFaa4a3D97fE9107Cef8a3F48c069F577Ff76cC1
Arg [2] : token1 (address): 0x5555555555555555555555555555555555555555
Arg [3] : protocolFactory (address): 0x7E028ac56cB2AF75292F3D967978189698C24732
Arg [4] : poolManager (address): 0x5C30c174475171D2372a22cD88F3E5CDb8097e9B
Arg [5] : sovereignVault (address): 0x0000000000000000000000000000000000000000
Arg [6] : verifierModule (address): 0x0000000000000000000000000000000000000000
Arg [7] : isToken0Rebase (bool): True
Arg [8] : isToken1Rebase (bool): True
Arg [9] : token0AbsErrorTolerance (uint256): 10
Arg [10] : token1AbsErrorTolerance (uint256): 0
Arg [11] : defaultSwapFeeBips (uint256): 0
-----Encoded View---------------
11 Constructor Arguments found :
Arg [0] : 000000000000000000000000ffaa4a3d97fe9107cef8a3f48c069f577ff76cc1
Arg [1] : 0000000000000000000000005555555555555555555555555555555555555555
Arg [2] : 0000000000000000000000007e028ac56cb2af75292f3d967978189698c24732
Arg [3] : 0000000000000000000000005c30c174475171d2372a22cd88f3e5cdb8097e9b
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [8] : 000000000000000000000000000000000000000000000000000000000000000a
Arg [9] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [10] : 0000000000000000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in HYPE
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.