Overview
ETH Balance
0 ETH
ETH Value
$0.00More Info
Private Name Tags
ContractCreator
TokenTracker
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 258698342 | 482 days ago | Contract Creation | 0 ETH |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
Stable2
Compiler Version
v0.8.26+commit.8a97fa7a
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {IBeanstalkWellFunction, IMultiFlowPumpWellFunction} from "src/interfaces/IBeanstalkWellFunction.sol";
import {ILookupTable} from "src/interfaces/ILookupTable.sol";
import {ProportionalLPToken2} from "src/functions/ProportionalLPToken2.sol";
import {IERC20} from "forge-std/interfaces/IERC20.sol";
/**
* @author brean, deadmanwalking
* @title Gas efficient Like-valued token pricing function for Wells with 2 tokens.
*
* Stableswap Wells with 2 tokens use the formula:
* `4 * A * (b_0+b_1) + D = 4 * A * D + D^3/(4 * b_0 * b_1)`
*
* Where:
* `A` is the Amplication parameter.
* `D` is the supply of LP tokens
* `b_i` is the reserve at index `i`
*
* @dev Limited to tokens with a maximum of 18 decimals.
*/
contract Stable2 is ProportionalLPToken2, IBeanstalkWellFunction {
struct PriceData {
uint256 targetPrice;
uint256 currentPrice;
uint256 newPrice;
uint256 maxStepSize;
ILookupTable.PriceData lutData;
}
// 2 token Pool.
uint256 constant N = 2;
// A precision
uint256 constant A_PRECISION = 100;
// price precision.
uint256 constant PRICE_PRECISION = 1e6;
// price threshold. more accurate pricing requires a lower threshold,
// at the cost of higher execution costs.
uint256 constant PRICE_THRESHOLD = 10; // 0.001%
address immutable lookupTable;
uint256 immutable a;
// Errors
error InvalidTokenDecimals();
error InvalidLUT();
// Due to the complexity of `calcReserveAtRatioLiquidity` and `calcReserveAtRatioSwap`,
// a LUT is used to reduce the complexity of the calculations on chain.
// the lookup table contract implements 3 functions:
// 1. getRatiosFromPriceLiquidity(uint256) -> PriceData memory
// 2. getRatiosFromPriceSwap(uint256) -> PriceData memory
// 3. getAParameter() -> uint256
// Lookup tables are a function of the A parameter.
constructor(
address lut
) {
if (lut == address(0)) revert InvalidLUT();
lookupTable = lut;
a = ILookupTable(lut).getAParameter();
}
/**
* @notice Calculate the amount of lp tokens given reserves.
* D invariant calculation in non-overflowing integer operations iteratively
* A * sum(x_i) * n**n + D = A * D * n**n + D**(n+1) / (n**n * prod(x_i))
*
* Converging solution:
* D[j+1] = (4 * A * sum(b_i) - (D[j] ** 3) / (4 * prod(b_i))) / (4 * A - 1)
*/
function calcLpTokenSupply(
uint256[] memory reserves,
bytes memory data
) public view returns (uint256 lpTokenSupply) {
if (reserves[0] == 0 && reserves[1] == 0) return 0;
uint256[] memory decimals = decodeWellData(data);
// scale reserves to 18 decimals.
uint256[] memory scaledReserves = getScaledReserves(reserves, decimals);
uint256 Ann = a * N * N;
uint256 sumReserves = scaledReserves[0] + scaledReserves[1];
lpTokenSupply = sumReserves;
for (uint256 i = 0; i < 255; i++) {
bool stableOscillation;
uint256 dP = lpTokenSupply;
// If division by 0, this will be borked: only withdrawal will work. And that is good
dP = dP * lpTokenSupply / (scaledReserves[0] * N);
dP = dP * lpTokenSupply / (scaledReserves[1] * N);
uint256 prevReserves = lpTokenSupply;
lpTokenSupply = (Ann * sumReserves / A_PRECISION + (dP * N)) * lpTokenSupply
/ (((Ann - A_PRECISION) * lpTokenSupply / A_PRECISION) + ((N + 1) * dP));
// Equality with the precision of 1
// If the difference between the current lpTokenSupply and the previous lpTokenSupply is 2,
// Check that the oscillation is stable, and if so, return the average between the two.
if (lpTokenSupply > prevReserves) {
if (lpTokenSupply - prevReserves == 2) {
if (stableOscillation) {
return lpTokenSupply - 1;
}
stableOscillation = true;
}
if (lpTokenSupply - prevReserves <= 1) return lpTokenSupply;
} else {
if (prevReserves - lpTokenSupply == 2) {
if (stableOscillation) {
return lpTokenSupply + 1;
}
stableOscillation = true;
}
if (prevReserves - lpTokenSupply <= 1) return lpTokenSupply;
}
}
revert("Non convergence: calcLpTokenSupply");
}
/**
* @notice Calculate x[i] if one reduces D from being calculated for reserves to D
* Done by solving quadratic equation iteratively.
* x_1**2 + x_1 * (sum' - (A*n**n - 1) * D / (A * n**n)) = D ** (n + 1) / (n ** (2 * n) * prod' * A)
* x_1**2 + b*x_1 = c
* x_1 = (x_1**2 + c) / (2*x_1 + b)
* @dev This function has a precision of +/- 1,
* which may round in favor of the well or the user.
*/
function calcReserve(
uint256[] memory reserves,
uint256 j,
uint256 lpTokenSupply,
bytes memory data
) public view returns (uint256 reserve) {
uint256[] memory decimals = decodeWellData(data);
uint256[] memory scaledReserves = getScaledReserves(reserves, decimals);
// avoid stack too deep errors.
(uint256 c, uint256 b) = getBandC(a * N * N, lpTokenSupply, j == 0 ? scaledReserves[1] : scaledReserves[0]);
reserve = lpTokenSupply;
uint256 prevReserve;
for (uint256 i; i < 255; ++i) {
prevReserve = reserve;
reserve = _calcReserve(reserve, b, c, lpTokenSupply);
// Equality with the precision of 1
// scale reserve down to original precision
if (reserve > prevReserve) {
if (reserve - prevReserve <= 1) {
return reserve / (10 ** (18 - decimals[j]));
}
} else {
if (prevReserve - reserve <= 1) {
return reserve / (10 ** (18 - decimals[j]));
}
}
}
revert("Non convergence: calcReserve");
}
/**
* @inheritdoc IMultiFlowPumpWellFunction
* @dev Returns a rate with decimal precision.
* Requires a minimum scaled reserves of 1e12.
* 6 decimals was chosen as higher decimals would require a higher minimum scaled reserve,
* which is prohibtive for large value tokens.
*/
function calcRate(
uint256[] memory reserves,
uint256 i,
uint256 j,
bytes memory data
) public view returns (uint256 rate) {
uint256[] memory decimals = decodeWellData(data);
uint256[] memory scaledReserves = getScaledReserves(reserves, decimals);
// calc lp token supply (note: `scaledReserves` is scaled up, and does not require bytes).
uint256 lpTokenSupply = calcLpTokenSupply(scaledReserves, abi.encode(18, 18));
rate = _calcRate(scaledReserves, i, j, lpTokenSupply);
}
/**
* @inheritdoc IMultiFlowPumpWellFunction
* @dev `calcReserveAtRatioSwap` fetches the closes approximate ratios from the target price,
* and performs newtons method in order to converge into a reserve.
*/
function calcReserveAtRatioSwap(
uint256[] memory reserves,
uint256 j,
uint256[] memory ratios,
bytes calldata data
) external view returns (uint256 reserve) {
uint256 i = j == 1 ? 0 : 1;
// scale reserves and ratios:
uint256[] memory decimals = decodeWellData(data);
uint256[] memory scaledReserves = getScaledReserves(reserves, decimals);
PriceData memory pd;
uint256[] memory scaledRatios = getScaledReserves(ratios, decimals);
// calc target price with 6 decimal precision:
pd.targetPrice = scaledRatios[i] * PRICE_PRECISION / scaledRatios[j];
// get ratios and price from the closest highest and lowest price from targetPrice:
pd.lutData = ILookupTable(lookupTable).getRatiosFromPriceSwap(pd.targetPrice);
// calculate lp token supply:
uint256 lpTokenSupply = calcLpTokenSupply(scaledReserves, abi.encode(18, 18));
// lpTokenSupply / 2 gives the reserves at parity:
uint256 parityReserve = lpTokenSupply / 2;
// update `scaledReserves` based on whether targetPrice is closer to low or high price:
if (percentDiff(pd.lutData.highPrice, pd.targetPrice) > percentDiff(pd.lutData.lowPrice, pd.targetPrice)) {
// targetPrice is closer to lowPrice.
scaledReserves[i] = parityReserve * pd.lutData.lowPriceI / pd.lutData.precision;
scaledReserves[j] = parityReserve * pd.lutData.lowPriceJ / pd.lutData.precision;
// initialize currentPrice:
pd.currentPrice = pd.lutData.lowPrice;
} else {
// targetPrice is closer to highPrice.
scaledReserves[i] = parityReserve * pd.lutData.highPriceI / pd.lutData.precision;
scaledReserves[j] = parityReserve * pd.lutData.highPriceJ / pd.lutData.precision;
// initialize currentPrice:
pd.currentPrice = pd.lutData.highPrice;
}
// calculate max step size:
// lowPriceJ will always be larger than highPriceJ so a check here is unnecessary.
pd.maxStepSize = scaledReserves[j] * (pd.lutData.lowPriceJ - pd.lutData.highPriceJ) / pd.lutData.lowPriceJ;
for (uint256 k; k < 255; k++) {
scaledReserves[j] = updateReserve(pd, scaledReserves[j]);
// calculate scaledReserve[i]:
scaledReserves[i] = calcReserve(scaledReserves, i, lpTokenSupply, abi.encode(18, 18));
// calculate new price from reserves:
pd.newPrice = _calcRate(scaledReserves, i, j, lpTokenSupply);
// if the new current price is either lower or higher than both the previous current price and the target price,
// (i.e the target price lies between the current price and the previous current price),
// recalibrate high/low price.
if (pd.newPrice > pd.currentPrice && pd.newPrice > pd.targetPrice) {
pd.lutData.highPriceJ = scaledReserves[j] * 1e18 / parityReserve;
pd.lutData.highPriceI = scaledReserves[i] * 1e18 / parityReserve;
pd.lutData.highPrice = pd.newPrice;
} else if (pd.newPrice < pd.currentPrice && pd.newPrice < pd.targetPrice) {
pd.lutData.lowPriceJ = scaledReserves[j] * 1e18 / parityReserve;
pd.lutData.lowPriceI = scaledReserves[i] * 1e18 / parityReserve;
pd.lutData.lowPrice = pd.newPrice;
}
// update max step size based on new scaled reserve.
pd.maxStepSize = scaledReserves[j] * (pd.lutData.lowPriceJ - pd.lutData.highPriceJ) / pd.lutData.lowPriceJ;
pd.currentPrice = pd.newPrice;
// check if new price is within PRICE_THRESHOLD:
if (pd.currentPrice > pd.targetPrice) {
if (pd.currentPrice - pd.targetPrice <= PRICE_THRESHOLD) {
return scaledReserves[j] / (10 ** (18 - decimals[j]));
}
} else {
if (pd.targetPrice - pd.currentPrice <= PRICE_THRESHOLD) {
return scaledReserves[j] / (10 ** (18 - decimals[j]));
}
}
}
revert("Non convergence: calcReserveAtRatioSwap");
}
/**
* @inheritdoc IBeanstalkWellFunction
* @dev `calcReserveAtRatioLiquidity` fetches the closes approximate ratios from the target price,
*/
function calcReserveAtRatioLiquidity(
uint256[] calldata reserves,
uint256 j,
uint256[] calldata ratios,
bytes calldata data
) external view returns (uint256 reserve) {
uint256 i = j == 1 ? 0 : 1;
// scale reserves and ratios:
uint256[] memory decimals = decodeWellData(data);
uint256[] memory scaledReserves = getScaledReserves(reserves, decimals);
PriceData memory pd;
uint256[] memory scaledRatios = getScaledReserves(ratios, decimals);
// calc target price with 6 decimal precision:
pd.targetPrice = scaledRatios[i] * PRICE_PRECISION / scaledRatios[j];
// get ratios and price from the closest highest and lowest price from targetPrice:
pd.lutData = ILookupTable(lookupTable).getRatiosFromPriceLiquidity(pd.targetPrice);
// update scaledReserve[j] such that calcRate(scaledReserves, i, j) = low/high Price,
// depending on which is closer to targetPrice.
if (percentDiff(pd.lutData.highPrice, pd.targetPrice) > percentDiff(pd.lutData.lowPrice, pd.targetPrice)) {
// targetPrice is closer to lowPrice.
scaledReserves[j] = scaledReserves[i] * pd.lutData.lowPriceJ / pd.lutData.precision;
// set current price to lowPrice.
pd.currentPrice = pd.lutData.lowPrice;
} else {
// targetPrice is closer to highPrice.
scaledReserves[j] = scaledReserves[i] * pd.lutData.highPriceJ / pd.lutData.precision;
// set current price to highPrice.
pd.currentPrice = pd.lutData.highPrice;
}
// calculate max step size:
// lowPriceJ will always be larger than highPriceJ so a check here is unnecessary.
pd.maxStepSize = scaledReserves[j] * (pd.lutData.lowPriceJ - pd.lutData.highPriceJ) / pd.lutData.lowPriceJ;
for (uint256 k; k < 255; k++) {
scaledReserves[j] = updateReserve(pd, scaledReserves[j]);
// calculate new price from reserves:
pd.newPrice = calcRate(scaledReserves, i, j, abi.encode(18, 18));
// if the new current price is either lower or higher than both the previous current price and the target price,
// (i.e the target price lies between the current price and the previous current price),
// recalibrate high/lowPrice and continue.
if (pd.newPrice > pd.targetPrice && pd.targetPrice > pd.currentPrice) {
pd.lutData.highPriceJ = scaledReserves[j] * 1e18 / scaledReserves[i];
pd.lutData.highPrice = pd.newPrice;
} else if (pd.newPrice < pd.targetPrice && pd.targetPrice < pd.currentPrice) {
pd.lutData.lowPriceJ = scaledReserves[j] * 1e18 / scaledReserves[i];
pd.lutData.lowPrice = pd.newPrice;
}
// update max step size based on new scaled reserve.
pd.maxStepSize = scaledReserves[j] * (pd.lutData.lowPriceJ - pd.lutData.highPriceJ) / pd.lutData.lowPriceJ;
pd.currentPrice = pd.newPrice;
// check if new price is within PRICE_THRESHOLD:
if (pd.currentPrice > pd.targetPrice) {
if (pd.currentPrice - pd.targetPrice <= PRICE_THRESHOLD) {
return scaledReserves[j] / (10 ** (18 - decimals[j]));
}
} else {
if (pd.targetPrice - pd.currentPrice <= PRICE_THRESHOLD) {
return scaledReserves[j] / (10 ** (18 - decimals[j]));
}
}
}
revert("Non convergence: calcReserveAtRatioLiquidity");
}
/**
* @notice decodes the data encoded in the well.
* @return decimals an array of the decimals of the tokens in the well.
*/
function decodeWellData(
bytes memory data
) public view virtual returns (uint256[] memory decimals) {
(uint256 decimal0, uint256 decimal1) = abi.decode(data, (uint256, uint256));
// if well data returns 0, assume 18 decimals.
if (decimal0 == 0) {
decimal0 = 18;
}
if (decimal1 == 0) {
decimal1 = 18;
}
if (decimal0 > 18 || decimal1 > 18) revert InvalidTokenDecimals();
decimals = new uint256[](2);
decimals[0] = decimal0;
decimals[1] = decimal1;
}
function name() external pure returns (string memory) {
return "Stable2";
}
function symbol() external pure returns (string memory) {
return "S2";
}
function version() external pure returns (string memory) {
return "1.1.0";
}
/**
* @notice internal calcRate function.
*/
function _calcRate(
uint256[] memory reserves,
uint256 i,
uint256 j,
uint256 lpTokenSupply
) internal view returns (uint256 rate) {
// add 1e6 to reserves:
uint256[] memory _reserves = new uint256[](2);
_reserves[i] = reserves[i];
_reserves[j] = reserves[j] + PRICE_PRECISION;
// calculate rate:
rate = _reserves[i] - calcReserve(_reserves, i, lpTokenSupply, abi.encode(18, 18));
}
/**
* @inheritdoc IMultiFlowPumpWellFunction
* @notice Returns the precision of the ratio at which the pump will cap the reserve at.
* @dev {Stable2.calcRate} returns the rate with PRICE_PRECISION, independent of data or index.
*/
function ratioPrecision(uint256, bytes calldata) external pure returns (uint256 precision) {
return PRICE_PRECISION;
}
/**
* @notice scale `reserves` by `precision`.
* @dev this sets both reserves to 18 decimals.
*/
function getScaledReserves(
uint256[] memory reserves,
uint256[] memory decimals
) internal pure returns (uint256[] memory scaledReserves) {
scaledReserves = new uint256[](2);
scaledReserves[0] = reserves[0] * 10 ** (18 - decimals[0]);
scaledReserves[1] = reserves[1] * 10 ** (18 - decimals[1]);
}
function _calcReserve(
uint256 reserve,
uint256 b,
uint256 c,
uint256 lpTokenSupply
) private pure returns (uint256) {
return (reserve * reserve + c) / (reserve * 2 + b - lpTokenSupply);
}
function getBandC(
uint256 Ann,
uint256 lpTokenSupply,
uint256 reserves
) private pure returns (uint256 c, uint256 b) {
c = lpTokenSupply * lpTokenSupply / (reserves * N) * lpTokenSupply * A_PRECISION / (Ann * N);
b = reserves + (lpTokenSupply * A_PRECISION / Ann);
}
/**
* @notice calculates the step size, and returns the updated reserve.
*/
function updateReserve(PriceData memory pd, uint256 reserve) internal pure returns (uint256) {
if (pd.targetPrice > pd.currentPrice) {
// if the targetPrice is greater than the currentPrice,
// the reserve needs to be decremented to increase currentPrice.
return reserve
- pd.maxStepSize * (pd.targetPrice - pd.currentPrice) / (pd.lutData.highPrice - pd.lutData.lowPrice);
} else {
// if the targetPrice is less than the currentPrice,
// the reserve needs to be incremented to decrease currentPrice.
return reserve
+ pd.maxStepSize * (pd.currentPrice - pd.targetPrice) / (pd.lutData.highPrice - pd.lutData.lowPrice);
}
}
/**
* @notice Calculate the percentage difference between two numbers.
* @return The percentage difference as a fixed-point number with 18 decimals.
* @dev This function calculates the absolute percentage difference:
* |(a - b)| / ((a + b) / 2) * 100
* The result is scaled by 1e18 for precision.
*/
function percentDiff(uint256 _a, uint256 _b) internal pure returns (uint256) {
if (_a == _b) return 0;
uint256 difference = _a > _b ? _a - _b : _b - _a;
uint256 average = (_a + _b) / 2;
// Multiply by 100 * 1e18 to get percentage with 18 decimal places
return (difference * 100 * 1e18) / average;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {IMultiFlowPumpWellFunction} from "src/interfaces/IMultiFlowPumpWellFunction.sol";
/**
* @title IBeanstalkWellFunction
* @notice Defines all necessary functions for Beanstalk to support a Well Function in addition to functions defined in the primary interface.
* It extends `IMultiFlowPumpWellFunction` as Beanstalk requires Wells to use MultiFlowPump in order to have access to manipulation resistant oracles.
* Beanstalk requires 2 functions to solve for a given reserve value such that the average price between
* the given reserve and all other reserves equals the average of the input ratios.
* - `calcReserveAtRatioSwap` assumes the target ratios are reached through executing a swap. Note: `calcReserveAtRatioSwap` is included in {IMultiFlowPumpWellFunction}.
* - `calcReserveAtRatioLiquidity` assumes the target ratios are reached through adding/removing liquidity.
*/
interface IBeanstalkWellFunction is IMultiFlowPumpWellFunction {
/**
* @notice Calculates the `j` reserve such that `π_{i | i != j} (d reserves_j / d reserves_i) = π_{i | i != j}(ratios_j / ratios_i)`.
* assumes that reserve_j is being added or removed in exchange for LP Tokens.
* @dev used by Beanstalk to calculate the max deltaB that can be converted in/out of a Well.
* @param reserves The reserves of the Well
* @param j The index of the reserve to solve for
* @param ratios The ratios of reserves to solve for
* @param data Well function data provided on every call
* @return reserve The resulting reserve at the jth index
*/
function calcReserveAtRatioLiquidity(
uint256[] calldata reserves,
uint256 j,
uint256[] calldata ratios,
bytes calldata data
) external view returns (uint256 reserve);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
/**
* @title PriceReserveMapping
* @author DeadmanWalking
* @notice In order to reasonably use `calcReserveAtRatioSwap` and `calcReserveAtRatioLiquidity` on chain,
* a lookup table contract is used to decrease the amount of iterations needed to converge into an answer.
*/
interface ILookupTable {
/**
* @notice the lookup table returns a series of data, given a price point:
* @param highPrice the closest price to the targetPrice, where targetPrice < highPrice.
* @param highPriceI reserve i such that `calcRate(reserve, i, j, data)` == highPrice.
* @param highPriceJ reserve j such that `calcRate(reserve, i, j, data)` == highPrice.
* @param lowPrice the closest price to the targetPrice, where targetPrice > lowPrice.
* @param lowPriceI reserve i such that `calcRate(reserve, i, j, data)` == lowPrice.
* @param lowPriceJ reserve j such that `calcRate(reserve, i, j, data)` == lowPrice.
* @param precision the initial reserve values. Assumes the inital reserve i == reserve j
*/
struct PriceData {
uint256 highPrice;
uint256 highPriceI;
uint256 highPriceJ;
uint256 lowPrice;
uint256 lowPriceI;
uint256 lowPriceJ;
uint256 precision;
}
function getRatiosFromPriceLiquidity(
uint256
) external view returns (PriceData memory);
function getRatiosFromPriceSwap(
uint256
) external view returns (PriceData memory);
function getAParameter() external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {IWellFunction} from "src/interfaces/IWellFunction.sol";
import {Math} from "oz/utils/math/Math.sol";
/**
* @title ProportionalLPToken2
* @notice Defines a proportional relationship between the supply of LP tokens
* and the amount of each underlying token for a two-token Well.
* @dev When removing `s` LP tokens with a Well with `S` LP token supply, the user
* recieves `s * b_i / S` of each underlying token.
*/
abstract contract ProportionalLPToken2 is IWellFunction {
using Math for uint256;
function calcLPTokenUnderlying(
uint256 lpTokenAmount,
uint256[] calldata reserves,
uint256 lpTokenSupply,
bytes calldata
) external pure returns (uint256[] memory underlyingAmounts) {
underlyingAmounts = new uint256[](2);
underlyingAmounts[0] = lpTokenAmount.mulDiv(reserves[0], lpTokenSupply);
underlyingAmounts[1] = lpTokenAmount.mulDiv(reserves[1], lpTokenSupply);
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.6.2;
/// @dev Interface of the ERC20 standard as defined in the EIP.
/// @dev This includes the optional name, symbol, and decimals metadata.
interface IERC20 {
/// @dev Emitted when `value` tokens are moved from one account (`from`) to another (`to`).
event Transfer(address indexed from, address indexed to, uint256 value);
/// @dev Emitted when the allowance of a `spender` for an `owner` is set, where `value`
/// is the new allowance.
event Approval(address indexed owner, address indexed spender, uint256 value);
/// @notice Returns the amount of tokens in existence.
function totalSupply() external view returns (uint256);
/// @notice Returns the amount of tokens owned by `account`.
function balanceOf(address account) external view returns (uint256);
/// @notice Moves `amount` tokens from the caller's account to `to`.
function transfer(address to, uint256 amount) external returns (bool);
/// @notice Returns the remaining number of tokens that `spender` is allowed
/// to spend on behalf of `owner`
function allowance(address owner, address spender) external view returns (uint256);
/// @notice Sets `amount` as the allowance of `spender` over the caller's tokens.
/// @dev Be aware of front-running risks: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
function approve(address spender, uint256 amount) external returns (bool);
/// @notice Moves `amount` tokens from `from` to `to` using the allowance mechanism.
/// `amount` is then deducted from the caller's allowance.
function transferFrom(address from, address to, uint256 amount) external returns (bool);
/// @notice Returns the name of the token.
function name() external view returns (string memory);
/// @notice Returns the symbol of the token.
function symbol() external view returns (string memory);
/// @notice Returns the decimals places of the token.
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {IWellFunction} from "src/interfaces/IWellFunction.sol";
/**
* @title IMultiFlowPumpWellFunction
* @dev A Well Function must implement IMultiFlowPumpWellFunction to be supported by
* the Multi Flow Pump.
*/
interface IMultiFlowPumpWellFunction is IWellFunction {
/**
* @notice Calculates the `j` reserve such that `π_{i | i != j} (d reserves_j / d reserves_i) = π_{i | i != j}(ratios_j / ratios_i)`.
* assumes that reserve_j is being swapped for other reserves in the Well.
* @dev used by Beanstalk to calculate the deltaB every Season
* @param reserves The reserves of the Well
* @param j The index of the reserve to solve for
* @param ratios The ratios of reserves to solve for
* @param data Well function data provided on every call
* @return reserve The resulting reserve at the jth index
*/
function calcReserveAtRatioSwap(
uint256[] calldata reserves,
uint256 j,
uint256[] calldata ratios,
bytes calldata data
) external view returns (uint256 reserve);
/**
* @notice Calculates the rate at which j can be exchanged for i.
* @param reserves The reserves of the Well
* @param i The index of the token for which the output is being calculated
* @param j The index of the token for which 1 token is being exchanged
* @param data Well function data provided on every call
* @return rate The rate at which j can be exchanged for i
* @dev should return with 36 decimal precision
*/
function calcRate(
uint256[] calldata reserves,
uint256 i,
uint256 j,
bytes calldata data
) external view returns (uint256 rate);
/**
* @notice Returns the precision of the ratio at which the pump will cap the reserve at.
* @param j The index of the reserve to solve for
* @param data The data passed to the well function
* @return precision The precision of the ratio at which the pump will cap the reserve at
*/
function ratioPrecision(uint256 j, bytes calldata data) external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/**
* @title IWellFunction
* @notice Defines a relationship between token reserves and LP token supply.
* @dev Well Functions can contain arbitrary logic, but should be deterministic
* if expected to be used alongside a Pump. When interacing with a Well or
* Well Function, always verify that the Well Function is valid.
*/
interface IWellFunction {
/**
* @notice Thrown if the user inputs a `j` value is out of bounds.
*/
error InvalidJArgument();
/**
* @notice Calculates the `j`th reserve given a list of `reserves` and `lpTokenSupply`.
* @param reserves A list of token reserves. The jth reserve will be ignored, but a placeholder must be provided.
* @param j The index of the reserve to solve for
* @param lpTokenSupply The supply of LP tokens
* @param data Extra Well function data provided on every call
* @return reserve The resulting reserve at the jth index
* @dev Should round up to ensure that Well reserves are marginally higher to enforce calcLpTokenSupply(...) >= totalSupply()
*/
function calcReserve(
uint256[] memory reserves,
uint256 j,
uint256 lpTokenSupply,
bytes calldata data
) external view returns (uint256 reserve);
/**
* @notice Gets the LP token supply given a list of reserves.
* @param reserves A list of token reserves
* @param data Extra Well function data provided on every call
* @return lpTokenSupply The resulting supply of LP tokens
* @dev Should round down to ensure so that the Well Token supply is marignally lower to enforce calcLpTokenSupply(...) >= totalSupply()
*/
function calcLpTokenSupply(
uint256[] memory reserves,
bytes calldata data
) external view returns (uint256 lpTokenSupply);
/**
* @notice Calculates the amount of each reserve token underlying a given amount of LP tokens.
* @param lpTokenAmount An amount of LP tokens
* @param reserves A list of token reserves
* @param lpTokenSupply The current supply of LP tokens
* @param data Extra Well function data provided on every call
* @return underlyingAmounts The amount of each reserve token that underlies the LP tokens
* @dev The constraint totalSupply() <= calcLPTokenSupply(...) must be held in the case where
* `lpTokenAmount` LP tokens are burned in exchanged for `underlyingAmounts`. If the constraint
* does not hold, then the Well Function is invalid.
*/
function calcLPTokenUnderlying(
uint256 lpTokenAmount,
uint256[] memory reserves,
uint256 lpTokenSupply,
bytes calldata data
) external view returns (uint256[] memory underlyingAmounts);
/**
* @notice Returns the name of the Well function.
*/
function name() external view returns (string memory);
/**
* @notice Returns the symbol of the Well function.
*/
function symbol() external view returns (string memory);
/**
* @notice Returns the version of the Well function.
*/
function version() external view returns (string memory);
}// 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);
}
}
}{
"remappings": [
"prb/math/=lib/prb-math/src/",
"forge-std/=lib/forge-std/src/",
"oz/=lib/openzeppelin-contracts/contracts/",
"ozu/=lib/openzeppelin-contracts-upgradeable/contracts/",
"src/=src/",
"mocks/=mocks/",
"tests/=tests/",
"utils/=utils/",
"@openzeppelin/=node_modules/@openzeppelin/",
"@prb/test/=lib/prb-math/lib/prb-test/src/",
"ds-test/=lib/prb-math/lib/forge-std/lib/ds-test/src/",
"erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
"openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"openzeppelin/=lib/openzeppelin-contracts-upgradeable/contracts/",
"prb-math/=lib/prb-math/src/",
"prb-test/=lib/prb-math/lib/prb-test/src/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "paris",
"viaIR": false,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"lut","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"InvalidJArgument","type":"error"},{"inputs":[],"name":"InvalidLUT","type":"error"},{"inputs":[],"name":"InvalidTokenDecimals","type":"error"},{"inputs":[{"internalType":"uint256","name":"lpTokenAmount","type":"uint256"},{"internalType":"uint256[]","name":"reserves","type":"uint256[]"},{"internalType":"uint256","name":"lpTokenSupply","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"calcLPTokenUnderlying","outputs":[{"internalType":"uint256[]","name":"underlyingAmounts","type":"uint256[]"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"reserves","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"calcLpTokenSupply","outputs":[{"internalType":"uint256","name":"lpTokenSupply","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"reserves","type":"uint256[]"},{"internalType":"uint256","name":"i","type":"uint256"},{"internalType":"uint256","name":"j","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"calcRate","outputs":[{"internalType":"uint256","name":"rate","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"reserves","type":"uint256[]"},{"internalType":"uint256","name":"j","type":"uint256"},{"internalType":"uint256","name":"lpTokenSupply","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"calcReserve","outputs":[{"internalType":"uint256","name":"reserve","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"reserves","type":"uint256[]"},{"internalType":"uint256","name":"j","type":"uint256"},{"internalType":"uint256[]","name":"ratios","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"calcReserveAtRatioLiquidity","outputs":[{"internalType":"uint256","name":"reserve","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"reserves","type":"uint256[]"},{"internalType":"uint256","name":"j","type":"uint256"},{"internalType":"uint256[]","name":"ratios","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"calcReserveAtRatioSwap","outputs":[{"internalType":"uint256","name":"reserve","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"decodeWellData","outputs":[{"internalType":"uint256[]","name":"decimals","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"ratioPrecision","outputs":[{"internalType":"uint256","name":"precision","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"}]Contract Creation Code
60c060405234801561001057600080fd5b506040516123d43803806123d483398101604081905261002f916100cd565b6001600160a01b03811661005657604051638005fdb760e01b815260040160405180910390fd5b6001600160a01b038116608081905260408051633e2a0a2960e01b81529051633e2a0a29916004808201926020929091908290030181865afa1580156100a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100c491906100fd565b60a05250610116565b6000602082840312156100df57600080fd5b81516001600160a01b03811681146100f657600080fd5b9392505050565b60006020828403121561010f57600080fd5b5051919050565b60805160a05161228b6101496000396000818161024d0152610bb10152600081816106a00152610e07015261228b6000f3fe608060405234801561001057600080fd5b50600436106100a95760003560e01c80637f35e83d116100715780637f35e83d1461014b57806380be8c981461015e57806395d89b4114610171578063a11686b81461018f578063b1d35841146101af578063bf66642a146101c257600080fd5b806306fdde03146100ae57806314c15fc0146100e35780632b227ea91461010457806354fd4d50146101175780635a84467c14610138575b600080fd5b60408051808201909152600781526629ba30b136329960c91b60208201525b6040516100da9190611a97565b60405180910390f35b6100f66100f1366004611c12565b6101d5565b6040519081526020016100da565b6100f6610112366004611c79565b6104e5565b6040805180820190915260058152640312e312e360dc1b60208201526100cd565b6100f6610146366004611d7f565b610551565b6100f6610159366004611c79565b610b87565b6100f661016c366004611e2c565b610d20565b604080518082019091526002815261299960f11b60208201526100cd565b6101a261019d366004611ece565b6113e4565b6040516100da9190611f02565b6100f66101bd366004611f45565b6114ae565b6101a26101d0366004611f90565b6114ba565b6000826000815181106101ea576101ea612016565b6020026020010151600014801561021b57508260018151811061020f5761020f612016565b60200260200101516000145b15610228575060006104df565b6000610233836113e4565b90506000610241858361155f565b905060006002610271817f0000000000000000000000000000000000000000000000000000000000000000612042565b61027b9190612042565b905060008260018151811061029257610292612016565b6020026020010151836000815181106102ad576102ad612016565b60200260200101516102bf9190612059565b905080945060005b60ff811015610486576000808790506002866000815181106102eb576102eb612016565b60200260200101516102fd9190612042565b6103078983612042565b6103119190612082565b905060028660018151811061032857610328612016565b602002602001015161033a9190612042565b6103448983612042565b61034e9190612082565b9050878161035e60026001612059565b6103689190612042565b60648a610375828a6120a4565b61037f9190612042565b6103899190612082565b6103939190612059565b8961039f600285612042565b60646103ab898b612042565b6103b59190612082565b6103bf9190612059565b6103c99190612042565b6103d39190612082565b985080891115610436576103e7818a6120a4565b60020361041357821561040e576103ff60018a6120a4565b985050505050505050506104df565b600192505b600161041f828b6120a4565b116104315750505050505050506104df565b61047b565b61044089826120a4565b60020361045d578215610458576103ff896001612059565b600192505b60016104698a836120a4565b1161047b5750505050505050506104df565b5050506001016102c7565b5060405162461bcd60e51b815260206004820152602260248201527f4e6f6e20636f6e76657267656e63653a2063616c634c70546f6b656e537570706044820152616c7960f01b60648201526084015b60405180910390fd5b92915050565b6000806104f1836113e4565b905060006104ff878361155f565b60408051601260208201819052918101919091529091506000906105379083906060015b6040516020818303038152906040526101d5565b905061054582888884611671565b98975050505050505050565b60008086600114610563576001610566565b60005b60ff16905060006105ac85858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506113e492505050565b905060006105ee8b8b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525086925061155f915050565b90506105f8611a2b565b60006106388a8a8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525088925061155f915050565b9050808b8151811061064c5761064c612016565b6020026020010151620f424082878151811061066a5761066a612016565b602002602001015161067c9190612042565b6106869190612082565b808352604051630a9028c960e41b815260048101919091527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a9028c909060240160e060405180830381865afa1580156106ef573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061071391906120b7565b6080830181905260600151825161072a919061176b565b608083015151835161073c919061176b565b11156107b757816080015160c00151826080015160a0015184878151811061076657610766612016565b60200260200101516107789190612042565b6107829190612082565b838c8151811061079457610794612016565b602002602001018181525050816080015160600151826020018181525050610823565b816080015160c001518260800151604001518487815181106107db576107db612016565b60200260200101516107ed9190612042565b6107f79190612082565b838c8151811061080957610809612016565b602090810291909101810191909152608083015151908301525b608082015160a081015160409091015161083d90826120a4565b848d8151811061084f5761084f612016565b60200260200101516108619190612042565b61086b9190612082565b606083015260005b60ff811015610b1e5761089f83858e8151811061089257610892612016565b60200260200101516117e2565b848d815181106108b1576108b1612016565b6020026020010181815250506108fa84878e6012806040516020016108e692919060ff92831681529116602082015260400190565b6040516020818303038152906040526104e5565b604084018190528351108015610914575060208301518351115b156109855783868151811061092b5761092b612016565b6020026020010151848d8151811061094557610945612016565b6020026020010151670de0b6b3a76400006109609190612042565b61096a9190612082565b60808401805160409081019290925290840151905152610a0c565b8251604084015110801561099d575060208301518351105b15610a0c578386815181106109b4576109b4612016565b6020026020010151848d815181106109ce576109ce612016565b6020026020010151670de0b6b3a76400006109e99190612042565b6109f39190612082565b60808401805160a0019190915260408401519051606001525b608083015160a0810151604090910151610a2690826120a4565b858e81518110610a3857610a38612016565b6020026020010151610a4a9190612042565b610a549190612082565b606084015260408301516020840181905283511015610aec5782516020840151600a91610a80916120a4565b11610ae757848c81518110610a9757610a97612016565b60200260200101516012610aab91906120a4565b610ab690600a612225565b848d81518110610ac857610ac8612016565b6020026020010151610ada9190612082565b9650505050505050610b7c565b610b16565b60208301518351600a91610aff916120a4565b11610b1657848c81518110610a9757610a97612016565b600101610873565b5060405162461bcd60e51b815260206004820152602c60248201527f4e6f6e20636f6e76657267656e63653a2063616c63526573657276654174526160448201526b74696f4c697175696469747960a01b60648201526084016104d6565b979650505050505050565b600080610b93836113e4565b90506000610ba1878361155f565b9050600080610c196002610bd5817f0000000000000000000000000000000000000000000000000000000000000000612042565b610bdf9190612042565b888a15610c065785600081518110610bf957610bf9612016565b602002602001015161188f565b85600181518110610bf957610bf9612016565b915091508694506000805b60ff811015610ccf57869150610c3c8784868c611909565b965081871115610ca4576001610c5283896120a4565b11610c9f57858a81518110610c6957610c69612016565b60200260200101516012610c7d91906120a4565b610c8890600a612225565b610c929088612082565b9650505050505050610d18565b610cc7565b6001610cb088846120a4565b11610cc757858a81518110610c6957610c69612016565b600101610c24565b5060405162461bcd60e51b815260206004820152601c60248201527f4e6f6e20636f6e76657267656e63653a2063616c63526573657276650000000060448201526064016104d6565b949350505050565b60008085600114610d32576001610d35565b60005b60ff1690506000610d7b85858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506113e492505050565b90506000610d89898361155f565b9050610d93611a2b565b6000610d9f898561155f565b9050808a81518110610db357610db3612016565b6020026020010151620f4240828781518110610dd157610dd1612016565b6020026020010151610de39190612042565b610ded9190612082565b80835260405163958581e560e01b815260048101919091527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063958581e59060240160e060405180830381865afa158015610e56573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e7a91906120b7565b60808301526040805160126020820181905291810191909152600090610ea4908590606001610523565b90506000610eb3600283612082565b9050610ecb846080015160600151856000015161176b565b6080850151518551610edd919061176b565b1115610f7b5760808085015160c0810151910151610efb9083612042565b610f059190612082565b858881518110610f1757610f17612016565b6020908102919091010152608084015160c081015160a090910151610f3c9083612042565b610f469190612082565b858d81518110610f5857610f58612016565b60200260200101818152505083608001516060015184602001818152505061100c565b608084015160c0810151602090910151610f959083612042565b610f9f9190612082565b858881518110610fb157610fb1612016565b6020908102919091010152608084015160c0810151604090910151610fd69083612042565b610fe09190612082565b858d81518110610ff257610ff2612016565b602090810291909101810191909152608085015151908501525b608084015160a081015160409091015161102690826120a4565b868e8151811061103857611038612016565b602002602001015161104a9190612042565b6110549190612082565b606085015260005b60ff8110156113825761107b85878f8151811061089257610892612016565b868e8151811061108d5761108d612016565b6020026020010181815250506110d68689856012806040516020016110c292919060ff92831681529116602082015260400190565b604051602081830303815290604052610b87565b8689815181106110e8576110e8612016565b60200260200101818152505061110086898f86611671565b60408601819052602086015110801561111d575084516040860151115b156111b85781868e8151811061113557611135612016565b6020026020010151670de0b6b3a76400006111509190612042565b61115a9190612082565b6080860151604001528551829087908a90811061117957611179612016565b6020026020010151670de0b6b3a76400006111949190612042565b61119e9190612082565b60808601805160200191909152604086015190515261126e565b846020015185604001511080156111d3575084516040860151105b1561126e5781868e815181106111eb576111eb612016565b6020026020010151670de0b6b3a76400006112069190612042565b6112109190612082565b608086015160a001528551829087908a90811061122f5761122f612016565b6020026020010151670de0b6b3a764000061124a9190612042565b6112549190612082565b608080870180519091019190915260408601519051606001525b608085015160a081015160409091015161128890826120a4565b878f8151811061129a5761129a612016565b60200260200101516112ac9190612042565b6112b69190612082565b6060860152604085015160208601819052855110156113505784516020860151600a916112e2916120a4565b1161134b57868d815181106112f9576112f9612016565b6020026020010151601261130d91906120a4565b61131890600a612225565b868e8151811061132a5761132a612016565b602002602001015161133c9190612082565b985050505050505050506113db565b61137a565b60208501518551600a91611363916120a4565b1161137a57868d815181106112f9576112f9612016565b60010161105c565b5060405162461bcd60e51b815260206004820152602760248201527f4e6f6e20636f6e76657267656e63653a2063616c635265736572766541745261604482015266074696f537761760cc1b60648201526084016104d6565b95945050505050565b6060600080838060200190518101906113fd9190612231565b915091508160000361140e57601291505b8060000361141a575060125b60128211806114295750601281115b156114475760405163686d360760e01b815260040160405180910390fd5b6040805160028082526060820183529091602083019080368337019050509250818360008151811061147b5761147b612016565b602002602001018181525050808360018151811061149b5761149b612016565b6020026020010181815250505050919050565b620f42405b9392505050565b6040805160028082526060808301845292602083019080368337019050509050611501868660008181106114f0576114f0612016565b8a9260209091020135905086611941565b8160008151811061151457611514612016565b602002602001018181525050611536868660018181106114f0576114f0612016565b8160018151811061154957611549612016565b6020026020010181815250509695505050505050565b60408051600280825260608083018452926020830190803683370190505090508160008151811061159257611592612016565b602002602001015160126115a691906120a4565b6115b190600a612225565b836000815181106115c4576115c4612016565b60200260200101516115d69190612042565b816000815181106115e9576115e9612016565b6020026020010181815250508160018151811061160857611608612016565b6020026020010151601261161c91906120a4565b61162790600a612225565b8360018151811061163a5761163a612016565b602002602001015161164c9190612042565b8160018151811061165f5761165f612016565b60200260200101818152505092915050565b604080516002808252606082018352600092839291906020830190803683370190505090508585815181106116a8576116a8612016565b60200260200101518186815181106116c2576116c2612016565b602002602001018181525050620f42408685815181106116e4576116e4612016565b60200260200101516116f69190612059565b81858151811061170857611708612016565b60200260200101818152505061173d8186856012806040516020016110c292919060ff92831681529116602082015260400190565b81868151811061174f5761174f612016565b602002602001015161176191906120a4565b9695505050505050565b600081830361177c575060006104df565b60008284116117945761178f84846120a4565b61179e565b61179e83856120a4565b9050600060026117ae8587612059565b6117b89190612082565b9050806117c6836064612042565b6117d890670de0b6b3a7640000612042565b6113db9190612082565b60008260200151836000015111156118455760808301516060810151905161180a91906120a4565b6020840151845161181b91906120a4565b846060015161182a9190612042565b6118349190612082565b61183e90836120a4565b90506104df565b60808301516060810151905161185b91906120a4565b8351602085015161186c91906120a4565b846060015161187b9190612042565b6118859190612082565b61183e9083612059565b60008061189d600286612042565b6064856118ab600287612042565b6118b58880612042565b6118bf9190612082565b6118c99190612042565b6118d39190612042565b6118dd9190612082565b9150846118eb606486612042565b6118f59190612082565b6118ff9084612059565b9050935093915050565b60008184611918876002612042565b6119229190612059565b61192c91906120a4565b836119378780612042565b6117d89190612059565b600080806000198587098587029250828110838203039150508060000361197b578382816119715761197161206c565b04925050506114b3565b8084116119c25760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016104d6565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b6040518060a0016040528060008152602001600081526020016000815260200160008152602001611a926040518060e00160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b905290565b602081526000825180602084015260005b81811015611ac55760208186018101516040868401015201611aa8565b506000604082850101526040601f19601f83011684010191505092915050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715611b2357611b23611ae5565b604052919050565b600082601f830112611b3c57600080fd5b81356001600160401b03811115611b5557611b55611ae5565b8060051b611b6560208201611afb565b91825260208185018101929081019086841115611b8157600080fd5b6020860192505b83831015611761578235825260209283019290910190611b88565b600082601f830112611bb457600080fd5b81356001600160401b03811115611bcd57611bcd611ae5565b611be0601f8201601f1916602001611afb565b818152846020838601011115611bf557600080fd5b816020850160208301376000918101602001919091529392505050565b60008060408385031215611c2557600080fd5b82356001600160401b03811115611c3b57600080fd5b611c4785828601611b2b565b92505060208301356001600160401b03811115611c6357600080fd5b611c6f85828601611ba3565b9150509250929050565b60008060008060808587031215611c8f57600080fd5b84356001600160401b03811115611ca557600080fd5b611cb187828801611b2b565b945050602085013592506040850135915060608501356001600160401b03811115611cdb57600080fd5b611ce787828801611ba3565b91505092959194509250565b60008083601f840112611d0557600080fd5b5081356001600160401b03811115611d1c57600080fd5b6020830191508360208260051b8501011115611d3757600080fd5b9250929050565b60008083601f840112611d5057600080fd5b5081356001600160401b03811115611d6757600080fd5b602083019150836020828501011115611d3757600080fd5b60008060008060008060006080888a031215611d9a57600080fd5b87356001600160401b03811115611db057600080fd5b611dbc8a828b01611cf3565b9098509650506020880135945060408801356001600160401b03811115611de257600080fd5b611dee8a828b01611cf3565b90955093505060608801356001600160401b03811115611e0d57600080fd5b611e198a828b01611d3e565b989b979a50959850939692959293505050565b600080600080600060808688031215611e4457600080fd5b85356001600160401b03811115611e5a57600080fd5b611e6688828901611b2b565b9550506020860135935060408601356001600160401b03811115611e8957600080fd5b611e9588828901611b2b565b93505060608601356001600160401b03811115611eb157600080fd5b611ebd88828901611d3e565b969995985093965092949392505050565b600060208284031215611ee057600080fd5b81356001600160401b03811115611ef657600080fd5b610d1884828501611ba3565b602080825282518282018190526000918401906040840190835b81811015611f3a578351835260209384019390920191600101611f1c565b509095945050505050565b600080600060408486031215611f5a57600080fd5b8335925060208401356001600160401b03811115611f7757600080fd5b611f8386828701611d3e565b9497909650939450505050565b60008060008060008060808789031215611fa957600080fd5b8635955060208701356001600160401b03811115611fc657600080fd5b611fd289828a01611cf3565b9096509450506040870135925060608701356001600160401b03811115611ff857600080fd5b61200489828a01611d3e565b979a9699509497509295939492505050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176104df576104df61202c565b808201808211156104df576104df61202c565b634e487b7160e01b600052601260045260246000fd5b60008261209f57634e487b7160e01b600052601260045260246000fd5b500490565b818103818111156104df576104df61202c565b600060e08284031280156120ca57600080fd5b5060405160009060e081016001600160401b03811182821017156120f0576120f0611ae5565b604090815284518252602080860151908301528481015190820152606080850151908201526080808501519082015260a0808501519082015260c09384015193810193909352509092915050565b6001815b60018411156121795780850481111561215d5761215d61202c565b600184161561216b57908102905b60019390931c928002612142565b935093915050565b600082612190575060016104df565b8161219d575060006104df565b81600181146121b357600281146121bd576121d9565b60019150506104df565b60ff8411156121ce576121ce61202c565b50506001821b6104df565b5060208310610133831016604e8410600b84101617156121fc575081810a6104df565b612209600019848461213e565b806000190482111561221d5761221d61202c565b029392505050565b60006114b38383612181565b6000806040838503121561224457600080fd5b50508051602090910151909290915056fea2646970667358221220cfe4388fe2d77062c4ef77da9a3148be16e4200f959eb1c57626d8e2723c7c2a64736f6c634300081a0033000000000000000000000000ba51055dad14d3920e1798d2e8a152d91cadb461
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106100a95760003560e01c80637f35e83d116100715780637f35e83d1461014b57806380be8c981461015e57806395d89b4114610171578063a11686b81461018f578063b1d35841146101af578063bf66642a146101c257600080fd5b806306fdde03146100ae57806314c15fc0146100e35780632b227ea91461010457806354fd4d50146101175780635a84467c14610138575b600080fd5b60408051808201909152600781526629ba30b136329960c91b60208201525b6040516100da9190611a97565b60405180910390f35b6100f66100f1366004611c12565b6101d5565b6040519081526020016100da565b6100f6610112366004611c79565b6104e5565b6040805180820190915260058152640312e312e360dc1b60208201526100cd565b6100f6610146366004611d7f565b610551565b6100f6610159366004611c79565b610b87565b6100f661016c366004611e2c565b610d20565b604080518082019091526002815261299960f11b60208201526100cd565b6101a261019d366004611ece565b6113e4565b6040516100da9190611f02565b6100f66101bd366004611f45565b6114ae565b6101a26101d0366004611f90565b6114ba565b6000826000815181106101ea576101ea612016565b6020026020010151600014801561021b57508260018151811061020f5761020f612016565b60200260200101516000145b15610228575060006104df565b6000610233836113e4565b90506000610241858361155f565b905060006002610271817f0000000000000000000000000000000000000000000000000000000000000064612042565b61027b9190612042565b905060008260018151811061029257610292612016565b6020026020010151836000815181106102ad576102ad612016565b60200260200101516102bf9190612059565b905080945060005b60ff811015610486576000808790506002866000815181106102eb576102eb612016565b60200260200101516102fd9190612042565b6103078983612042565b6103119190612082565b905060028660018151811061032857610328612016565b602002602001015161033a9190612042565b6103448983612042565b61034e9190612082565b9050878161035e60026001612059565b6103689190612042565b60648a610375828a6120a4565b61037f9190612042565b6103899190612082565b6103939190612059565b8961039f600285612042565b60646103ab898b612042565b6103b59190612082565b6103bf9190612059565b6103c99190612042565b6103d39190612082565b985080891115610436576103e7818a6120a4565b60020361041357821561040e576103ff60018a6120a4565b985050505050505050506104df565b600192505b600161041f828b6120a4565b116104315750505050505050506104df565b61047b565b61044089826120a4565b60020361045d578215610458576103ff896001612059565b600192505b60016104698a836120a4565b1161047b5750505050505050506104df565b5050506001016102c7565b5060405162461bcd60e51b815260206004820152602260248201527f4e6f6e20636f6e76657267656e63653a2063616c634c70546f6b656e537570706044820152616c7960f01b60648201526084015b60405180910390fd5b92915050565b6000806104f1836113e4565b905060006104ff878361155f565b60408051601260208201819052918101919091529091506000906105379083906060015b6040516020818303038152906040526101d5565b905061054582888884611671565b98975050505050505050565b60008086600114610563576001610566565b60005b60ff16905060006105ac85858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506113e492505050565b905060006105ee8b8b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525086925061155f915050565b90506105f8611a2b565b60006106388a8a8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525088925061155f915050565b9050808b8151811061064c5761064c612016565b6020026020010151620f424082878151811061066a5761066a612016565b602002602001015161067c9190612042565b6106869190612082565b808352604051630a9028c960e41b815260048101919091527f000000000000000000000000ba51055dad14d3920e1798d2e8a152d91cadb4616001600160a01b03169063a9028c909060240160e060405180830381865afa1580156106ef573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061071391906120b7565b6080830181905260600151825161072a919061176b565b608083015151835161073c919061176b565b11156107b757816080015160c00151826080015160a0015184878151811061076657610766612016565b60200260200101516107789190612042565b6107829190612082565b838c8151811061079457610794612016565b602002602001018181525050816080015160600151826020018181525050610823565b816080015160c001518260800151604001518487815181106107db576107db612016565b60200260200101516107ed9190612042565b6107f79190612082565b838c8151811061080957610809612016565b602090810291909101810191909152608083015151908301525b608082015160a081015160409091015161083d90826120a4565b848d8151811061084f5761084f612016565b60200260200101516108619190612042565b61086b9190612082565b606083015260005b60ff811015610b1e5761089f83858e8151811061089257610892612016565b60200260200101516117e2565b848d815181106108b1576108b1612016565b6020026020010181815250506108fa84878e6012806040516020016108e692919060ff92831681529116602082015260400190565b6040516020818303038152906040526104e5565b604084018190528351108015610914575060208301518351115b156109855783868151811061092b5761092b612016565b6020026020010151848d8151811061094557610945612016565b6020026020010151670de0b6b3a76400006109609190612042565b61096a9190612082565b60808401805160409081019290925290840151905152610a0c565b8251604084015110801561099d575060208301518351105b15610a0c578386815181106109b4576109b4612016565b6020026020010151848d815181106109ce576109ce612016565b6020026020010151670de0b6b3a76400006109e99190612042565b6109f39190612082565b60808401805160a0019190915260408401519051606001525b608083015160a0810151604090910151610a2690826120a4565b858e81518110610a3857610a38612016565b6020026020010151610a4a9190612042565b610a549190612082565b606084015260408301516020840181905283511015610aec5782516020840151600a91610a80916120a4565b11610ae757848c81518110610a9757610a97612016565b60200260200101516012610aab91906120a4565b610ab690600a612225565b848d81518110610ac857610ac8612016565b6020026020010151610ada9190612082565b9650505050505050610b7c565b610b16565b60208301518351600a91610aff916120a4565b11610b1657848c81518110610a9757610a97612016565b600101610873565b5060405162461bcd60e51b815260206004820152602c60248201527f4e6f6e20636f6e76657267656e63653a2063616c63526573657276654174526160448201526b74696f4c697175696469747960a01b60648201526084016104d6565b979650505050505050565b600080610b93836113e4565b90506000610ba1878361155f565b9050600080610c196002610bd5817f0000000000000000000000000000000000000000000000000000000000000064612042565b610bdf9190612042565b888a15610c065785600081518110610bf957610bf9612016565b602002602001015161188f565b85600181518110610bf957610bf9612016565b915091508694506000805b60ff811015610ccf57869150610c3c8784868c611909565b965081871115610ca4576001610c5283896120a4565b11610c9f57858a81518110610c6957610c69612016565b60200260200101516012610c7d91906120a4565b610c8890600a612225565b610c929088612082565b9650505050505050610d18565b610cc7565b6001610cb088846120a4565b11610cc757858a81518110610c6957610c69612016565b600101610c24565b5060405162461bcd60e51b815260206004820152601c60248201527f4e6f6e20636f6e76657267656e63653a2063616c63526573657276650000000060448201526064016104d6565b949350505050565b60008085600114610d32576001610d35565b60005b60ff1690506000610d7b85858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506113e492505050565b90506000610d89898361155f565b9050610d93611a2b565b6000610d9f898561155f565b9050808a81518110610db357610db3612016565b6020026020010151620f4240828781518110610dd157610dd1612016565b6020026020010151610de39190612042565b610ded9190612082565b80835260405163958581e560e01b815260048101919091527f000000000000000000000000ba51055dad14d3920e1798d2e8a152d91cadb4616001600160a01b03169063958581e59060240160e060405180830381865afa158015610e56573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e7a91906120b7565b60808301526040805160126020820181905291810191909152600090610ea4908590606001610523565b90506000610eb3600283612082565b9050610ecb846080015160600151856000015161176b565b6080850151518551610edd919061176b565b1115610f7b5760808085015160c0810151910151610efb9083612042565b610f059190612082565b858881518110610f1757610f17612016565b6020908102919091010152608084015160c081015160a090910151610f3c9083612042565b610f469190612082565b858d81518110610f5857610f58612016565b60200260200101818152505083608001516060015184602001818152505061100c565b608084015160c0810151602090910151610f959083612042565b610f9f9190612082565b858881518110610fb157610fb1612016565b6020908102919091010152608084015160c0810151604090910151610fd69083612042565b610fe09190612082565b858d81518110610ff257610ff2612016565b602090810291909101810191909152608085015151908501525b608084015160a081015160409091015161102690826120a4565b868e8151811061103857611038612016565b602002602001015161104a9190612042565b6110549190612082565b606085015260005b60ff8110156113825761107b85878f8151811061089257610892612016565b868e8151811061108d5761108d612016565b6020026020010181815250506110d68689856012806040516020016110c292919060ff92831681529116602082015260400190565b604051602081830303815290604052610b87565b8689815181106110e8576110e8612016565b60200260200101818152505061110086898f86611671565b60408601819052602086015110801561111d575084516040860151115b156111b85781868e8151811061113557611135612016565b6020026020010151670de0b6b3a76400006111509190612042565b61115a9190612082565b6080860151604001528551829087908a90811061117957611179612016565b6020026020010151670de0b6b3a76400006111949190612042565b61119e9190612082565b60808601805160200191909152604086015190515261126e565b846020015185604001511080156111d3575084516040860151105b1561126e5781868e815181106111eb576111eb612016565b6020026020010151670de0b6b3a76400006112069190612042565b6112109190612082565b608086015160a001528551829087908a90811061122f5761122f612016565b6020026020010151670de0b6b3a764000061124a9190612042565b6112549190612082565b608080870180519091019190915260408601519051606001525b608085015160a081015160409091015161128890826120a4565b878f8151811061129a5761129a612016565b60200260200101516112ac9190612042565b6112b69190612082565b6060860152604085015160208601819052855110156113505784516020860151600a916112e2916120a4565b1161134b57868d815181106112f9576112f9612016565b6020026020010151601261130d91906120a4565b61131890600a612225565b868e8151811061132a5761132a612016565b602002602001015161133c9190612082565b985050505050505050506113db565b61137a565b60208501518551600a91611363916120a4565b1161137a57868d815181106112f9576112f9612016565b60010161105c565b5060405162461bcd60e51b815260206004820152602760248201527f4e6f6e20636f6e76657267656e63653a2063616c635265736572766541745261604482015266074696f537761760cc1b60648201526084016104d6565b95945050505050565b6060600080838060200190518101906113fd9190612231565b915091508160000361140e57601291505b8060000361141a575060125b60128211806114295750601281115b156114475760405163686d360760e01b815260040160405180910390fd5b6040805160028082526060820183529091602083019080368337019050509250818360008151811061147b5761147b612016565b602002602001018181525050808360018151811061149b5761149b612016565b6020026020010181815250505050919050565b620f42405b9392505050565b6040805160028082526060808301845292602083019080368337019050509050611501868660008181106114f0576114f0612016565b8a9260209091020135905086611941565b8160008151811061151457611514612016565b602002602001018181525050611536868660018181106114f0576114f0612016565b8160018151811061154957611549612016565b6020026020010181815250509695505050505050565b60408051600280825260608083018452926020830190803683370190505090508160008151811061159257611592612016565b602002602001015160126115a691906120a4565b6115b190600a612225565b836000815181106115c4576115c4612016565b60200260200101516115d69190612042565b816000815181106115e9576115e9612016565b6020026020010181815250508160018151811061160857611608612016565b6020026020010151601261161c91906120a4565b61162790600a612225565b8360018151811061163a5761163a612016565b602002602001015161164c9190612042565b8160018151811061165f5761165f612016565b60200260200101818152505092915050565b604080516002808252606082018352600092839291906020830190803683370190505090508585815181106116a8576116a8612016565b60200260200101518186815181106116c2576116c2612016565b602002602001018181525050620f42408685815181106116e4576116e4612016565b60200260200101516116f69190612059565b81858151811061170857611708612016565b60200260200101818152505061173d8186856012806040516020016110c292919060ff92831681529116602082015260400190565b81868151811061174f5761174f612016565b602002602001015161176191906120a4565b9695505050505050565b600081830361177c575060006104df565b60008284116117945761178f84846120a4565b61179e565b61179e83856120a4565b9050600060026117ae8587612059565b6117b89190612082565b9050806117c6836064612042565b6117d890670de0b6b3a7640000612042565b6113db9190612082565b60008260200151836000015111156118455760808301516060810151905161180a91906120a4565b6020840151845161181b91906120a4565b846060015161182a9190612042565b6118349190612082565b61183e90836120a4565b90506104df565b60808301516060810151905161185b91906120a4565b8351602085015161186c91906120a4565b846060015161187b9190612042565b6118859190612082565b61183e9083612059565b60008061189d600286612042565b6064856118ab600287612042565b6118b58880612042565b6118bf9190612082565b6118c99190612042565b6118d39190612042565b6118dd9190612082565b9150846118eb606486612042565b6118f59190612082565b6118ff9084612059565b9050935093915050565b60008184611918876002612042565b6119229190612059565b61192c91906120a4565b836119378780612042565b6117d89190612059565b600080806000198587098587029250828110838203039150508060000361197b578382816119715761197161206c565b04925050506114b3565b8084116119c25760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016104d6565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b6040518060a0016040528060008152602001600081526020016000815260200160008152602001611a926040518060e00160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b905290565b602081526000825180602084015260005b81811015611ac55760208186018101516040868401015201611aa8565b506000604082850101526040601f19601f83011684010191505092915050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715611b2357611b23611ae5565b604052919050565b600082601f830112611b3c57600080fd5b81356001600160401b03811115611b5557611b55611ae5565b8060051b611b6560208201611afb565b91825260208185018101929081019086841115611b8157600080fd5b6020860192505b83831015611761578235825260209283019290910190611b88565b600082601f830112611bb457600080fd5b81356001600160401b03811115611bcd57611bcd611ae5565b611be0601f8201601f1916602001611afb565b818152846020838601011115611bf557600080fd5b816020850160208301376000918101602001919091529392505050565b60008060408385031215611c2557600080fd5b82356001600160401b03811115611c3b57600080fd5b611c4785828601611b2b565b92505060208301356001600160401b03811115611c6357600080fd5b611c6f85828601611ba3565b9150509250929050565b60008060008060808587031215611c8f57600080fd5b84356001600160401b03811115611ca557600080fd5b611cb187828801611b2b565b945050602085013592506040850135915060608501356001600160401b03811115611cdb57600080fd5b611ce787828801611ba3565b91505092959194509250565b60008083601f840112611d0557600080fd5b5081356001600160401b03811115611d1c57600080fd5b6020830191508360208260051b8501011115611d3757600080fd5b9250929050565b60008083601f840112611d5057600080fd5b5081356001600160401b03811115611d6757600080fd5b602083019150836020828501011115611d3757600080fd5b60008060008060008060006080888a031215611d9a57600080fd5b87356001600160401b03811115611db057600080fd5b611dbc8a828b01611cf3565b9098509650506020880135945060408801356001600160401b03811115611de257600080fd5b611dee8a828b01611cf3565b90955093505060608801356001600160401b03811115611e0d57600080fd5b611e198a828b01611d3e565b989b979a50959850939692959293505050565b600080600080600060808688031215611e4457600080fd5b85356001600160401b03811115611e5a57600080fd5b611e6688828901611b2b565b9550506020860135935060408601356001600160401b03811115611e8957600080fd5b611e9588828901611b2b565b93505060608601356001600160401b03811115611eb157600080fd5b611ebd88828901611d3e565b969995985093965092949392505050565b600060208284031215611ee057600080fd5b81356001600160401b03811115611ef657600080fd5b610d1884828501611ba3565b602080825282518282018190526000918401906040840190835b81811015611f3a578351835260209384019390920191600101611f1c565b509095945050505050565b600080600060408486031215611f5a57600080fd5b8335925060208401356001600160401b03811115611f7757600080fd5b611f8386828701611d3e565b9497909650939450505050565b60008060008060008060808789031215611fa957600080fd5b8635955060208701356001600160401b03811115611fc657600080fd5b611fd289828a01611cf3565b9096509450506040870135925060608701356001600160401b03811115611ff857600080fd5b61200489828a01611d3e565b979a9699509497509295939492505050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176104df576104df61202c565b808201808211156104df576104df61202c565b634e487b7160e01b600052601260045260246000fd5b60008261209f57634e487b7160e01b600052601260045260246000fd5b500490565b818103818111156104df576104df61202c565b600060e08284031280156120ca57600080fd5b5060405160009060e081016001600160401b03811182821017156120f0576120f0611ae5565b604090815284518252602080860151908301528481015190820152606080850151908201526080808501519082015260a0808501519082015260c09384015193810193909352509092915050565b6001815b60018411156121795780850481111561215d5761215d61202c565b600184161561216b57908102905b60019390931c928002612142565b935093915050565b600082612190575060016104df565b8161219d575060006104df565b81600181146121b357600281146121bd576121d9565b60019150506104df565b60ff8411156121ce576121ce61202c565b50506001821b6104df565b5060208310610133831016604e8410600b84101617156121fc575081810a6104df565b612209600019848461213e565b806000190482111561221d5761221d61202c565b029392505050565b60006114b38383612181565b6000806040838503121561224457600080fd5b50508051602090910151909290915056fea2646970667358221220cfe4388fe2d77062c4ef77da9a3148be16e4200f959eb1c57626d8e2723c7c2a64736f6c634300081a0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000BA51055dAD14d3920e1798D2e8A152d91CaDb461
-----Decoded View---------------
Arg [0] : lut (address): 0xBA51055dAD14d3920e1798D2e8A152d91CaDb461
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000BA51055dAD14d3920e1798D2e8A152d91CaDb461
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
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.