Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00More Info
Private Name Tags
ContractCreator
TokenTracker
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 3696522 | 615 days ago | Contract Creation | 0 ETH |
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
CatalystVaultAmplified
Compiler Version
v0.8.22+commit.4fc1097e
Contract Source Code (Solidity Standard Json-Input format)
//SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.19;
import { ERC20 } from 'solady/tokens/ERC20.sol';
import { SafeTransferLib } from 'solady/utils/SafeTransferLib.sol';
import { FixedPointMathLib } from "solady/utils/FixedPointMathLib.sol";
import { ICatalystChainInterface } from "./interfaces/ICatalystChainInterface.sol";
import { WADWAD } from "./utils/MathConstants.sol";
import { CatalystVaultCommon } from "./CatalystVaultCommon.sol";
import { IntegralsAmplified } from "./IntegralsAmplified.sol";
import { ICatalystReceiver} from "./interfaces/IOnCatalyst.sol";
import "./ICatalystV1Vault.sol";
/**
* @title Catalyst: Fixed rate cross-chain swap vault.
* @author Cata Labs Inc.
* @notice Catalyst multi-chain vault using the asset specific
* pricing curve: 1/w^\theta (1 - \theta) where \theta is
* the vault amplification and w is the vault asset balance.
*
* The following contract supports between 1 and 3 assets for
* atomic swaps. To increase the number of tokens supported,
* change MAX_ASSETS to the desired maximum token amount.
* This constant is set in "CatalystVaultCommon.sol"
*
* This vault implements the ERC20 specification, such that the
* contract will be its own vault token.
* @dev This contract is deployed inactive: It cannot be used as a
* vault as is. To use it, a proxy contract duplicating the
* logic of this contract needs to be deployed. In Vyper, this
* can be done through (vy >= 0.3.4) create_minimal_proxy_to.
* In Solidity, this can be done through OZ clones: Clones.clone(...)
* After deployment of the proxy, call setup(...) AND initializeSwapCurves(...).
* This will initialize the vault and prepare it for cross-chain transactions.
* However, only the Catalyst factory is allowed to perform these functions.
* It is important that both setup(...) AND initializeSwapCurves(...) are called
* in the same transaciton, as otherwise the vault is not fully finalised and
* may be configured incorrectly by a third-party.
*
* If connected to a supported cross-chain interface, call
* setConnection to connect the vault with vaults on other chains.
*
* Finally, call finishSetup to give up the creator's control over the vault.
* !If finishSetup is not called, the vault can be drained by the creator!
*/
contract CatalystVaultAmplified is CatalystVaultCommon, IntegralsAmplified {
//--- Storage ---//
/**
* @notice Adjustment used to remove a certain escrow amount from the balance * computation
*/
mapping(address => uint256) public _underwriteEscrowMatchBalance0;
//--- ERRORS ---//
// Errors are defined in interfaces/ICatalystV1VaultErrors.sol
//--- Config ---//
/** @notice Minimum time parameter adjustments can be made over. */
uint256 constant MIN_ADJUSTMENT_TIME = 7 days;
/**
* @dev When the swap is a very small size of the vault, the
* swaps returns slightly more. To counteract this, an additional
* fee slightly larger than the error is added. The below
* constants determines when this fee is added and the size.
*/
uint256 constant SMALL_SWAP_RATIO = 1e12;
uint256 constant SMALL_SWAP_RETURN = 95e16;
// For other config options, see CatalystVaultCommon.sol
//-- Variables --//
int64 public _oneMinusAmp;
int64 public _targetAmplification;
/**
* @dev To keep track of pool ownership, the vault needs to keep track of
* the local unit balance. That is, do other vaults own or owe assets to this vault?
*/
int256 public _unitTracker;
constructor(address factory_, address mathlib_) payable CatalystVaultCommon(factory_, mathlib_) {}
/**
* @notice Configures an empty vault.
* @dev The initial token amounts should have been sent to the vault before setup is called.
* Since someone can call setup can claim the initial tokens, this needs to be
* done atomically!
*
* If 0 of a token in assets is provided, the setup reverts.
* @param assets A list of token addresses to be associated with the vault.
* @param weights Weights brings the price into a true 1:1 swap. That is:
* i_t \cdot W_i = j_t \cdot W_j \forall i, j when P_i(i_t) = P_j(j_t).
* in other words, weights are used to compensate for the difference in decimals. (or non 1:1.)
* @param amp Amplification factor. Should be < 10**18.
* @param depositor The address to mint tokens to.
*/
function initializeSwapCurves(
address[] calldata assets,
uint256[] calldata weights,
uint64 amp,
address depositor
) external override {
// May only be invoked by the FACTORY. The factory only invokes this function for proxy contracts.
require(msg.sender == FACTORY); // dev: swap curves may only be initialized once by the factory
require(_tokenIndexing[0] == address(0)); // dev: swap curves may only be initialized once by the factory
// Check that the amplification is correct.
require(amp < FixedPointMathLib.WAD); // dev: amplification not set correctly.
// Note there is no need to check whether assets.length/weights.length are valid, as invalid arguments
// will either cause the function to fail (e.g. if assets.length > MAX_ASSETS the assignment
// to initialBalances[it] will fail) or will cause the vault to get initialized with an undesired state
// (and the vault shouldn't be used by anyone until its configuration has been finalised).
// In any case, the factory does check for valid assets/weights arguments to prevent erroneous configurations.
// Note Since assets.len != 0 is not checked, the initial depositor may invoke this function many times, resulting
// in vault tokens being minted for the 'depositor' every time. This is not an issue, since 'INITIAL_MINT_AMOUNT' is
// an arbitrary number; the value of the vault tokens is determined by the ratio of the vault asset balances and vault
// tokens supply once setup has finalized. Furthermore, the vault should not be used until setup has finished and the
// vault configuration has been verified.
unchecked {
// Amplification is stored as 1 - amp since most equations uses amp this way.
_oneMinusAmp = int64(uint64(FixedPointMathLib.WAD - amp));
_targetAmplification = int64(uint64(FixedPointMathLib.WAD - amp));
}
// Compute the security limit.
uint256[] memory initialBalances = new uint256[](MAX_ASSETS);
uint256 maxUnitCapacity = 0;
uint assetLength = assets.length;
for (uint256 it; it < assetLength;) {
address tokenAddress = assets[it];
_tokenIndexing[it] = tokenAddress;
uint256 weight = weights[it];
require(weight != 0); // dev: invalid 0-valued weight provided
_weight[tokenAddress] = weight;
// The contract expects the tokens to have been sent to it before setup is
// called. Make sure the vault has more than 0 tokens.
// Reverts if tokenAddress is address(0).
// This contract uses safeTransferLib from Solady. When "safeTransfering", there is no
// check for smart contract code. This could be an issue if non-tokens are allowed to enter
// the pool, as then the pool could be expoited by later deploying an address to the addres.
// The below check ensure that there is a token deployed to the contract.
uint256 balanceOfSelf = ERC20(tokenAddress).balanceOf(address(this));
require(balanceOfSelf != 0); // dev: 0 tokens provided in setup.
initialBalances[it] = balanceOfSelf;
maxUnitCapacity += weight * balanceOfSelf;
unchecked {
++it;
}
}
// The security limit is implemented as being 50% of the current balance.
// Since the security limit is evaluated after balance changes, the limit in
// storage should be the current balance.
_maxUnitCapacity = maxUnitCapacity;
// Mint vault tokens to the vault creator.
_mint(depositor, INITIAL_MINT_AMOUNT);
emit VaultDeposit(depositor, INITIAL_MINT_AMOUNT, initialBalances);
}
/**
* @notice Returns the current cross-chain swap capacity.
* @dev Overwrites the common implementation because of the
* differences as to how it is used. As a result, this always returns
* half of the common implementation (or of _maxUnitCapacity)
*/
function getUnitCapacity() public view override returns (uint256) {
return super.getUnitCapacity() >> 1; // Equal to divide by 2.
}
/**
* @notice Re-computes the security limit incase funds have been sent to the vault.
*/
function updateMaxUnitCapacity() external {
uint256 maxUnitCapacity;
for (uint256 it; it < MAX_ASSETS;) {
address asset = _tokenIndexing[it];
if (asset == address(0)) break;
maxUnitCapacity += (ERC20(asset).balanceOf(address(this)) - _escrowedTokens[asset]) * _weight[asset];
unchecked {
++it;
}
}
_maxUnitCapacity = maxUnitCapacity;
}
//--- Swap integrals ---//
// Inherited from the Integrals file.
/**
* @notice Computes the return of SendAsset excluding fees.
* @dev Reverts if 'fromAsset' is not a token in the vault or if
* 'amount' and the vault asset balance are both 0.
* Does not contain the swap fee.
* @param fromAsset Address of the token to sell.
* @param amount Amount of from token to sell.
* @return uint256 Units.
*/
function calcSendAsset(
address fromAsset,
uint256 amount
) public view override returns (uint256) {
// A high => fewer units returned. Do not subtract the escrow amount
uint256 A = ERC20(fromAsset).balanceOf(address(this));
uint256 W = _weight[fromAsset];
// If 'fromAsset' is not part of the vault (i.e. W is 0) or if 'amount' and
// the vault asset balance (i.e. 'A') are both 0 this will revert, since 0**p is
// implemented as exp(ln(0) * p) and ln(0) is undefined.
uint256 U = _calcPriceCurveArea(amount, A, W, _oneMinusAmp);
// If the swap is a very small portion of the vault add an additional fee. This covers mathematical errors.
unchecked { //SMALL_SWAP_RATIO is not zero, and if U * SMALL_SWAP_RETURN overflows, less is returned to the user.
// Also U * SMALL_SWAP_RETURN cannot overflow, since U depends heavily on amount/A. If this number is small (which it is in this case) then U is also "small".
if (A/SMALL_SWAP_RATIO >= amount) return U * SMALL_SWAP_RETURN / FixedPointMathLib.WAD;
}
return U;
}
/**
* @notice Computes the output of ReceiveAsset excluding fees.
* @dev Reverts if 'toAsset' is not a token in the vault.
* Does not contain the swap fee.
* @param toAsset Address of the token to buy.
* @param U Number of units to convert.
* @return uint256 Ppurchased tokens.
*/
function calcReceiveAsset(
address toAsset,
uint256 U
) public view override returns (uint256) {
// B low => fewer tokens returned. Subtract the escrow amount to decrease the balance.
uint256 B = ERC20(toAsset).balanceOf(address(this)) - _escrowedTokens[toAsset];
uint256 W = _weight[toAsset];
// If someone were to purchase a token that is not part of the vault on setup
// they would just add value to the vault. We don't care about it.
// However, it will revert since the solved integral contains U/W and when
// W = 0 then U/W returns division by 0 error.
return _calcPriceCurveLimit(U, B, W, _oneMinusAmp);
}
/**
* @notice Computes the output of localSwap excluding fees.
* @dev Implemented through _calcCombinedPriceCurves.
* Reverts if either 'fromAsset' or 'toAsset' is not in the vault, or if the vault 'fromAsset'
* balance and 'amount' are both 0.
* Does not contain the swap fee.
* @param fromAsset Address of the token to sell.
* @param toAsset Address of the token to buy.
* @param amount Amount of from token to sell for to token.
* @return output Output denominated in toAsset.
*/
function calcLocalSwap(
address fromAsset,
address toAsset,
uint256 amount
) public view override returns (uint256 output) {
uint256 A = ERC20(fromAsset).balanceOf(address(this));
uint256 B = ERC20(toAsset).balanceOf(address(this)) - _escrowedTokens[toAsset];
uint256 W_A = _weight[fromAsset];
uint256 W_B = _weight[toAsset];
int256 oneMinusAmp = _oneMinusAmp;
output = _calcPriceCurveLimit(_calcPriceCurveArea(amount, A, W_A, oneMinusAmp), B, W_B, oneMinusAmp);
// If the swap is a very small portion of the vault add an additional fee. This covers mathematical errors.
unchecked { //SMALL_SWAP_RATIO is not zero, and if output * SMALL_SWAP_RETURN overflows, less is returned to the user
if (A/SMALL_SWAP_RATIO >= amount) return output * SMALL_SWAP_RETURN / FixedPointMathLib.WAD;
}
}
/**
* @notice Deposits a user-configurable amount of tokens.
* @dev The swap fee is imposed on deposits.
* Requires approvals for all tokens within the vault.
* It is advised that the deposit matches the vault's %token distribution.
* Deposit is done by converting tokenAmounts into units and then using
* the macro for units to vault tokens. (_calcPriceCurveLimitShare).
* The elements of tokenAmounts correspond to _tokenIndexing[0...N].
* @param tokenAmounts Array of the tokens amounts to be deposited.
* @param minOut Minimum number of vault tokens to be minted.
* @return vaultTokens Number of minted vault tokens.
*/
function depositMixed(
uint256[] memory tokenAmounts,
uint256 minOut
) nonReentrant external override returns(uint256 vaultTokens) {
// _updateAmplification();
int256 oneMinusAmp = _oneMinusAmp;
uint256 it_times_walpha_amped;
// There is a Stack too deep issue in a later branch. To counteract this,
// wab is stored short-lived. This requires letting U get negative.
// As such, we define an additional variable called intU which is signed
int256 intU;
// Compute walpha_0 to find the reference balances. This lets us evaluate the
// number of tokens the vault should have If the price in the pool is 1:1.
// walpha_0 is computed several times in this contract:
// - DepositMixed
// - WithdrawMixed
// - WithdrawAll
// - sendLiquidity
// - receiveLiquidity
// Since the implementation is very similar, it could be computed seperatly.
// However, some of the implementations differ notably:
// - DepositMixed: The for loop is reused for computing the value of incoming assets.
// - WithdrawMixed: The for loop is used to cache tokenIndexed, effAssetBalances, and assetWeight.
// - WithdrawAll: The for loop is used to cache tokenIndexed, effWeightAssetBalances.
// - Both sendLiquidity and receiveLiquidity implements the reference computation: computeBalance0().
// Before each implementation, there will be a short comment to describe how the implementation is different.
{
int256 weightedAssetBalanceSum = 0;
uint256 assetDepositSum = 0;
for (uint256 it; it < MAX_ASSETS;) {
address token = _tokenIndexing[it];
if (token == address(0)) break;
uint256 weight = _weight[token];
uint256 tokenAmount = tokenAmounts[it];
{
// Whenever balance0 is computed, the true balance should be used.
uint256 weightAssetBalance = weight * ERC20(token).balanceOf(address(this));
{
// wa^(1-k) is required twice. It is F(A) in the
// sendAsset equation and part of the wa_0^(1-k) calculation.
// If weightAssetBalance == 0, then this computation would fail. However since 0^(1-k) = 0, we can set it to 0.
int256 wab = 0;
if (weightAssetBalance != 0) {
// calculate balance 0 with the underwritten amount subtracted.
wab = FixedPointMathLib.powWad(
int256((weightAssetBalance - _underwriteEscrowMatchBalance0[token] * weight) * FixedPointMathLib.WAD), // If casting overflows to a negative number, powWad fails
oneMinusAmp
);
// if wab == 0, there is no need to add it. So only add if != 0.
weightedAssetBalanceSum += wab;
wab = FixedPointMathLib.powWad(
int256(weightAssetBalance * FixedPointMathLib.WAD), // If casting overflows to a negative number, powWad fails
oneMinusAmp
);
}
// This line is the origin of the stack too deep issue.
// Moving intU += before this section would solve the issue but it is not possible since it would evaluate incorrectly.
// Save gas if the user provides no tokens, as the rest of the loop has no effect in that case
if (tokenAmount == 0) {
unchecked {
++it;
}
continue;
}
// int_A^{A+x} f(w) dw = F(A+x) - F(A).
unchecked {
// This is -F(A). Since we are subtracting first, U (i.e. intU) must be able to go negative.
// |intU| < weightedAssetBalanceSum since F(A+x) is added to intU in the lines after this.
intU -= wab;
}
}
// Add F(A+x).
// This computation will not revert, since we know tokenAmount != 0.
intU += FixedPointMathLib.powWad(
int256((weightAssetBalance + weight * tokenAmount) * FixedPointMathLib.WAD), // If casting overflows to a negative number, powWad fails
oneMinusAmp
);
}
assetDepositSum += tokenAmount * weight;
SafeTransferLib.safeTransferFrom(
token,
msg.sender,
address(this),
tokenAmount
); // dev: Token withdrawal from user failed.
unchecked {
++it;
}
}
// Increase the security limit by the amount deposited.
_maxUnitCapacity += assetDepositSum;
// Short term decrease the security limit by the amount deposited.
// While one may assume _usedUnitCapacity < _maxUnitCapacity, this is not always the case. As such, this remains checked.
_usedUnitCapacity += assetDepositSum;
// Compute the reference liquidity.
// weightedAssetBalanceSum > _unitTracker always, since _unitTracker correlates to exactly
// the difference between weightedAssetBalanceSum and weightedAssetBalance0Sum and thus
// _unitTracker < weightedAssetBalance0Sum
unchecked {
// weightedAssetBalanceSum - _unitTracker can overflow for negative _unitTracker.
// The result will be correct once it is casted to uint256.
it_times_walpha_amped = uint256(weightedAssetBalanceSum - _unitTracker); // By design, weightedAssetBalanceSum > _unitTracker
// Notice that we are not dividing by it. That is because we would then later have to multiply by it.
}
}
// Subtract fee from U (intU). This prevents people from using deposit and withdrawal as a method of swapping.
// To reduce costs, the governance fee is not taken. As a result, swapping through deposit+withdrawal circumvents
// the governance fee. No incentives align for traders to abuse this and is nativly disincentivised by the higher gas cost.
// intU should not be negative. But in the case it is, the result is very bad. For safety, check it is above 0.
require(intU >= 0); // dev: U needs to be positive, otherwise, the uint256 casting becomes too larger.
unchecked {
// U (intU) is generally small, so the below equation should not overflow.
// If it does, it has to be (uint256(intU) * (FixedPointMathLib.WAD - _vaultFee)) that overflows.
// In which case, something close to 0 will be returned. When divided by FixedPointMathLib.WAD
// it will return 0. The casting to int256 is then 0.
intU = int256(
// intU shouldn't be negative but the above check ensures it is ALWAYS positive.
(uint256(intU) * (FixedPointMathLib.WAD - _vaultFee))/FixedPointMathLib.WAD
);
}
int256 oneMinusAmpInverse = WADWAD / oneMinusAmp;
// On totalSupply(). Do not add escrow amount, as higher amount results in a larger return.
vaultTokens = _calcPriceCurveLimitShare(uint256(intU), totalSupply(), it_times_walpha_amped, oneMinusAmpInverse); // uint256: intU is positive by design.
// Check that the minimum output is honoured.
if (minOut > vaultTokens) revert ReturnInsufficient(vaultTokens, minOut);
// Mint the desired number of vault tokens to the user.
_mint(msg.sender, vaultTokens);
// Emit the deposit event
emit VaultDeposit(msg.sender, vaultTokens, tokenAmounts);
}
/**
* @notice Burns vault tokens and releases the symmetrical share of tokens to the burner.
* This can impact the vault prices.
* @dev This is the cheapest way to withdraw and only way to withdraw 100% of the liquidity.
* @param vaultTokens Number of vault tokens to burn.
* @param minOut Minimum token output. If less is returned, the transaction reverts.
* @return amounts Array containing the amounts withdrawn.
*/
function withdrawAll(
uint256 vaultTokens,
uint256[] memory minOut
) nonReentrant external override returns(uint256[] memory amounts) {
// _updateAmplification();
// Burn the desired number of vault tokens to the user.
// If they don't have it, it saves gas.
// * Remember to add vaultTokens when accessing totalSupply()
_burn(msg.sender, vaultTokens);
// (For everyone else, it is probably cheaper to burn last. However, burning here makes
// the implementation more similar to the volatile one)
int256 oneMinusAmp = _oneMinusAmp;
// Cache weights and balances.
address[MAX_ASSETS] memory tokenIndexed;
uint256[MAX_ASSETS] memory effWeightAssetBalances; // The 'effective' balances (compensated with the escrowed balances)
uint256 walpha_0_ampped;
// Compute walpha_0 to find the reference balances. This lets us evaluate the
// number of tokens the vault should have If the price in the pool is 1:1.
// This is a balance0 implementation. The for loop is used to cache tokenIndexed and effWeightAssetBalances.
{
int256 weightedAssetBalanceSum = 0;
// The number of iterations, "it", is needed briefly outside the loop.
uint256 it;
for (it = 0; it < MAX_ASSETS;) {
address token = _tokenIndexing[it];
if (token == address(0)) break;
tokenIndexed[it] = token;
uint256 weight = _weight[token];
// Whenever balance0 is computed, the true balance should be used.
uint256 weightAssetBalance = weight * ERC20(token).balanceOf(address(this));
// Since this is used for a withdrawal, the escrow amount needs to be subtracted to return less.
effWeightAssetBalances[it] = weightAssetBalance - _escrowedTokens[token] * weight; // Store
// If weightAssetBalance == 0, then this computation would fail. However since 0^(1-k) = 0, we can set it to 0.
if (weightAssetBalance != 0) {
int256 wab = FixedPointMathLib.powWad(
int256((weightAssetBalance - _underwriteEscrowMatchBalance0[token] * weight) * FixedPointMathLib.WAD), // If casting overflows to a negative number, powWad fails
oneMinusAmp
);
// if wab == 0, there is no need to add it. So only add if != 0.
weightedAssetBalanceSum += wab;
}
unchecked {
++it;
}
}
// Compute the reference liquidity.
// weightedAssetBalanceSum > _unitTracker always, since _unitTracker correlates to exactly
// the difference between weightedAssetBalanceSum and weightedAssetBalance0Sum and thus
// _unitTracker < weightedAssetBalance0Sum
unchecked {
// weightedAssetBalanceSum - _unitTracker can overflow for negative _unitTracker. The result will
// be correct once it is casted to uint256.
walpha_0_ampped = uint256(weightedAssetBalanceSum - _unitTracker) / it; // By design, weightedAssetBalanceSum > _unitTracker
}
}
// For later event logging, the amounts transferred from the vault are stored.
amounts = new uint256[](MAX_ASSETS);
// The vault token to assets equation is:
// wtk = wa ·(1 - ((wa^(1-k) - wa_0^(1-k) · (1 - (PT-pt)/PT)^(1-k))/wa^(1-k))^(1/(1-k))
// The inner diff is wa_0^(1-k) · (1 - (PT-pt)/PT)^(1-k).
// since it doesn't depend on the token, it should only be computed once.
uint256 innerdiff;
{
// Remember to add the number of vault tokens burned to totalSupply()
// _escrowedVaultTokens is added, since it makes pt_fraction smaller
uint256 ts = (totalSupply() + _escrowedVaultTokens + vaultTokens);
uint256 pt_fraction = ((ts - vaultTokens) * FixedPointMathLib.WAD) / ts;
// If pt_fraction == 0 => 0^oneMinusAmp = powWad(0, oneMinusAmp) => exp(ln(0) * oneMinusAmp) which is undefined.
// However, we know what 0^oneMinusAmp is: 0!. So we just set it to 0.
innerdiff = pt_fraction == 0 ? walpha_0_ampped : FixedPointMathLib.mulWad(
walpha_0_ampped,
FixedPointMathLib.WAD - uint256(FixedPointMathLib.powWad( // Always casts a positive value
int256(pt_fraction), // Casting always safe, as pt_fraction < 1
oneMinusAmp
))
);
}
uint256 totalWithdrawn;
int256 oneMinusAmpInverse = WADWAD / oneMinusAmp;
for (uint256 it; it < MAX_ASSETS;) {
address token = tokenIndexed[it];
if (token == address(0)) break;
// ampWeightAssetBalance cannot be cached because the balance0 computation does it without the escrow.
// This computation needs to do it with the escrow.
uint256 ampWeightAssetBalance = uint256(FixedPointMathLib.powWad( // Powwad is always positive.
int256(effWeightAssetBalances[it] * FixedPointMathLib.WAD), // If casting overflows to a negative number, powWad fails
oneMinusAmp
));
//! If the vault doesn't have enough assets for a withdrawal, then
//! withdraw all of the vaults assets. This should be protected against by setting minOut != 0.
//! This happens because the vault expects assets to come back. (it is owed assets)
//! We don't want to keep track of debt so we simply return less
uint256 weightedTokenAmount = effWeightAssetBalances[it];
//! The above happens if innerdiff >= ampWeightAssetBalance. So if that isn't
//! the case, we should compute the true value.
if (innerdiff < ampWeightAssetBalance) {
// wtk = wa ·(1 - ((wa^(1-k) - wa_0^(1-k) · (1 - (PT-pt)/PT)^(1-k))/wa^(1-k))^(1/(1-k))
// wtk = wa ·(1 - ((wa^(1-k) - innerdiff)/wa^(1-k))^(1/(1-k))
// Since ampWeightAssetBalance ** (1/(1-amp)) == effWeightAssetBalances but the
// mathematical lib returns ampWeightAssetBalance ** (1/(1-amp)) < effWeightAssetBalances.
// the result is that if innerdiff isn't big enough to make up for the difference
// the transaction reverts. If that is the case, use withdrawAll.
// This quirk is "okay", since it means fewer tokens are always returned.
// Since tokens are withdrawn, the change is negative. As such, multiply the equation by -1.
weightedTokenAmount = FixedPointMathLib.mulWad(
weightedTokenAmount,
FixedPointMathLib.WAD - uint256(FixedPointMathLib.powWad( // The inner is between 0 and 1. Power of < 1 is always between 0 and 1.
int256(FixedPointMathLib.divWadUp( // 0 < innerdiff < ampWeightAssetBalance => < 1 thus casting never overflows.
ampWeightAssetBalance - innerdiff,
ampWeightAssetBalance
)),
oneMinusAmpInverse // 1/(1-amp)
))
);
}
// Store the amount withdrawn to subtract from the security limit later.
totalWithdrawn += weightedTokenAmount;
unchecked {
// remove the weight from weightedTokenAmount.
weightedTokenAmount /= _weight[token];
}
// Check if the user is satisfied with the output.
uint256 tokenMinOut = minOut[it]; // GAS SAVING
if (tokenMinOut > weightedTokenAmount) revert ReturnInsufficient(weightedTokenAmount, tokenMinOut);
// Store the token amount.
amounts[it] = weightedTokenAmount;
// Transfer the released tokens to the user.
SafeTransferLib.safeTransfer(token, msg.sender, weightedTokenAmount);
unchecked {
++it;
}
}
// Decrease the security limit by the amount withdrawn.
_maxUnitCapacity -= totalWithdrawn;
if (_usedUnitCapacity <= totalWithdrawn) {
_usedUnitCapacity = 0;
} else {
unchecked {
// We know: _usedUnitCapacity > totalWithdrawn.
_usedUnitCapacity -= totalWithdrawn;
}
}
// Emit the event
emit VaultWithdraw(msg.sender, vaultTokens, amounts);
}
/**
* @notice Burns vaultTokens and release a token distribution set by the user.
* @dev It is advised that the withdrawal matches the vault's %token distribution.
* Notice the special scheme for the ratios used. This is done to optimise gas since it doesn't require a sum or ratios.
* Cannot be used to withdraw all liquidity. For that, withdrawAll should be used.
* @param vaultTokens Number of vault tokens to withdraw.
* @param withdrawRatio Percentage of units used to withdraw. In the following special scheme: U_0 = U · withdrawRatio[0], U_1 = (U - U_0) · withdrawRatio[1], U_2 = (U - U_0 - U_1) · withdrawRatio[2], .... Is WAD.
* @param minOut Minimum number of tokens withdrawn.
* @return amounts Array containing the amounts withdrawn.
*/
function withdrawMixed(
uint256 vaultTokens,
uint256[] calldata withdrawRatio,
uint256[] calldata minOut
) nonReentrant external override returns(uint256[] memory amounts) {
// _updateAmplification();
// Burn the desired number of vault tokens to the user. If they don't have it, it saves gas.
// * Remember to add vaultTokens when accessing totalSupply()
_burn(msg.sender, vaultTokens);
// (For everyone else, it is probably cheaper to burn last. However, burning here makes
// the implementation more similar to the volatile one).
int256 oneMinusAmp = _oneMinusAmp;
// Cache weights and balances.
address[MAX_ASSETS] memory tokenIndexed;
uint256[MAX_ASSETS] memory effAssetBalances; // The 'effective' balances (compensated with the escrowed balances)
uint256 U = 0;
// Compute walpha_0 to find the reference balances. This lets us evaluate the
// number of tokens the vault should have if the price in the pool is 1:1.
// unlike in withdrawAll, this value is needed to compute U.
{
// As such, we don't need to remember the value beyond this section.
uint256 walpha_0_ampped;
// This is a balance0 implementation. The for loop is used to cache tokenIndexed, effAssetBalances and assetWeight.
{
int256 weightedAssetBalanceSum = 0;
// A very careful stack optimisation is made here.
// The number of iterations, "it", is needed briefly outside the loop.
// To reduce the number of items in the stack, U = it.
for (U = 0; U < MAX_ASSETS;) {
address token = _tokenIndexing[U];
if (token == address(0)) break;
tokenIndexed[U] = token;
uint256 weight = _weight[token];
// Whenever balance0 is computed, the true balance should be used.
uint256 ab = ERC20(token).balanceOf(address(this));
// Later we need to use the asset balances. Since it is for a withdrawal, we should subtract the escrowed tokens
// such that less is returned.
effAssetBalances[U] = ab - _escrowedTokens[token];
// subtract _underwriteEscrowMatchBalance0 since this is used for balance0.
uint256 weightAssetBalance = weight * (ab - _underwriteEscrowMatchBalance0[token]);
// If weightAssetBalance == 0, then this computation would fail. However since 0^(1-k) = 0, we can set it to 0.
int256 wab = 0;
if (weightAssetBalance != 0) {
wab = FixedPointMathLib.powWad(
int256(weightAssetBalance * FixedPointMathLib.WAD), // If casting overflows to a negative number, powWad fails
oneMinusAmp
);
// if wab == 0, there is no need to add it. So only add if != 0.
weightedAssetBalanceSum += wab;
}
unchecked {
++U;
}
}
// weightedAssetBalanceSum > _unitTracker always, since _unitTracker correlates to exactly
// the difference between weightedAssetBalanceSum and weightedAssetBalance0Sum and thus
// _unitTracker < weightedAssetBalance0Sum
unchecked {
// weightedAssetBalanceSum - _unitTracker can overflow for negative _unitTracker. The result will
// be correct once it is casted to uint256.
walpha_0_ampped = uint256(weightedAssetBalanceSum - _unitTracker) / U; // By design, weightedAssetBalanceSum > _unitTracker
}
// set U = number of tokens in the vault. But that is exactly what it is.
}
// Remember to add the number of vault tokens burned to totalSupply()
uint256 ts = totalSupply() + _escrowedVaultTokens + vaultTokens;
// Since vault tokens are getting subtracted from the total supply, remember
// to add a negative sign to vault tokens.
uint256 pt_fraction = FixedPointMathLib.divWad(ts - vaultTokens, ts);
// Compute the unit worth of the vault tokens.
// Recall that U is equal to N already. So we only need to multiply by the right side.
// Since pt_fraction < 1, the units are negative. This is expected for swap to tokens. As such
// FixedPointMathLib.WAD is moved in front to make U positive.
U *= FixedPointMathLib.mulWad(
walpha_0_ampped,
FixedPointMathLib.WAD - uint256(FixedPointMathLib.powWad( // Always casts a positive value
int256(pt_fraction), // If casting overflows to a negative number, powWad fails
oneMinusAmp
))
);
}
// For later event logging, the amounts transferred to the vault are stored.
amounts = new uint256[](MAX_ASSETS);
uint256 totalWithdrawn;
for (uint256 it; it < MAX_ASSETS;) {
// Ideally we would collect the token into memory to save gas but there isn't space in the stack.
if (tokenIndexed[it] == address(0)) break;
// Units allocated for the specific token.
uint256 U_i = FixedPointMathLib.mulWad(U, withdrawRatio[it]);
if (U_i == 0) {
// After a withdrawRatio of 1, all other withdrawRatios should be 0. Otherwise, there was an input error.
if (withdrawRatio[it] != 0) revert WithdrawRatioNotZero();
// Check the minimum output. This is important, since the normal check is skipped.
if (minOut[it] != 0) revert ReturnInsufficient(0, minOut[it]);
unchecked {
++it;
}
continue;
}
U -= U_i; // Subtract the number of units used. This will underflow for malicious withdrawRatios > 1.
uint256 assetWeight = _weight[tokenIndexed[it]];
// Units are shared between "liquidity units" and "token units". As such, we just need to convert the units to tokens.
uint256 tokenAmount = _calcPriceCurveLimit(U_i, effAssetBalances[it], assetWeight, oneMinusAmp);
// Ensure the output satisfies the user.
if (minOut[it] > tokenAmount) revert ReturnInsufficient(tokenAmount, minOut[it]);
// Store amount for withdraw event.
amounts[it] = tokenAmount;
// Transfer the released tokens to the user.
SafeTransferLib.safeTransfer(tokenIndexed[it], msg.sender, tokenAmount);
// Decrease the security limit by the amount withdrawn.
totalWithdrawn += tokenAmount * assetWeight;
unchecked {
++it;
}
}
// Ensure all units are used. This should be done by setting at least one withdrawRatio to 1 (WAD).
if (U != 0) revert UnusedUnitsAfterWithdrawal(U);
// Decrease the security limit by the amount withdrawn.
_maxUnitCapacity -= totalWithdrawn;
if (_usedUnitCapacity <= totalWithdrawn) {
_usedUnitCapacity = 0;
} else {
unchecked {
// We know: _usedUnitCapacity > totalWithdrawn >= 0.
_usedUnitCapacity -= totalWithdrawn;
}
}
// Emit the event
emit VaultWithdraw(msg.sender, vaultTokens, amounts);
}
/**
* @notice A swap between 2 assets within the vault. Is atomic.
* @param fromAsset Asset the user wants to sell.
* @param toAsset Asset the user wants to buy.
* @param amount Amount of fromAsset the user wants to sell.
* @param minOut Minimum output the user wants. Otherwise, the transaction reverts.
* @return out The number of tokens purchased.
*/
function localSwap(
address fromAsset,
address toAsset,
uint256 amount,
uint256 minOut
) nonReentrant external override returns (uint256 out) {
// _updateAmplification();
uint256 fee = FixedPointMathLib.mulWad(amount, _vaultFee);
// Calculate the return value.
out = calcLocalSwap(fromAsset, toAsset, amount - fee);
// Ensure the return value is more than the minimum output.
if (minOut > out) revert ReturnInsufficient(out, minOut);
// Transfer tokens to the user and collect tokens from the user.
// The order doesn't matter, since the function is reentrant protected.
// The transaction that is most likly to revert is first.
SafeTransferLib.safeTransferFrom(fromAsset, msg.sender, address(this), amount);
SafeTransferLib.safeTransfer(toAsset, msg.sender, out);
// Collect potential governance fee
_collectGovernanceFee(fromAsset, fee);
// For amplified vaults, the security limit is based on the sum of the tokens in the vault.
uint256 weightedAmount = amount * _weight[fromAsset];
uint256 weightedOut = out * _weight[toAsset];
// The if statement ensures the independent calculations never under or overflow.
if (weightedOut > weightedAmount) {
_maxUnitCapacity -= weightedOut - weightedAmount;
} else {
_maxUnitCapacity += weightedAmount - weightedOut;
}
emit LocalSwap(msg.sender, fromAsset, toAsset, amount, out);
}
/** @notice Common logic between sendAsset implementations */
function _sendAsset(
RouteDescription calldata routeDescription,
address fromAsset,
uint8 toAssetIndex,
uint256 U,
uint256 amount,
uint256 fee,
uint256 minOut,
address fallbackUser,
uint16 underwriteIncentiveX16,
bytes calldata calldata_
) internal {
// Fallback user cannot be address(0) since this is used as a check for the existance of an escrow.
// It would also be a silly fallback address.
require(fallbackUser != address(0));
// onSendAssetSuccess requires casting U to int256 to update the _unitTracker and must never revert. Check for overflow here.
require(U < uint256(type(int256).max)); // int256 max fits in uint256
_unitTracker += int256(U);
// Send the purchased units to the target vault on the target chain.
ICatalystChainInterface(_chainInterface).sendCrossChainAsset{value: msg.value}(
routeDescription,
toAssetIndex,
U,
minOut,
amount - fee,
fromAsset,
underwriteIncentiveX16,
calldata_
);
// Store the escrow information. For that, an index is required. Since we need this index twice, we store it.
// Only information that is relevant for the escrow has to be hashed. (+ some extra for randomisation)
// No need to hash context (as token/liquidity escrow data is different), fromVault, toVault, targetAssetIndex, minOut, CallData
bytes32 sendAssetHash = _computeSendAssetHash(
routeDescription.toAccount, // Ensures no collisions between different users
U, // Used to randomise the hash
amount - fee, // Required! to validate release escrow data
fromAsset, // Required! to validate release escrow data
uint32(block.number) // May overflow, but this is desired (% 2**32)
);
// Escrow the tokens used to purchase units. These will be sent back if transaction doesn't arrive / timeout.
_setTokenEscrow(
sendAssetHash,
fallbackUser,
fromAsset,
amount - fee
);
// Notice that the fee is subtracted from the escrow. If this is not done, the escrow can be used as a cheap denial of service vector.
// This is unfortunate.
// Collect the tokens from the user.
SafeTransferLib.safeTransferFrom(fromAsset, msg.sender, address(this), amount);
// Governance Fee
_collectGovernanceFee(fromAsset, fee);
// Adjustment of the security limit is delayed until ack to avoid a router abusing timeout to circumvent the security limit.
emit SendAsset(
routeDescription.chainIdentifier,
routeDescription.toVault,
routeDescription.toAccount,
fromAsset,
toAssetIndex,
amount,
minOut,
U,
fee,
underwriteIncentiveX16
);
}
/**
* @notice Initiate a cross-chain swap by purchasing units and transfering the units to the target vault.
* @param routeDescription Cross-chain route description that contains the chainIdentifier, toAccount, toVault and relaying incentive.
* @param fromAsset Asset the user wants to sell.
* @param toAssetIndex Index of the asset the user wants to buy in the target vault.
* @param amount Number of fromAsset to sell to the vault.
* @param minOut Minimum number output of tokens on the target chain.
* @param fallbackUser If the transaction fails, send the escrowed funds to this address.
* @param underwriteIncentiveX16 Payment for underwriting the swap (out of type(uint16).max).
* @param calldata_ Data field if a call should be made on the target chain.
* Encoding depends on the target chain, with EVM: bytes.concat(bytes20(uint160(<address>)), <data>). At maximum 65535 bytes can be passed.
* @return U Number of units bought.
*/
function sendAsset(
RouteDescription calldata routeDescription,
address fromAsset,
uint8 toAssetIndex,
uint256 amount,
uint256 minOut,
address fallbackUser,
uint16 underwriteIncentiveX16,
bytes calldata calldata_
) nonReentrant onlyConnectedPool(routeDescription.chainIdentifier, routeDescription.toVault) external payable override returns (uint256 U) {
// _updateAmplification();
uint256 fee = FixedPointMathLib.mulWad(amount, _vaultFee);
// Calculate the units bought.
U = calcSendAsset(fromAsset, amount - fee);
// Execute the common sendAsset logic.
_sendAsset(
routeDescription,
fromAsset,
toAssetIndex,
U,
amount,
fee,
minOut,
fallbackUser,
underwriteIncentiveX16,
calldata_
);
}
/**
* @notice Initiate a cross-chain swap by purchasing units and transfer them to another vault using a fixed number of units.
* @dev This function is intended to match an existing underwrite. Since normal sendAssets aren't "exact" in regards to U,
* this functions makes it easier to hit a specific underwrite.
* @param routeDescription Cross-chain route description that contains the chainIdentifier, toAccount, toVault and relaying incentive.
* @param fromAsset Asset the user wants to sell.
* @param toAssetIndex Index of the asset the user wants to buy in the target vault.
* @param amount Number of fromAsset to sell to the vault.
* @param minOut Minimum number output of tokens on the target chain.
* @param minU Minimum and exact number of units sent.
* @param fallbackUser If the transaction fails, send the escrowed funds to this address.
* @param underwriteIncentiveX16 Payment for underwriting the swap (out of type(uint16).max).
* @param calldata_ Data field if a call should be made on the target chain.
* Encoding depends on the target chain, with EVM: bytes.concat(bytes20(uint160(<address>)), <data>). At maximum 65535 bytes can be passed..
* @return U Always equal to minOut, as that is the number of units to be used on the destination chain.
*/
function sendAssetFixedUnit(
ICatalystV1Structs.RouteDescription calldata routeDescription,
address fromAsset,
uint8 toAssetIndex,
uint256 amount,
uint256 minOut,
uint256 minU,
address fallbackUser,
uint16 underwriteIncentiveX16,
bytes calldata calldata_
) nonReentrant onlyConnectedPool(routeDescription.chainIdentifier, routeDescription.toVault) external payable override returns (uint256 U) {
// _updateAmplification();
uint256 fee = FixedPointMathLib.mulWad(amount, _vaultFee);
// Calculate the units bought.
U = calcSendAsset(fromAsset, amount - fee);
if (U < minU) revert ReturnInsufficient(U, minU);
// The set number of units bought to minU.
U = minU;
// Execute the common sendAsset logic.
_sendAsset(
routeDescription,
fromAsset,
toAssetIndex,
U,
amount,
fee,
minOut,
fallbackUser,
underwriteIncentiveX16,
calldata_
);
}
/**
* @notice Handles common logic associated with the completion of a cross-chain swap.
* This function convert incoming Units (expected to be from an incoming cross-chain swap) into a specific token.
* @dev This function is intended to finalise a receiveAsset call.
* @param toAsset Asset to buy with the units.
* @param U Incoming units to be turned into vaults tokens.
* @param minOut Minimum number of tokens to purchase. Will revert if less.
* @return purchasedTokens Number of toAsset bought.
*/
function _receiveAsset(
address toAsset,
uint256 U,
uint256 minOut
) internal override returns (uint256 purchasedTokens) {
// _updateAmplification();
// Calculate the swap return value. Fee is always taken on the sending token.
purchasedTokens = calcReceiveAsset(toAsset, U);
// Check if the swap is according to the swap limits.
uint256 deltaSecurityLimit = purchasedTokens * _weight[toAsset];
if (_maxUnitCapacity <= deltaSecurityLimit) revert ExceedsSecurityLimit();
unchecked {
// We know that _maxUnitCapacity > deltaSecurityLimit so it cannot underflow.
_maxUnitCapacity -= deltaSecurityLimit;
}
_updateUnitCapacity(deltaSecurityLimit);
// Ensure the user is satisfied with the number of tokens.
if (minOut > purchasedTokens) revert ReturnInsufficient(purchasedTokens, minOut);
// Track units for balance0 computation.
_unitTracker -= int256(U);
}
/**
* @notice Completes a cross-chain swap by converting units to the desired token.
* @dev Security checks are performed by _receiveAsset.
* @param channelId Source chain identifier.
* @param fromVault Source vault.
* @param toAssetIndex Index of the asset to be purchased.
* @param toAccount Recipient of assets on destination chain.
* @param U Incoming units.
* @param minOut Minimum number of token to buy. Reverts back to the sending side.
* @param fromAmount Used to match cross-chain swap events. The input amount minus fees on the sending chain.
* @param fromAsset Used to match cross-chain swap events. The input asset on the source chain.
* @param blockNumberMod Used to match cross-chain swap events. The block number from the source chain.
* @param purchasedTokens Number of toAsset bought.
*/
function receiveAsset(
bytes32 channelId,
bytes calldata fromVault,
uint256 toAssetIndex,
address toAccount,
uint256 U,
uint256 minOut,
uint256 fromAmount,
bytes calldata fromAsset,
uint32 blockNumberMod
) nonReentrant onlyChainInterface onlyConnectedPool(channelId, fromVault) external override returns(uint256 purchasedTokens) {
// Convert the asset index (toAsset) into the asset to be purchased.
address toAsset = _tokenIndexing[toAssetIndex];
purchasedTokens = _receiveAsset(
toAsset,
U,
minOut
);
// Send the assets to the user.
SafeTransferLib.safeTransfer(toAsset, toAccount, purchasedTokens);
emit ReceiveAsset(
channelId,
fromVault,
toAccount,
toAsset,
U,
purchasedTokens,
fromAmount,
fromAsset,
blockNumberMod
);
}
//--- Liquidity swapping ---//
// Because of the way vault tokens work in a pool, there needs to be a way for users to easily get
// a distributed stake. Liquidity swaps is a macro implemented at the smart contract level equivalent to:
// 1. Withdraw tokens.
// 2. Convert tokens to units & transfer to target vault.
// 3. Convert units to an even mix of tokens.
// 4. Deposit the even mix of tokens.
// In 1 user invocation.
/**
* @notice Computes balance0**(1-amp) without any special caching.
* @dev Whenever balance0 is computed, the true balance should be used instead of the one
* modifed by the escrow. This is because balance0 is constant during swaps. Thus, if the
* balance was modified, it would not be constant during swaps.
* The function also returns the vault asset count as it is always used in conjunction with walpha_0_ampped.
* The external function does not.
* @return walpha_0_ampped Balance0**(1-amp)
* @return it the vault asset count
*/
function _computeBalance0(int256 oneMinusAmp) internal view returns(uint256 walpha_0_ampped, uint256 it) {
// Compute walpha_0 to find the reference balances. This lets us evaluate the
// number of tokens the vault should have IF the price in the pool is 1:1.
// This is a balance0 implementation. The balance 0 implementation here is reference.
int256 weightedAssetBalanceSum = 0;
for (it; it < MAX_ASSETS;) {
address token = _tokenIndexing[it];
if (token == address(0)) break;
uint256 weight = _weight[token];
uint256 weightAssetBalance = weight * (ERC20(token).balanceOf(address(this)) - _underwriteEscrowMatchBalance0[token]);
// If weightAssetBalance == 0, then this computation would fail. However since 0^(1-k) = 0, we can set it to 0.
int256 wab = 0;
if (weightAssetBalance != 0){
wab = FixedPointMathLib.powWad(
int256(weightAssetBalance * FixedPointMathLib.WAD), // If casting overflows to a negative number, powWad fails
oneMinusAmp
);
// if wab == 0, there is no need to add it. So only add if != 0.
weightedAssetBalanceSum += wab;
}
unchecked {
++it;
}
}
// weightedAssetBalanceSum > _unitTracker always, since _unitTracker correlates to exactly
// the difference between weightedAssetBalanceSum and weightedAssetBalance0Sum and thus
// _unitTracker < weightedAssetBalance0Sum
unchecked {
// weightedAssetBalanceSum - _unitTracker can overflow for negative _unitTracker. The result will
// be correct once it is casted to uint256.
walpha_0_ampped = uint256(weightedAssetBalanceSum - _unitTracker) / it; // By design, weightedAssetBalanceSum > _unitTracker
}
}
/**
* @notice Computes balance0 for the pool.
* @dev This can be used as a local invariant. Is constant (or slowly increasing) for swaps.
* Deposits and withdrawals change balance0 and as such, it cannot be used to examine if a vault is secure
* by it self.
* This function does not return balance0 as it, is returns a weighted amplified form.
* For pretty much any real world usage of the function, this is the relevant form.
* @return walpha_0 Balance0**(1-amp)
*/
function computeBalance0() external view returns(uint256 walpha_0) {
int256 oneMinusAmp = _oneMinusAmp;
(uint256 walpha_0_ampped, ) = _computeBalance0(oneMinusAmp);
walpha_0 = uint256( // casting: powWad is not negative.
FixedPointMathLib.powWad(
int256(walpha_0_ampped), // Casting: If overflow, then powWad fails as the overflow is into negative.
WADWAD / oneMinusAmp
)
);
}
/**
* @notice Initiate a cross-chain liquidity swap by withdrawing tokens and converting them to units.
* @dev While the description says tokens are withdrawn and then converted to units, vault tokens are converted
* directly into units through the following equation: U = N · wa^(1-k) · (((PT + pt)/PT)^(1-k) - 1)
* @param routeDescription Cross-chain route description that contains the chainIdentifier, toAccount, toVault, and relaying incentive.
* @param vaultTokens Number of vault tokens to exchange.
* @param minOut Array of minout describing: [the minimum number of vault tokens, the minimum number of reference assets].
* @param fallbackUser If the transaction fails, send the escrowed funds to this address.
* @param calldata_ Data field if a call should be made on the target chain.
* Encoding depends on the target chain, with EVM: abi.encodePacket(bytes20(<address>), <data>). At maximum 65535 bytes can be passed.
* @return U Number of units bought.
*/
function sendLiquidity(
RouteDescription calldata routeDescription,
uint256 vaultTokens,
uint256[2] calldata minOut,
address fallbackUser,
bytes calldata calldata_
) nonReentrant onlyConnectedPool(routeDescription.chainIdentifier, routeDescription.toVault) external payable override returns (uint256 U) {
// Fallback user cannot be address(0) since this is used as a check for the existance of an escrow.
// It would also be a silly fallback address.
require(fallbackUser != address(0));
// Correct address format is checked on the cross-chain interface.
// _updateAmplification();
// When accesssing totalSupply, remember that we already burnt the incoming vaultTokens.
_burn(msg.sender, vaultTokens);
int256 oneMinusAmp = _oneMinusAmp;
// Compute walpha_0 to find the reference balances. This lets us evaluate the
// number of tokens the vault should have If the price in the pool is 1:1.
(uint256 walpha_0_ampped, uint256 it) = _computeBalance0(oneMinusAmp);
{
// Plus _escrowedVaultTokens since we want the withdrawal to return less. Adding vaultTokens as these have already been burnt.
uint256 ts = totalSupply() + _escrowedVaultTokens + vaultTokens;
uint256 pt_fraction = FixedPointMathLib.divWad(ts + vaultTokens, ts);
U = it * FixedPointMathLib.mulWad(
walpha_0_ampped,
uint256(FixedPointMathLib.powWad( // Always casts a positive value
int256(pt_fraction), // If casting overflows to a negative number, powWad fails
oneMinusAmp
)) - FixedPointMathLib.WAD
);
// onSendLiquiditySuccess requires casting U to int256 to update the _unitTracker and must never revert. Check for overflow here.
require(U < uint256(type(int256).max)); // int256 max fits in uint256
_unitTracker += int256(U);
}
// Transfer the units to the target vault.
ICatalystChainInterface(_chainInterface).sendCrossChainLiquidity{value: msg.value}(
routeDescription,
U,
minOut,
vaultTokens,
calldata_
);
// Store the escrow information. For that, an index is required. Since we need this index twice, we store it.
// Only information that is relevant for the escrow has to be hashed. (+ some extra for randomisation)
// No need to hash context (as token/liquidity escrow data is different), fromVault, toVault, targetAssetIndex, minOut, CallData
bytes32 sendLiquidityHash = _computeSendLiquidityHash(
routeDescription.toAccount, // Ensures no collisions between different users
U, // Used to randomise the hash
vaultTokens, // Required! to validate release escrow data
uint32(block.number) // May overflow, but this is desired (% 2**32)
);
// Emit event before setting escrow to clear up variables from stack.
emit SendLiquidity(
routeDescription.chainIdentifier,
routeDescription.toVault,
routeDescription.toAccount,
vaultTokens,
minOut,
U
);
// Escrow the vault token used to purchase units. These will be sent back if transaction doesn't arrive / timeout.
_setLiquidityEscrow(
sendLiquidityHash,
fallbackUser,
vaultTokens
);
// Adjustment of the security limit is delayed until ack to avoid
// a router abusing timeout to circumvent the security limit at a low cost.
}
/**
* @notice Handles common logic assocaited with the completion of a cross-chain liquidity swap.
* This function convert incoming units directly to vault tokens.
* @dev This function is meant to finalise a receiveLiquidity call.
* @param U Incoming units to be turned into vault tokens.
* @param minVaultTokens Minimum number of vault tokens to mint (revert if less).
* @param minReferenceAsset Minimum number of reference tokens the vaults tokens are worth (revert if less).
* @return vaultTokens Minted vault tokens.
*/
function _receiveLiquidity(
uint256 U,
uint256 minVaultTokens,
uint256 minReferenceAsset
) internal returns (uint256 vaultTokens) {
// _updateAmplification();
int256 oneMinusAmp = _oneMinusAmp;
// Compute walpha_0 to find the reference balances. This lets us evaluate the
// number of tokens the vault should have If the price in the pool is 1:1.
(uint256 walpha_0_ampped, uint256 it) = _computeBalance0(oneMinusAmp);
int256 oneMinusAmpInverse = WADWAD / oneMinusAmp;
uint256 it_times_walpha_amped = it * walpha_0_ampped;
// On totalSupply(). Do not add escrow amount, as higher amount results in a larger return.
vaultTokens = _calcPriceCurveLimitShare(U, totalSupply(), it_times_walpha_amped, oneMinusAmpInverse);
// Check if more vault tokens than the minimum can be minted.
if (minVaultTokens > vaultTokens) revert ReturnInsufficient(vaultTokens, minVaultTokens);
// Then check if the minimum number of reference assets is honoured.
if (minReferenceAsset != 0) {
uint256 walpha_0 = uint256(FixedPointMathLib.powWad( // uint256 casting: Is always positive.
int256(walpha_0_ampped), // int256 casting: If casts to a negative number, powWad fails because it uses ln which can't take negative numbers.
oneMinusAmpInverse
));
// Add escrow to ensure that even if all ongoing transaction revert, the user gets their expected amount.
// Add vault tokens because they are going to be minted (We want the reference value after mint).
uint256 walpha_0_owned = ((walpha_0 * vaultTokens) / (totalSupply() + _escrowedVaultTokens + vaultTokens)) / FixedPointMathLib.WAD;
if (minReferenceAsset > walpha_0_owned) revert ReturnInsufficient(walpha_0_owned, minReferenceAsset);
}
// Update the unit tracker:
_unitTracker -= int256(U);
// Security limit
{
// To calculate the vaultTokenEquiv, we set \alpha_t = \alpha_0.
// This should be a close enough approximation.
// If U > it_times_walpha_amped, then U can purchase more than 50% of the vault.
// And the below calculation doesn't work.
if (it_times_walpha_amped <= U) revert ExceedsSecurityLimit();
uint256 vaultTokenEquiv = FixedPointMathLib.mulWadUp(
uint256(FixedPointMathLib.powWad( // Always casts a positive value
int256(it_times_walpha_amped), // If casting overflows to a negative number, powWad fails
oneMinusAmpInverse
)),
FixedPointMathLib.WAD - uint256(FixedPointMathLib.powWad( // powWad is always <= 1, as 'base' is always <= 1
int256(FixedPointMathLib.divWad( // Casting never overflows, as division result is always <= 1
it_times_walpha_amped - U,
it_times_walpha_amped
)),
oneMinusAmpInverse
))
);
// Check if the swap is according to the swap limits
_updateUnitCapacity(FixedPointMathLib.mulWad(2, vaultTokenEquiv));
}
}
/**
* @notice Completes a cross-chain liquidity swap by converting units to tokens and depositing.
* @dev Security checks are performed by _receiveLiquidity.
* While the description says units are converted to tokens and then deposited, units are converted
* directly to vault tokens through the following equation: pt = PT · (((N · wa_0^(1-k) + U)/(N · wa_0^(1-k))^(1/(1-k)) - 1)
* @param channelId Source chain identifier.
* @param fromVault Source vault.
* @param toAccount Recipient of vault tokens.
* @param U Incoming units to be turned into vault tokens.
* @param minVaultTokens Minimum number of vault tokens to mint (revert if less).
* @param minReferenceAsset Minimum number of reference tokens the vaults tokens are worth (revert if less).
* @param fromAmount Used to match cross-chain swap events. The input amount on the source chain.
* @param blockNumberMod Used to match cross-chain swap events. The block number from the source chain.
* @return purchasedVaultTokens Minted vault tokens.
*/
function receiveLiquidity(
bytes32 channelId,
bytes calldata fromVault,
address toAccount,
uint256 U,
uint256 minVaultTokens,
uint256 minReferenceAsset,
uint256 fromAmount,
uint32 blockNumberMod
) nonReentrant onlyChainInterface onlyConnectedPool(channelId, fromVault) external override returns(uint256 purchasedVaultTokens) {
purchasedVaultTokens = _receiveLiquidity(
U,
minVaultTokens,
minReferenceAsset
);
emit ReceiveLiquidity(channelId, fromVault, toAccount, U, purchasedVaultTokens, fromAmount, blockNumberMod);
// Mint vault tokens for the user.
_mint(toAccount, purchasedVaultTokens);
}
//-- Escrow Functions --//
/**
* @notice Deletes and releases escrowed tokens to the vault and updates the security limit.
* @dev Should never revert!
* The base implementation exists in CatalystVaultCommon. The function adds security limit
* adjustment to the implementation to swap volume supported.
* @param toAccount Recipient of the transaction on the target chain.
* @param U Number of units purchased.
* @param escrowAmount Number of tokens escrowed.
* @param escrowToken Token escrowed.
* @param blockNumberMod Block number at which the swap transaction was commited (mod 32)
*/
function onSendAssetSuccess(
bytes32 channelId,
bytes calldata toAccount,
uint256 U,
uint256 escrowAmount,
address escrowToken,
uint32 blockNumberMod
) public override {
// Execute common escrow logic.
super.onSendAssetSuccess(channelId, toAccount, U, escrowAmount, escrowToken, blockNumberMod);
// Received assets should be subtracted from the used unit capacity.
// It is assumed if the router was fraudulent no-one would execute a trade.
// As a result, if people swap into the vault, we should expect that there is exactly
// the inswapped amount of trust in the vault. If this wasn't implemented, there would be
// a maximum daily cross chain volume, which is bad for liquidity providers.
unchecked {
// escrowAmount * _weight[escrowToken] has been calculated before.
uint256 escrowAmountTimesWeight = escrowAmount * _weight[escrowToken];
uint256 UC = _usedUnitCapacity;
// If UC < escrowAmount and we do UC - escrowAmount < 0 underflow => bad.
if (UC > escrowAmountTimesWeight) {
_usedUnitCapacity = UC - escrowAmountTimesWeight; // Does not underflow since _usedUnitCapacity > escrowAmount.
} else if (UC != 0) {
// If UC == 0, then we shouldn't do anything. Skip that case.
// when UC <= escrowAmount => UC - escrowAmount <= 0 => max(UC - escrowAmount, 0) = 0
_usedUnitCapacity = 0;
}
// There is a chance that _maxUnitCapacity + escrowAmount * _weight[escrowToken] will overflow.
// since the number has never been calculated before. This function should never revert so the computation
// has to be done unchecked.
uint256 muc = _maxUnitCapacity;
uint256 new_muc = muc + escrowAmountTimesWeight; // Might overflow. Can be checked by comparing it against MUC.
// If new_muc < muc, then new_muc has overflown. As a result, we should set muc = uint256::MAX
if (new_muc < muc) {
_maxUnitCapacity = type(uint256).max;
} else {
_maxUnitCapacity = new_muc;
}
}
}
/**
* @notice Deletes and releases escrowed tokens to the vault and updates the security limit.
* @dev Should never revert!
* The base implementation exists in CatalystVaultCommon. The function adds security limit
* adjustment to the implementation to swap volume supported.
* @param toAccount Recipient of the transaction on the target chain.
* @param U Number of units acquired.
* @param escrowAmount Number of tokens escrowed.
* @param escrowToken Token escrowed.
* @param blockNumberMod Block number at which the swap transaction was commited (mod 32)
*/
function onSendAssetFailure(
bytes32 channelId,
bytes calldata toAccount,
uint256 U,
uint256 escrowAmount,
address escrowToken,
uint32 blockNumberMod
) public override {
// Execute common escrow logic.
super.onSendAssetFailure(channelId, toAccount, U, escrowAmount, escrowToken, blockNumberMod);
// Removed timed-out units from the unit tracker. This will keep the
// balance0 in balance, since tokens also leave the vault
_unitTracker -= int256(U); // It has already been checked on sendAsset that casting to int256 will not overflow.
// Cannot be manipulated by the router as, otherwise, the swapHash check will fail
}
// onSendLiquiditySuccess is not overwritten since we are unable to increase
// the security limit. This is because it is very expensive to compute the update
// to the security limit. If someone liquidity swapped a significant amount of assets
// it is assumed the vault has low liquidity. In these cases, liquidity swaps shouldn't be used.
/**
* @notice Deletes and releases liquidity escrowed tokens to the vault and updates the security limit.
* @dev Should never revert!
* The base implementation exists in CatalystVaultCommon.
* @param toAccount Recipient of the transaction on the target chain. Encoded in bytes32.
* @param U Number of units initially acquired.
* @param escrowAmount Number of vault tokens escrowed.
* @param blockNumberMod Block number at which the swap transaction was commited (mod 32)
*/
function onSendLiquidityFailure(
bytes32 channelId,
bytes calldata toAccount,
uint256 U,
uint256 escrowAmount,
uint32 blockNumberMod
) public override {
super.onSendLiquidityFailure(channelId, toAccount, U, escrowAmount, blockNumberMod);
// Removed timed-out units from the unit tracker. This will keep the
// balance0 in balance, since tokens also leave the vault
_unitTracker -= int256(U); // It has already been checked on sendAsset that casting to int256 will not overflow.
// Cannot be manipulated by the router as, otherwise, the swapHash check will fail
}
function underwriteAsset(
bytes32 identifier,
address toAsset,
uint256 U,
uint256 minOut
) override public returns (uint256 purchasedTokens) {
// We need to ensure that the conversion in deleteUnderwrite (and receiveAsset) doesn't overflow.
require(U < uint256(type(int256).max)); // int256 max fits in uint256
purchasedTokens = super.underwriteAsset(identifier, toAsset, U, minOut);
// unit tracking is handled by _receiveAsset.
// since _unitTrakcer -= int256(U) has been set but no tokens have
// let the pool, we need to remove the corresponding amount from
// the balance 0 computation to ensure it is still correct.
unchecked {
// Must be less than the vault balance.
_underwriteEscrowMatchBalance0[toAsset] += purchasedTokens;
}
}
function releaseUnderwriteAsset(
address refundTo,
bytes32 identifier,
uint256 escrowAmount,
address escrowToken,
bytes32 sourceIdentifier,
bytes calldata fromVault
) override public {
super.releaseUnderwriteAsset(refundTo, identifier, escrowAmount, escrowToken, sourceIdentifier, fromVault);
unchecked {
_underwriteEscrowMatchBalance0[escrowToken] -= escrowAmount;
}
}
function deleteUnderwriteAsset(
bytes32 identifier,
uint256 U,
uint256 escrowAmount,
address escrowToken
) override public {
super.deleteUnderwriteAsset(identifier, U, escrowAmount, escrowToken);
// update the unit tracker. When underwriteAsset was called, the _unitTracker was updated with
// _unitTrakcer -= int256(U) so we need to cancel that.
_unitTracker += int256(U); // It has already been checked on sendAsset that casting to int256 will not overflow.
// Cannot be manipulated by the router as, otherwise, the swapHash check will fail
unchecked {
_underwriteEscrowMatchBalance0[escrowToken] -= escrowAmount;
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Simple ERC20 + EIP-2612 implementation.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol)
///
/// @dev Note:
/// - The ERC20 standard allows minting and transferring to and from the zero address,
/// minting and transferring zero tokens, as well as self-approvals.
/// For performance, this implementation WILL NOT revert for such actions.
/// Please add any checks with overrides if desired.
/// - The `permit` function uses the ecrecover precompile (0x1).
///
/// If you are overriding:
/// - NEVER violate the ERC20 invariant:
/// the total sum of all balances must be equal to `totalSupply()`.
/// - Check that the overridden function is actually used in the function you want to
/// change the behavior of. Much of the code has been manually inlined for performance.
abstract contract ERC20 {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The total supply has overflowed.
error TotalSupplyOverflow();
/// @dev The allowance has overflowed.
error AllowanceOverflow();
/// @dev The allowance has underflowed.
error AllowanceUnderflow();
/// @dev Insufficient balance.
error InsufficientBalance();
/// @dev Insufficient allowance.
error InsufficientAllowance();
/// @dev The permit is invalid.
error InvalidPermit();
/// @dev The permit has expired.
error PermitExpired();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EVENTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Emitted when `amount` tokens is transferred from `from` to `to`.
event Transfer(address indexed from, address indexed to, uint256 amount);
/// @dev Emitted when `amount` tokens is approved by `owner` to be used by `spender`.
event Approval(address indexed owner, address indexed spender, uint256 amount);
/// @dev `keccak256(bytes("Transfer(address,address,uint256)"))`.
uint256 private constant _TRANSFER_EVENT_SIGNATURE =
0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;
/// @dev `keccak256(bytes("Approval(address,address,uint256)"))`.
uint256 private constant _APPROVAL_EVENT_SIGNATURE =
0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STORAGE */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The storage slot for the total supply.
uint256 private constant _TOTAL_SUPPLY_SLOT = 0x05345cdf77eb68f44c;
/// @dev The balance slot of `owner` is given by:
/// ```
/// mstore(0x0c, _BALANCE_SLOT_SEED)
/// mstore(0x00, owner)
/// let balanceSlot := keccak256(0x0c, 0x20)
/// ```
uint256 private constant _BALANCE_SLOT_SEED = 0x87a211a2;
/// @dev The allowance slot of (`owner`, `spender`) is given by:
/// ```
/// mstore(0x20, spender)
/// mstore(0x0c, _ALLOWANCE_SLOT_SEED)
/// mstore(0x00, owner)
/// let allowanceSlot := keccak256(0x0c, 0x34)
/// ```
uint256 private constant _ALLOWANCE_SLOT_SEED = 0x7f5e9f20;
/// @dev The nonce slot of `owner` is given by:
/// ```
/// mstore(0x0c, _NONCES_SLOT_SEED)
/// mstore(0x00, owner)
/// let nonceSlot := keccak256(0x0c, 0x20)
/// ```
uint256 private constant _NONCES_SLOT_SEED = 0x38377508;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev `(_NONCES_SLOT_SEED << 16) | 0x1901`.
uint256 private constant _NONCES_SLOT_SEED_WITH_SIGNATURE_PREFIX = 0x383775081901;
/// @dev `keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)")`.
bytes32 private constant _DOMAIN_TYPEHASH =
0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f;
/// @dev `keccak256("1")`.
bytes32 private constant _VERSION_HASH =
0xc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6;
/// @dev `keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)")`.
bytes32 private constant _PERMIT_TYPEHASH =
0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ERC20 METADATA */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the name of the token.
function name() public view virtual returns (string memory);
/// @dev Returns the symbol of the token.
function symbol() public view virtual returns (string memory);
/// @dev Returns the decimals places of the token.
function decimals() public view virtual returns (uint8) {
return 18;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ERC20 */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the amount of tokens in existence.
function totalSupply() public view virtual returns (uint256 result) {
/// @solidity memory-safe-assembly
assembly {
result := sload(_TOTAL_SUPPLY_SLOT)
}
}
/// @dev Returns the amount of tokens owned by `owner`.
function balanceOf(address owner) public view virtual returns (uint256 result) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x0c, _BALANCE_SLOT_SEED)
mstore(0x00, owner)
result := sload(keccak256(0x0c, 0x20))
}
}
/// @dev Returns the amount of tokens that `spender` can spend on behalf of `owner`.
function allowance(address owner, address spender)
public
view
virtual
returns (uint256 result)
{
/// @solidity memory-safe-assembly
assembly {
mstore(0x20, spender)
mstore(0x0c, _ALLOWANCE_SLOT_SEED)
mstore(0x00, owner)
result := sload(keccak256(0x0c, 0x34))
}
}
/// @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
///
/// Emits a {Approval} event.
function approve(address spender, uint256 amount) public virtual returns (bool) {
/// @solidity memory-safe-assembly
assembly {
// Compute the allowance slot and store the amount.
mstore(0x20, spender)
mstore(0x0c, _ALLOWANCE_SLOT_SEED)
mstore(0x00, caller())
sstore(keccak256(0x0c, 0x34), amount)
// Emit the {Approval} event.
mstore(0x00, amount)
log3(0x00, 0x20, _APPROVAL_EVENT_SIGNATURE, caller(), shr(96, mload(0x2c)))
}
return true;
}
/// @dev Transfer `amount` tokens from the caller to `to`.
///
/// Requirements:
/// - `from` must at least have `amount`.
///
/// Emits a {Transfer} event.
function transfer(address to, uint256 amount) public virtual returns (bool) {
_beforeTokenTransfer(msg.sender, to, amount);
/// @solidity memory-safe-assembly
assembly {
// Compute the balance slot and load its value.
mstore(0x0c, _BALANCE_SLOT_SEED)
mstore(0x00, caller())
let fromBalanceSlot := keccak256(0x0c, 0x20)
let fromBalance := sload(fromBalanceSlot)
// Revert if insufficient balance.
if gt(amount, fromBalance) {
mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
revert(0x1c, 0x04)
}
// Subtract and store the updated balance.
sstore(fromBalanceSlot, sub(fromBalance, amount))
// Compute the balance slot of `to`.
mstore(0x00, to)
let toBalanceSlot := keccak256(0x0c, 0x20)
// Add and store the updated balance of `to`.
// Will not overflow because the sum of all user balances
// cannot exceed the maximum uint256 value.
sstore(toBalanceSlot, add(sload(toBalanceSlot), amount))
// Emit the {Transfer} event.
mstore(0x20, amount)
log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, caller(), shr(96, mload(0x0c)))
}
_afterTokenTransfer(msg.sender, to, amount);
return true;
}
/// @dev Transfers `amount` tokens from `from` to `to`.
///
/// Note: Does not update the allowance if it is the maximum uint256 value.
///
/// Requirements:
/// - `from` must at least have `amount`.
/// - The caller must have at least `amount` of allowance to transfer the tokens of `from`.
///
/// Emits a {Transfer} event.
function transferFrom(address from, address to, uint256 amount) public virtual returns (bool) {
_beforeTokenTransfer(from, to, amount);
/// @solidity memory-safe-assembly
assembly {
let from_ := shl(96, from)
// Compute the allowance slot and load its value.
mstore(0x20, caller())
mstore(0x0c, or(from_, _ALLOWANCE_SLOT_SEED))
let allowanceSlot := keccak256(0x0c, 0x34)
let allowance_ := sload(allowanceSlot)
// If the allowance is not the maximum uint256 value.
if add(allowance_, 1) {
// Revert if the amount to be transferred exceeds the allowance.
if gt(amount, allowance_) {
mstore(0x00, 0x13be252b) // `InsufficientAllowance()`.
revert(0x1c, 0x04)
}
// Subtract and store the updated allowance.
sstore(allowanceSlot, sub(allowance_, amount))
}
// Compute the balance slot and load its value.
mstore(0x0c, or(from_, _BALANCE_SLOT_SEED))
let fromBalanceSlot := keccak256(0x0c, 0x20)
let fromBalance := sload(fromBalanceSlot)
// Revert if insufficient balance.
if gt(amount, fromBalance) {
mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
revert(0x1c, 0x04)
}
// Subtract and store the updated balance.
sstore(fromBalanceSlot, sub(fromBalance, amount))
// Compute the balance slot of `to`.
mstore(0x00, to)
let toBalanceSlot := keccak256(0x0c, 0x20)
// Add and store the updated balance of `to`.
// Will not overflow because the sum of all user balances
// cannot exceed the maximum uint256 value.
sstore(toBalanceSlot, add(sload(toBalanceSlot), amount))
// Emit the {Transfer} event.
mstore(0x20, amount)
log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, shr(96, from_), shr(96, mload(0x0c)))
}
_afterTokenTransfer(from, to, amount);
return true;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EIP-2612 */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev For more performance, override to return the constant value
/// of `keccak256(bytes(name()))` if `name()` will never change.
function _constantNameHash() internal view virtual returns (bytes32 result) {}
/// @dev Returns the current nonce for `owner`.
/// This value is used to compute the signature for EIP-2612 permit.
function nonces(address owner) public view virtual returns (uint256 result) {
/// @solidity memory-safe-assembly
assembly {
// Compute the nonce slot and load its value.
mstore(0x0c, _NONCES_SLOT_SEED)
mstore(0x00, owner)
result := sload(keccak256(0x0c, 0x20))
}
}
/// @dev Sets `value` as the allowance of `spender` over the tokens of `owner`,
/// authorized by a signed approval by `owner`.
///
/// Emits a {Approval} event.
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual {
bytes32 nameHash = _constantNameHash();
// We simply calculate it on-the-fly to allow for cases where the `name` may change.
if (nameHash == bytes32(0)) nameHash = keccak256(bytes(name()));
/// @solidity memory-safe-assembly
assembly {
// Revert if the block timestamp is greater than `deadline`.
if gt(timestamp(), deadline) {
mstore(0x00, 0x1a15a3cc) // `PermitExpired()`.
revert(0x1c, 0x04)
}
let m := mload(0x40) // Grab the free memory pointer.
// Clean the upper 96 bits.
owner := shr(96, shl(96, owner))
spender := shr(96, shl(96, spender))
// Compute the nonce slot and load its value.
mstore(0x0e, _NONCES_SLOT_SEED_WITH_SIGNATURE_PREFIX)
mstore(0x00, owner)
let nonceSlot := keccak256(0x0c, 0x20)
let nonceValue := sload(nonceSlot)
// Prepare the domain separator.
mstore(m, _DOMAIN_TYPEHASH)
mstore(add(m, 0x20), nameHash)
mstore(add(m, 0x40), _VERSION_HASH)
mstore(add(m, 0x60), chainid())
mstore(add(m, 0x80), address())
mstore(0x2e, keccak256(m, 0xa0))
// Prepare the struct hash.
mstore(m, _PERMIT_TYPEHASH)
mstore(add(m, 0x20), owner)
mstore(add(m, 0x40), spender)
mstore(add(m, 0x60), value)
mstore(add(m, 0x80), nonceValue)
mstore(add(m, 0xa0), deadline)
mstore(0x4e, keccak256(m, 0xc0))
// Prepare the ecrecover calldata.
mstore(0x00, keccak256(0x2c, 0x42))
mstore(0x20, and(0xff, v))
mstore(0x40, r)
mstore(0x60, s)
let t := staticcall(gas(), 1, 0, 0x80, 0x20, 0x20)
// If the ecrecover fails, the returndatasize will be 0x00,
// `owner` will be checked if it equals the hash at 0x00,
// which evaluates to false (i.e. 0), and we will revert.
// If the ecrecover succeeds, the returndatasize will be 0x20,
// `owner` will be compared against the returned address at 0x20.
if iszero(eq(mload(returndatasize()), owner)) {
mstore(0x00, 0xddafbaef) // `InvalidPermit()`.
revert(0x1c, 0x04)
}
// Increment and store the updated nonce.
sstore(nonceSlot, add(nonceValue, t)) // `t` is 1 if ecrecover succeeds.
// Compute the allowance slot and store the value.
// The `owner` is already at slot 0x20.
mstore(0x40, or(shl(160, _ALLOWANCE_SLOT_SEED), spender))
sstore(keccak256(0x2c, 0x34), value)
// Emit the {Approval} event.
log3(add(m, 0x60), 0x20, _APPROVAL_EVENT_SIGNATURE, owner, spender)
mstore(0x40, m) // Restore the free memory pointer.
mstore(0x60, 0) // Restore the zero pointer.
}
}
/// @dev Returns the EIP-712 domain separator for the EIP-2612 permit.
function DOMAIN_SEPARATOR() public view virtual returns (bytes32 result) {
bytes32 nameHash = _constantNameHash();
// We simply calculate it on-the-fly to allow for cases where the `name` may change.
if (nameHash == bytes32(0)) nameHash = keccak256(bytes(name()));
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Grab the free memory pointer.
mstore(m, _DOMAIN_TYPEHASH)
mstore(add(m, 0x20), nameHash)
mstore(add(m, 0x40), _VERSION_HASH)
mstore(add(m, 0x60), chainid())
mstore(add(m, 0x80), address())
result := keccak256(m, 0xa0)
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INTERNAL MINT FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Mints `amount` tokens to `to`, increasing the total supply.
///
/// Emits a {Transfer} event.
function _mint(address to, uint256 amount) internal virtual {
_beforeTokenTransfer(address(0), to, amount);
/// @solidity memory-safe-assembly
assembly {
let totalSupplyBefore := sload(_TOTAL_SUPPLY_SLOT)
let totalSupplyAfter := add(totalSupplyBefore, amount)
// Revert if the total supply overflows.
if lt(totalSupplyAfter, totalSupplyBefore) {
mstore(0x00, 0xe5cfe957) // `TotalSupplyOverflow()`.
revert(0x1c, 0x04)
}
// Store the updated total supply.
sstore(_TOTAL_SUPPLY_SLOT, totalSupplyAfter)
// Compute the balance slot and load its value.
mstore(0x0c, _BALANCE_SLOT_SEED)
mstore(0x00, to)
let toBalanceSlot := keccak256(0x0c, 0x20)
// Add and store the updated balance.
sstore(toBalanceSlot, add(sload(toBalanceSlot), amount))
// Emit the {Transfer} event.
mstore(0x20, amount)
log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, 0, shr(96, mload(0x0c)))
}
_afterTokenTransfer(address(0), to, amount);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INTERNAL BURN FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Burns `amount` tokens from `from`, reducing the total supply.
///
/// Emits a {Transfer} event.
function _burn(address from, uint256 amount) internal virtual {
_beforeTokenTransfer(from, address(0), amount);
/// @solidity memory-safe-assembly
assembly {
// Compute the balance slot and load its value.
mstore(0x0c, _BALANCE_SLOT_SEED)
mstore(0x00, from)
let fromBalanceSlot := keccak256(0x0c, 0x20)
let fromBalance := sload(fromBalanceSlot)
// Revert if insufficient balance.
if gt(amount, fromBalance) {
mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
revert(0x1c, 0x04)
}
// Subtract and store the updated balance.
sstore(fromBalanceSlot, sub(fromBalance, amount))
// Subtract and store the updated total supply.
sstore(_TOTAL_SUPPLY_SLOT, sub(sload(_TOTAL_SUPPLY_SLOT), amount))
// Emit the {Transfer} event.
mstore(0x00, amount)
log3(0x00, 0x20, _TRANSFER_EVENT_SIGNATURE, shr(96, shl(96, from)), 0)
}
_afterTokenTransfer(from, address(0), amount);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INTERNAL TRANSFER FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Moves `amount` of tokens from `from` to `to`.
function _transfer(address from, address to, uint256 amount) internal virtual {
_beforeTokenTransfer(from, to, amount);
/// @solidity memory-safe-assembly
assembly {
let from_ := shl(96, from)
// Compute the balance slot and load its value.
mstore(0x0c, or(from_, _BALANCE_SLOT_SEED))
let fromBalanceSlot := keccak256(0x0c, 0x20)
let fromBalance := sload(fromBalanceSlot)
// Revert if insufficient balance.
if gt(amount, fromBalance) {
mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
revert(0x1c, 0x04)
}
// Subtract and store the updated balance.
sstore(fromBalanceSlot, sub(fromBalance, amount))
// Compute the balance slot of `to`.
mstore(0x00, to)
let toBalanceSlot := keccak256(0x0c, 0x20)
// Add and store the updated balance of `to`.
// Will not overflow because the sum of all user balances
// cannot exceed the maximum uint256 value.
sstore(toBalanceSlot, add(sload(toBalanceSlot), amount))
// Emit the {Transfer} event.
mstore(0x20, amount)
log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, shr(96, from_), shr(96, mload(0x0c)))
}
_afterTokenTransfer(from, to, amount);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INTERNAL ALLOWANCE FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Updates the allowance of `owner` for `spender` based on spent `amount`.
function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {
/// @solidity memory-safe-assembly
assembly {
// Compute the allowance slot and load its value.
mstore(0x20, spender)
mstore(0x0c, _ALLOWANCE_SLOT_SEED)
mstore(0x00, owner)
let allowanceSlot := keccak256(0x0c, 0x34)
let allowance_ := sload(allowanceSlot)
// If the allowance is not the maximum uint256 value.
if add(allowance_, 1) {
// Revert if the amount to be transferred exceeds the allowance.
if gt(amount, allowance_) {
mstore(0x00, 0x13be252b) // `InsufficientAllowance()`.
revert(0x1c, 0x04)
}
// Subtract and store the updated allowance.
sstore(allowanceSlot, sub(allowance_, amount))
}
}
}
/// @dev Sets `amount` as the allowance of `spender` over the tokens of `owner`.
///
/// Emits a {Approval} event.
function _approve(address owner, address spender, uint256 amount) internal virtual {
/// @solidity memory-safe-assembly
assembly {
let owner_ := shl(96, owner)
// Compute the allowance slot and store the amount.
mstore(0x20, spender)
mstore(0x0c, or(owner_, _ALLOWANCE_SLOT_SEED))
sstore(keccak256(0x0c, 0x34), amount)
// Emit the {Approval} event.
mstore(0x00, amount)
log3(0x00, 0x20, _APPROVAL_EVENT_SIGNATURE, shr(96, owner_), shr(96, mload(0x2c)))
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* HOOKS TO OVERRIDE */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Hook that is called before any transfer of tokens.
/// This includes minting and burning.
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}
/// @dev Hook that is called after any transfer of tokens.
/// This includes minting and burning.
function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeTransferLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
///
/// @dev Note:
/// - For ETH transfers, please use `forceSafeTransferETH` for DoS protection.
/// - For ERC20s, this implementation won't check that a token has code,
/// responsibility is delegated to the caller.
library SafeTransferLib {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The ETH transfer has failed.
error ETHTransferFailed();
/// @dev The ERC20 `transferFrom` has failed.
error TransferFromFailed();
/// @dev The ERC20 `transfer` has failed.
error TransferFailed();
/// @dev The ERC20 `approve` has failed.
error ApproveFailed();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Suggested gas stipend for contract receiving ETH that disallows any storage writes.
uint256 internal constant GAS_STIPEND_NO_STORAGE_WRITES = 2300;
/// @dev Suggested gas stipend for contract receiving ETH to perform a few
/// storage reads and writes, but low enough to prevent griefing.
uint256 internal constant GAS_STIPEND_NO_GRIEF = 100000;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ETH OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
// If the ETH transfer MUST succeed with a reasonable gas budget, use the force variants.
//
// The regular variants:
// - Forwards all remaining gas to the target.
// - Reverts if the target reverts.
// - Reverts if the current contract has insufficient balance.
//
// The force variants:
// - Forwards with an optional gas stipend
// (defaults to `GAS_STIPEND_NO_GRIEF`, which is sufficient for most cases).
// - If the target reverts, or if the gas stipend is exhausted,
// creates a temporary contract to force send the ETH via `SELFDESTRUCT`.
// Future compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758.
// - Reverts if the current contract has insufficient balance.
//
// The try variants:
// - Forwards with a mandatory gas stipend.
// - Instead of reverting, returns whether the transfer succeeded.
/// @dev Sends `amount` (in wei) ETH to `to`.
function safeTransferETH(address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
if iszero(call(gas(), to, amount, codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
revert(0x1c, 0x04)
}
}
}
/// @dev Sends all the ETH in the current contract to `to`.
function safeTransferAllETH(address to) internal {
/// @solidity memory-safe-assembly
assembly {
// Transfer all the ETH and check if it succeeded or not.
if iszero(call(gas(), to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
revert(0x1c, 0x04)
}
}
}
/// @dev Force sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
function forceSafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal {
/// @solidity memory-safe-assembly
assembly {
if lt(selfbalance(), amount) {
mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
revert(0x1c, 0x04)
}
if iszero(call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, to) // Store the address in scratch space.
mstore8(0x0b, 0x73) // Opcode `PUSH20`.
mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
}
}
}
/// @dev Force sends all the ETH in the current contract to `to`, with a `gasStipend`.
function forceSafeTransferAllETH(address to, uint256 gasStipend) internal {
/// @solidity memory-safe-assembly
assembly {
if iszero(call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, to) // Store the address in scratch space.
mstore8(0x0b, 0x73) // Opcode `PUSH20`.
mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
}
}
}
/// @dev Force sends `amount` (in wei) ETH to `to`, with `GAS_STIPEND_NO_GRIEF`.
function forceSafeTransferETH(address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
if lt(selfbalance(), amount) {
mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
revert(0x1c, 0x04)
}
if iszero(call(GAS_STIPEND_NO_GRIEF, to, amount, codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, to) // Store the address in scratch space.
mstore8(0x0b, 0x73) // Opcode `PUSH20`.
mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
}
}
}
/// @dev Force sends all the ETH in the current contract to `to`, with `GAS_STIPEND_NO_GRIEF`.
function forceSafeTransferAllETH(address to) internal {
/// @solidity memory-safe-assembly
assembly {
// forgefmt: disable-next-item
if iszero(call(GAS_STIPEND_NO_GRIEF, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, to) // Store the address in scratch space.
mstore8(0x0b, 0x73) // Opcode `PUSH20`.
mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
}
}
}
/// @dev Sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
function trySafeTransferETH(address to, uint256 amount, uint256 gasStipend)
internal
returns (bool success)
{
/// @solidity memory-safe-assembly
assembly {
success := call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)
}
}
/// @dev Sends all the ETH in the current contract to `to`, with a `gasStipend`.
function trySafeTransferAllETH(address to, uint256 gasStipend)
internal
returns (bool success)
{
/// @solidity memory-safe-assembly
assembly {
success := call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ERC20 OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Sends `amount` of ERC20 `token` from `from` to `to`.
/// Reverts upon failure.
///
/// The `from` account must have at least `amount` approved for
/// the current contract to manage.
function safeTransferFrom(address token, address from, address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x60, amount) // Store the `amount` argument.
mstore(0x40, to) // Store the `to` argument.
mstore(0x2c, shl(96, from)) // Store the `from` argument.
mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`.
// Perform the transfer, reverting upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
)
) {
mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
revert(0x1c, 0x04)
}
mstore(0x60, 0) // Restore the zero slot to zero.
mstore(0x40, m) // Restore the free memory pointer.
}
}
/// @dev Sends all of ERC20 `token` from `from` to `to`.
/// Reverts upon failure.
///
/// The `from` account must have their entire balance approved for
/// the current contract to manage.
function safeTransferAllFrom(address token, address from, address to)
internal
returns (uint256 amount)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x40, to) // Store the `to` argument.
mstore(0x2c, shl(96, from)) // Store the `from` argument.
mstore(0x0c, 0x70a08231000000000000000000000000) // `balanceOf(address)`.
// Read the balance, reverting upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
gt(returndatasize(), 0x1f), // At least 32 bytes returned.
staticcall(gas(), token, 0x1c, 0x24, 0x60, 0x20)
)
) {
mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
revert(0x1c, 0x04)
}
mstore(0x00, 0x23b872dd) // `transferFrom(address,address,uint256)`.
amount := mload(0x60) // The `amount` is already at 0x60. We'll need to return it.
// Perform the transfer, reverting upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
)
) {
mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
revert(0x1c, 0x04)
}
mstore(0x60, 0) // Restore the zero slot to zero.
mstore(0x40, m) // Restore the free memory pointer.
}
}
/// @dev Sends `amount` of ERC20 `token` from the current contract to `to`.
/// Reverts upon failure.
function safeTransfer(address token, address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x14, to) // Store the `to` argument.
mstore(0x34, amount) // Store the `amount` argument.
mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.
// Perform the transfer, reverting upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
)
) {
mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
revert(0x1c, 0x04)
}
mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
}
}
/// @dev Sends all of ERC20 `token` from the current contract to `to`.
/// Reverts upon failure.
function safeTransferAll(address token, address to) internal returns (uint256 amount) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`.
mstore(0x20, address()) // Store the address of the current contract.
// Read the balance, reverting upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
gt(returndatasize(), 0x1f), // At least 32 bytes returned.
staticcall(gas(), token, 0x1c, 0x24, 0x34, 0x20)
)
) {
mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
revert(0x1c, 0x04)
}
mstore(0x14, to) // Store the `to` argument.
amount := mload(0x34) // The `amount` is already at 0x34. We'll need to return it.
mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.
// Perform the transfer, reverting upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
)
) {
mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
revert(0x1c, 0x04)
}
mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
}
}
/// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
/// Reverts upon failure.
function safeApprove(address token, address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x14, to) // Store the `to` argument.
mstore(0x34, amount) // Store the `amount` argument.
mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
// Perform the approval, reverting upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
)
) {
mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.
revert(0x1c, 0x04)
}
mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
}
}
/// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
/// If the initial attempt to approve fails, attempts to reset the approved amount to zero,
/// then retries the approval again (some tokens, e.g. USDT, requires this).
/// Reverts upon failure.
function safeApproveWithRetry(address token, address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x14, to) // Store the `to` argument.
mstore(0x34, amount) // Store the `amount` argument.
mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
// Perform the approval, retrying upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
)
) {
mstore(0x34, 0) // Store 0 for the `amount`.
mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
pop(call(gas(), token, 0, 0x10, 0x44, codesize(), 0x00)) // Reset the approval.
mstore(0x34, amount) // Store back the original `amount`.
// Retry the approval, reverting upon failure.
if iszero(
and(
or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
)
) {
mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.
revert(0x1c, 0x04)
}
}
mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
}
}
/// @dev Returns the amount of ERC20 `token` owned by `account`.
/// Returns zero if the `token` does not exist.
function balanceOf(address token, address account) internal view returns (uint256 amount) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x14, account) // Store the `account` argument.
mstore(0x00, 0x70a08231000000000000000000000000) // `balanceOf(address)`.
amount :=
mul(
mload(0x20),
and( // The arguments of `and` are evaluated from right to left.
gt(returndatasize(), 0x1f), // At least 32 bytes returned.
staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20)
)
)
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Arithmetic library with operations for fixed-point numbers.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/FixedPointMathLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol)
library FixedPointMathLib {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The operation failed, as the output exceeds the maximum value of uint256.
error ExpOverflow();
/// @dev The operation failed, as the output exceeds the maximum value of uint256.
error FactorialOverflow();
/// @dev The operation failed, due to an overflow.
error RPowOverflow();
/// @dev The mantissa is too big to fit.
error MantissaOverflow();
/// @dev The operation failed, due to an multiplication overflow.
error MulWadFailed();
/// @dev The operation failed, due to an multiplication overflow.
error SMulWadFailed();
/// @dev The operation failed, either due to a multiplication overflow, or a division by a zero.
error DivWadFailed();
/// @dev The operation failed, either due to a multiplication overflow, or a division by a zero.
error SDivWadFailed();
/// @dev The operation failed, either due to a multiplication overflow, or a division by a zero.
error MulDivFailed();
/// @dev The division failed, as the denominator is zero.
error DivFailed();
/// @dev The full precision multiply-divide operation failed, either due
/// to the result being larger than 256 bits, or a division by a zero.
error FullMulDivFailed();
/// @dev The output is undefined, as the input is less-than-or-equal to zero.
error LnWadUndefined();
/// @dev The input outside the acceptable domain.
error OutOfDomain();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The scalar of ETH and most ERC20s.
uint256 internal constant WAD = 1e18;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* SIMPLIFIED FIXED POINT OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Equivalent to `(x * y) / WAD` rounded down.
function mulWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to `require(y == 0 || x <= type(uint256).max / y)`.
if mul(y, gt(x, div(not(0), y))) {
mstore(0x00, 0xbac65e5b) // `MulWadFailed()`.
revert(0x1c, 0x04)
}
z := div(mul(x, y), WAD)
}
}
/// @dev Equivalent to `(x * y) / WAD` rounded down.
function sMulWad(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(x, y)
// Equivalent to `require((x == 0 || z / x == y) && !(x == -1 && y == type(int256).min))`.
if iszero(gt(or(iszero(x), eq(sdiv(z, x), y)), lt(not(x), eq(y, shl(255, 1))))) {
mstore(0x00, 0xedcd4dd4) // `SMulWadFailed()`.
revert(0x1c, 0x04)
}
z := sdiv(z, WAD)
}
}
/// @dev Equivalent to `(x * y) / WAD` rounded down, but without overflow checks.
function rawMulWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := div(mul(x, y), WAD)
}
}
/// @dev Equivalent to `(x * y) / WAD` rounded down, but without overflow checks.
function rawSMulWad(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := sdiv(mul(x, y), WAD)
}
}
/// @dev Equivalent to `(x * y) / WAD` rounded up.
function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to `require(y == 0 || x <= type(uint256).max / y)`.
if mul(y, gt(x, div(not(0), y))) {
mstore(0x00, 0xbac65e5b) // `MulWadFailed()`.
revert(0x1c, 0x04)
}
z := add(iszero(iszero(mod(mul(x, y), WAD))), div(mul(x, y), WAD))
}
}
/// @dev Equivalent to `(x * y) / WAD` rounded up, but without overflow checks.
function rawMulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := add(iszero(iszero(mod(mul(x, y), WAD))), div(mul(x, y), WAD))
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded down.
function divWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to `require(y != 0 && (WAD == 0 || x <= type(uint256).max / WAD))`.
if iszero(mul(y, iszero(mul(WAD, gt(x, div(not(0), WAD)))))) {
mstore(0x00, 0x7c5f487d) // `DivWadFailed()`.
revert(0x1c, 0x04)
}
z := div(mul(x, WAD), y)
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded down.
function sDivWad(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(x, WAD)
// Equivalent to `require(y != 0 && ((x * WAD) / WAD == x))`.
if iszero(and(iszero(iszero(y)), eq(sdiv(z, WAD), x))) {
mstore(0x00, 0x5c43740d) // `SDivWadFailed()`.
revert(0x1c, 0x04)
}
z := sdiv(mul(x, WAD), y)
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded down, but without overflow and divide by zero checks.
function rawDivWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := div(mul(x, WAD), y)
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded down, but without overflow and divide by zero checks.
function rawSDivWad(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := sdiv(mul(x, WAD), y)
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded up.
function divWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to `require(y != 0 && (WAD == 0 || x <= type(uint256).max / WAD))`.
if iszero(mul(y, iszero(mul(WAD, gt(x, div(not(0), WAD)))))) {
mstore(0x00, 0x7c5f487d) // `DivWadFailed()`.
revert(0x1c, 0x04)
}
z := add(iszero(iszero(mod(mul(x, WAD), y))), div(mul(x, WAD), y))
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded up, but without overflow and divide by zero checks.
function rawDivWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := add(iszero(iszero(mod(mul(x, WAD), y))), div(mul(x, WAD), y))
}
}
/// @dev Equivalent to `x` to the power of `y`.
/// because `x ** y = (e ** ln(x)) ** y = e ** (ln(x) * y)`.
function powWad(int256 x, int256 y) internal pure returns (int256) {
// Using `ln(x)` means `x` must be greater than 0.
return expWad((lnWad(x) * y) / int256(WAD));
}
/// @dev Returns `exp(x)`, denominated in `WAD`.
/// Credit to Remco Bloemen under MIT license: https://2π.com/22/exp-ln
function expWad(int256 x) internal pure returns (int256 r) {
unchecked {
// When the result is less than 0.5 we return zero.
// This happens when `x <= (log(1e-18) * 1e18) ~ -4.15e19`.
if (x <= -41446531673892822313) return r;
/// @solidity memory-safe-assembly
assembly {
// When the result is greater than `(2**255 - 1) / 1e18` we can not represent it as
// an int. This happens when `x >= floor(log((2**255 - 1) / 1e18) * 1e18) ≈ 135`.
if iszero(slt(x, 135305999368893231589)) {
mstore(0x00, 0xa37bfec9) // `ExpOverflow()`.
revert(0x1c, 0x04)
}
}
// `x` is now in the range `(-42, 136) * 1e18`. Convert to `(-42, 136) * 2**96`
// for more intermediate precision and a binary basis. This base conversion
// is a multiplication by 1e18 / 2**96 = 5**18 / 2**78.
x = (x << 78) / 5 ** 18;
// Reduce range of x to (-½ ln 2, ½ ln 2) * 2**96 by factoring out powers
// of two such that exp(x) = exp(x') * 2**k, where k is an integer.
// Solving this gives k = round(x / log(2)) and x' = x - k * log(2).
int256 k = ((x << 96) / 54916777467707473351141471128 + 2 ** 95) >> 96;
x = x - k * 54916777467707473351141471128;
// `k` is in the range `[-61, 195]`.
// Evaluate using a (6, 7)-term rational approximation.
// `p` is made monic, we'll multiply by a scale factor later.
int256 y = x + 1346386616545796478920950773328;
y = ((y * x) >> 96) + 57155421227552351082224309758442;
int256 p = y + x - 94201549194550492254356042504812;
p = ((p * y) >> 96) + 28719021644029726153956944680412240;
p = p * x + (4385272521454847904659076985693276 << 96);
// We leave `p` in `2**192` basis so we don't need to scale it back up for the division.
int256 q = x - 2855989394907223263936484059900;
q = ((q * x) >> 96) + 50020603652535783019961831881945;
q = ((q * x) >> 96) - 533845033583426703283633433725380;
q = ((q * x) >> 96) + 3604857256930695427073651918091429;
q = ((q * x) >> 96) - 14423608567350463180887372962807573;
q = ((q * x) >> 96) + 26449188498355588339934803723976023;
/// @solidity memory-safe-assembly
assembly {
// Div in assembly because solidity adds a zero check despite the unchecked.
// The q polynomial won't have zeros in the domain as all its roots are complex.
// No scaling is necessary because p is already `2**96` too large.
r := sdiv(p, q)
}
// r should be in the range `(0.09, 0.25) * 2**96`.
// We now need to multiply r by:
// - The scale factor `s ≈ 6.031367120`.
// - The `2**k` factor from the range reduction.
// - The `1e18 / 2**96` factor for base conversion.
// We do this all at once, with an intermediate result in `2**213`
// basis, so the final right shift is always by a positive amount.
r = int256(
(uint256(r) * 3822833074963236453042738258902158003155416615667) >> uint256(195 - k)
);
}
}
/// @dev Returns `ln(x)`, denominated in `WAD`.
/// Credit to Remco Bloemen under MIT license: https://2π.com/22/exp-ln
function lnWad(int256 x) internal pure returns (int256 r) {
/// @solidity memory-safe-assembly
assembly {
// We want to convert `x` from `10**18` fixed point to `2**96` fixed point.
// We do this by multiplying by `2**96 / 10**18`. But since
// `ln(x * C) = ln(x) + ln(C)`, we can simply do nothing here
// and add `ln(2**96 / 10**18)` at the end.
// Compute `k = log2(x) - 96`, `r = 159 - k = 255 - log2(x) = 255 ^ log2(x)`.
r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
// We place the check here for more optimal stack operations.
if iszero(sgt(x, 0)) {
mstore(0x00, 0x1615e638) // `LnWadUndefined()`.
revert(0x1c, 0x04)
}
// forgefmt: disable-next-item
r := xor(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),
0xf8f9f9faf9fdfafbf9fdfcfdfafbfcfef9fafdfafcfcfbfefafafcfbffffffff))
// Reduce range of x to (1, 2) * 2**96
// ln(2^k * x) = k * ln(2) + ln(x)
x := shr(159, shl(r, x))
// Evaluate using a (8, 8)-term rational approximation.
// `p` is made monic, we will multiply by a scale factor later.
// forgefmt: disable-next-item
let p := sub( // This heavily nested expression is to avoid stack-too-deep for via-ir.
sar(96, mul(add(43456485725739037958740375743393,
sar(96, mul(add(24828157081833163892658089445524,
sar(96, mul(add(3273285459638523848632254066296,
x), x))), x))), x)), 11111509109440967052023855526967)
p := sub(sar(96, mul(p, x)), 45023709667254063763336534515857)
p := sub(sar(96, mul(p, x)), 14706773417378608786704636184526)
p := sub(mul(p, x), shl(96, 795164235651350426258249787498))
// We leave `p` in `2**192` basis so we don't need to scale it back up for the division.
// `q` is monic by convention.
let q := add(5573035233440673466300451813936, x)
q := add(71694874799317883764090561454958, sar(96, mul(x, q)))
q := add(283447036172924575727196451306956, sar(96, mul(x, q)))
q := add(401686690394027663651624208769553, sar(96, mul(x, q)))
q := add(204048457590392012362485061816622, sar(96, mul(x, q)))
q := add(31853899698501571402653359427138, sar(96, mul(x, q)))
q := add(909429971244387300277376558375, sar(96, mul(x, q)))
// `p / q` is in the range `(0, 0.125) * 2**96`.
// Finalization, we need to:
// - Multiply by the scale factor `s = 5.549…`.
// - Add `ln(2**96 / 10**18)`.
// - Add `k * ln(2)`.
// - Multiply by `10**18 / 2**96 = 5**18 >> 78`.
// The q polynomial is known not to have zeros in the domain.
// No scaling required because p is already `2**96` too large.
p := sdiv(p, q)
// Multiply by the scaling factor: `s * 5**18 * 2**96`, base is now `5**18 * 2**192`.
p := mul(1677202110996718588342820967067443963516166, p)
// Add `ln(2) * k * 5**18 * 2**192`.
// forgefmt: disable-next-item
p := add(mul(16597577552685614221487285958193947469193820559219878177908093499208371, sub(159, r)), p)
// Add `ln(2**96 / 10**18) * 5**18 * 2**192`.
p := add(600920179829731861736702779321621459595472258049074101567377883020018308, p)
// Base conversion: mul `2**18 / 2**192`.
r := sar(174, p)
}
}
/// @dev Returns `W_0(x)`, denominated in `WAD`.
/// See: https://en.wikipedia.org/wiki/Lambert_W_function
/// a.k.a. Product log function. This is an approximation of the principal branch.
function lambertW0Wad(int256 x) internal pure returns (int256 w) {
// forgefmt: disable-next-item
unchecked {
if ((w = x) <= -367879441171442322) revert OutOfDomain(); // `x` less than `-1/e`.
int256 wad = int256(WAD);
int256 p = x;
uint256 c; // Whether we need to avoid catastrophic cancellation.
uint256 i = 4; // Number of iterations.
if (w <= 0x1ffffffffffff) {
if (-0x4000000000000 <= w) {
i = 1; // Inputs near zero only take one step to converge.
} else if (w <= -0x3ffffffffffffff) {
i = 32; // Inputs near `-1/e` take very long to converge.
}
} else if (w >> 63 == 0) {
/// @solidity memory-safe-assembly
assembly {
// Inline log2 for more performance, since the range is small.
let v := shr(49, w)
let l := shl(3, lt(0xff, v))
l := add(or(l, byte(and(0x1f, shr(shr(l, v), 0x8421084210842108cc6318c6db6d54be)),
0x0706060506020504060203020504030106050205030304010505030400000000)), 49)
w := sdiv(shl(l, 7), byte(sub(l, 31), 0x0303030303030303040506080c13))
c := gt(l, 60)
i := add(2, add(gt(l, 53), c))
}
} else {
int256 ll = lnWad(w = lnWad(w));
/// @solidity memory-safe-assembly
assembly {
// `w = ln(x) - ln(ln(x)) + b * ln(ln(x)) / ln(x)`.
w := add(sdiv(mul(ll, 1023715080943847266), w), sub(w, ll))
i := add(3, iszero(shr(68, x)))
c := iszero(shr(143, x))
}
if (c == 0) {
do { // If `x` is big, use Newton's so that intermediate values won't overflow.
int256 e = expWad(w);
/// @solidity memory-safe-assembly
assembly {
let t := mul(w, div(e, wad))
w := sub(w, sdiv(sub(t, x), div(add(e, t), wad)))
}
if (p <= w) break;
p = w;
} while (--i != 0);
/// @solidity memory-safe-assembly
assembly {
w := sub(w, sgt(w, 2))
}
return w;
}
}
do { // Otherwise, use Halley's for faster convergence.
int256 e = expWad(w);
/// @solidity memory-safe-assembly
assembly {
let t := add(w, wad)
let s := sub(mul(w, e), mul(x, wad))
w := sub(w, sdiv(mul(s, wad), sub(mul(e, t), sdiv(mul(add(t, wad), s), add(t, t)))))
}
if (p <= w) break;
p = w;
} while (--i != c);
/// @solidity memory-safe-assembly
assembly {
w := sub(w, sgt(w, 2))
}
// For certain ranges of `x`, we'll use the quadratic-rate recursive formula of
// R. Iacono and J.P. Boyd for the last iteration, to avoid catastrophic cancellation.
if (c != 0) {
int256 t = w | 1;
/// @solidity memory-safe-assembly
assembly {
x := sdiv(mul(x, wad), t)
}
x = (t * (wad + lnWad(x)));
/// @solidity memory-safe-assembly
assembly {
w := sdiv(x, add(wad, t))
}
}
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* GENERAL NUMBER UTILITIES */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Calculates `floor(x * y / d)` with full precision.
/// Throws if result overflows a uint256 or when `d` is zero.
/// Credit to Remco Bloemen under MIT license: https://2π.com/21/muldiv
function fullMulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 result) {
/// @solidity memory-safe-assembly
assembly {
for {} 1 {} {
// 512-bit multiply `[p1 p0] = x * y`.
// Compute the product mod `2**256` and mod `2**256 - 1`
// then use the Chinese Remainder Theorem to reconstruct
// the 512 bit result. The result is stored in two 256
// variables such that `product = p1 * 2**256 + p0`.
// Least significant 256 bits of the product.
result := mul(x, y) // Temporarily use `result` as `p0` to save gas.
let mm := mulmod(x, y, not(0))
// Most significant 256 bits of the product.
let p1 := sub(mm, add(result, lt(mm, result)))
// Handle non-overflow cases, 256 by 256 division.
if iszero(p1) {
if iszero(d) {
mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
revert(0x1c, 0x04)
}
result := div(result, d)
break
}
// Make sure the result is less than `2**256`. Also prevents `d == 0`.
if iszero(gt(d, p1)) {
mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
revert(0x1c, 0x04)
}
/*------------------- 512 by 256 division --------------------*/
// Make division exact by subtracting the remainder from `[p1 p0]`.
// Compute remainder using mulmod.
let r := mulmod(x, y, d)
// `t` is the least significant bit of `d`.
// Always greater or equal to 1.
let t := and(d, sub(0, d))
// Divide `d` by `t`, which is a power of two.
d := div(d, t)
// Invert `d mod 2**256`
// Now that `d` is an odd number, it has an inverse
// modulo `2**256` such that `d * inv = 1 mod 2**256`.
// Compute the inverse by starting with a seed that is correct
// correct for four bits. That is, `d * inv = 1 mod 2**4`.
let inv := xor(2, mul(3, d))
// Now use 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.
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**8
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**16
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**32
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**64
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**128
result :=
mul(
// Divide [p1 p0] by the factors of two.
// Shift in bits from `p1` into `p0`. For this we need
// to flip `t` such that it is `2**256 / t`.
or(
mul(sub(p1, gt(r, result)), add(div(sub(0, t), t), 1)),
div(sub(result, r), t)
),
// inverse mod 2**256
mul(inv, sub(2, mul(d, inv)))
)
break
}
}
}
/// @dev Calculates `floor(x * y / d)` with full precision, rounded up.
/// Throws if result overflows a uint256 or when `d` is zero.
/// Credit to Uniswap-v3-core under MIT license:
/// https://github.com/Uniswap/v3-core/blob/main/contracts/libraries/FullMath.sol
function fullMulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 result) {
result = fullMulDiv(x, y, d);
/// @solidity memory-safe-assembly
assembly {
if mulmod(x, y, d) {
result := add(result, 1)
if iszero(result) {
mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
revert(0x1c, 0x04)
}
}
}
}
/// @dev Returns `floor(x * y / d)`.
/// Reverts if `x * y` overflows, or `d` is zero.
function mulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to require(d != 0 && (y == 0 || x <= type(uint256).max / y))
if iszero(mul(d, iszero(mul(y, gt(x, div(not(0), y)))))) {
mstore(0x00, 0xad251c27) // `MulDivFailed()`.
revert(0x1c, 0x04)
}
z := div(mul(x, y), d)
}
}
/// @dev Returns `ceil(x * y / d)`.
/// Reverts if `x * y` overflows, or `d` is zero.
function mulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to require(d != 0 && (y == 0 || x <= type(uint256).max / y))
if iszero(mul(d, iszero(mul(y, gt(x, div(not(0), y)))))) {
mstore(0x00, 0xad251c27) // `MulDivFailed()`.
revert(0x1c, 0x04)
}
z := add(iszero(iszero(mod(mul(x, y), d))), div(mul(x, y), d))
}
}
/// @dev Returns `ceil(x / d)`.
/// Reverts if `d` is zero.
function divUp(uint256 x, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
if iszero(d) {
mstore(0x00, 0x65244e4e) // `DivFailed()`.
revert(0x1c, 0x04)
}
z := add(iszero(iszero(mod(x, d))), div(x, d))
}
}
/// @dev Returns `max(0, x - y)`.
function zeroFloorSub(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(gt(x, y), sub(x, y))
}
}
/// @dev Exponentiate `x` to `y` by squaring, denominated in base `b`.
/// Reverts if the computation overflows.
function rpow(uint256 x, uint256 y, uint256 b) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(b, iszero(y)) // `0 ** 0 = 1`. Otherwise, `0 ** n = 0`.
if x {
z := xor(b, mul(xor(b, x), and(y, 1))) // `z = isEven(y) ? scale : x`
let half := shr(1, b) // Divide `b` by 2.
// Divide `y` by 2 every iteration.
for { y := shr(1, y) } y { y := shr(1, y) } {
let xx := mul(x, x) // Store x squared.
let xxRound := add(xx, half) // Round to the nearest number.
// Revert if `xx + half` overflowed, or if `x ** 2` overflows.
if or(lt(xxRound, xx), shr(128, x)) {
mstore(0x00, 0x49f7642b) // `RPowOverflow()`.
revert(0x1c, 0x04)
}
x := div(xxRound, b) // Set `x` to scaled `xxRound`.
// If `y` is odd:
if and(y, 1) {
let zx := mul(z, x) // Compute `z * x`.
let zxRound := add(zx, half) // Round to the nearest number.
// If `z * x` overflowed or `zx + half` overflowed:
if or(xor(div(zx, x), z), lt(zxRound, zx)) {
// Revert if `x` is non-zero.
if iszero(iszero(x)) {
mstore(0x00, 0x49f7642b) // `RPowOverflow()`.
revert(0x1c, 0x04)
}
}
z := div(zxRound, b) // Return properly scaled `zxRound`.
}
}
}
}
}
/// @dev Returns the square root of `x`.
function sqrt(uint256 x) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// `floor(sqrt(2**15)) = 181`. `sqrt(2**15) - 181 = 2.84`.
z := 181 // The "correct" value is 1, but this saves a multiplication later.
// This segment is to get a reasonable initial estimate for the Babylonian method. With a bad
// start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.
// Let `y = x / 2**r`. We check `y >= 2**(k + 8)`
// but shift right by `k` bits to ensure that if `x >= 256`, then `y >= 256`.
let r := shl(7, lt(0xffffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffffff, shr(r, x))))
z := shl(shr(1, r), z)
// Goal was to get `z*z*y` within a small factor of `x`. More iterations could
// get y in a tighter range. Currently, we will have y in `[256, 256*(2**16))`.
// We ensured `y >= 256` so that the relative difference between `y` and `y+1` is small.
// That's not possible if `x < 256` but we can just verify those cases exhaustively.
// Now, `z*z*y <= x < z*z*(y+1)`, and `y <= 2**(16+8)`, and either `y >= 256`, or `x < 256`.
// Correctness can be checked exhaustively for `x < 256`, so we assume `y >= 256`.
// Then `z*sqrt(y)` is within `sqrt(257)/sqrt(256)` of `sqrt(x)`, or about 20bps.
// For `s` in the range `[1/256, 256]`, the estimate `f(s) = (181/1024) * (s+1)`
// is in the range `(1/2.84 * sqrt(s), 2.84 * sqrt(s))`,
// with largest error when `s = 1` and when `s = 256` or `1/256`.
// Since `y` is in `[256, 256*(2**16))`, let `a = y/65536`, so that `a` is in `[1/256, 256)`.
// Then we can estimate `sqrt(y)` using
// `sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2**18`.
// There is no overflow risk here since `y < 2**136` after the first branch above.
z := shr(18, mul(z, add(shr(r, x), 65536))) // A `mul()` is saved from starting `z` at 181.
// Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
// If `x+1` is a perfect square, the Babylonian method cycles between
// `floor(sqrt(x))` and `ceil(sqrt(x))`. This statement ensures we return floor.
// See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division
z := sub(z, lt(div(x, z), z))
}
}
/// @dev Returns the cube root of `x`.
/// Credit to bout3fiddy and pcaversaccio under AGPLv3 license:
/// https://github.com/pcaversaccio/snekmate/blob/main/src/utils/Math.vy
function cbrt(uint256 x) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
let r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
z := div(shl(div(r, 3), shl(lt(0xf, shr(r, x)), 0xf)), xor(7, mod(r, 3)))
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := sub(z, lt(div(x, mul(z, z)), z))
}
}
/// @dev Returns the square root of `x`, denominated in `WAD`.
function sqrtWad(uint256 x) internal pure returns (uint256 z) {
unchecked {
z = 10 ** 9;
if (x <= type(uint256).max / 10 ** 36 - 1) {
x *= 10 ** 18;
z = 1;
}
z *= sqrt(x);
}
}
/// @dev Returns the cube root of `x`, denominated in `WAD`.
function cbrtWad(uint256 x) internal pure returns (uint256 z) {
unchecked {
z = 10 ** 12;
if (x <= (type(uint256).max / 10 ** 36) * 10 ** 18 - 1) {
if (x >= type(uint256).max / 10 ** 36) {
x *= 10 ** 18;
z = 10 ** 6;
} else {
x *= 10 ** 36;
z = 1;
}
}
z *= cbrt(x);
}
}
/// @dev Returns the factorial of `x`.
function factorial(uint256 x) internal pure returns (uint256 result) {
/// @solidity memory-safe-assembly
assembly {
if iszero(lt(x, 58)) {
mstore(0x00, 0xaba0f2a2) // `FactorialOverflow()`.
revert(0x1c, 0x04)
}
for { result := 1 } x { x := sub(x, 1) } { result := mul(result, x) }
}
}
/// @dev Returns the log2 of `x`.
/// Equivalent to computing the index of the most significant bit (MSB) of `x`.
/// Returns 0 if `x` is zero.
function log2(uint256 x) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
// forgefmt: disable-next-item
r := or(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),
0x0706060506020504060203020504030106050205030304010505030400000000))
}
}
/// @dev Returns the log2 of `x`, rounded up.
/// Returns 0 if `x` is zero.
function log2Up(uint256 x) internal pure returns (uint256 r) {
r = log2(x);
/// @solidity memory-safe-assembly
assembly {
r := add(r, lt(shl(r, 1), x))
}
}
/// @dev Returns the log10 of `x`.
/// Returns 0 if `x` is zero.
function log10(uint256 x) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
if iszero(lt(x, 100000000000000000000000000000000000000)) {
x := div(x, 100000000000000000000000000000000000000)
r := 38
}
if iszero(lt(x, 100000000000000000000)) {
x := div(x, 100000000000000000000)
r := add(r, 20)
}
if iszero(lt(x, 10000000000)) {
x := div(x, 10000000000)
r := add(r, 10)
}
if iszero(lt(x, 100000)) {
x := div(x, 100000)
r := add(r, 5)
}
r := add(r, add(gt(x, 9), add(gt(x, 99), add(gt(x, 999), gt(x, 9999)))))
}
}
/// @dev Returns the log10 of `x`, rounded up.
/// Returns 0 if `x` is zero.
function log10Up(uint256 x) internal pure returns (uint256 r) {
r = log10(x);
/// @solidity memory-safe-assembly
assembly {
r := add(r, lt(exp(10, r), x))
}
}
/// @dev Returns the log256 of `x`.
/// Returns 0 if `x` is zero.
function log256(uint256 x) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(shr(3, r), lt(0xff, shr(r, x)))
}
}
/// @dev Returns the log256 of `x`, rounded up.
/// Returns 0 if `x` is zero.
function log256Up(uint256 x) internal pure returns (uint256 r) {
r = log256(x);
/// @solidity memory-safe-assembly
assembly {
r := add(r, lt(shl(shl(3, r), 1), x))
}
}
/// @dev Returns the scientific notation format `mantissa * 10 ** exponent` of `x`.
/// Useful for compressing prices (e.g. using 25 bit mantissa and 7 bit exponent).
function sci(uint256 x) internal pure returns (uint256 mantissa, uint256 exponent) {
/// @solidity memory-safe-assembly
assembly {
mantissa := x
if mantissa {
if iszero(mod(mantissa, 1000000000000000000000000000000000)) {
mantissa := div(mantissa, 1000000000000000000000000000000000)
exponent := 33
}
if iszero(mod(mantissa, 10000000000000000000)) {
mantissa := div(mantissa, 10000000000000000000)
exponent := add(exponent, 19)
}
if iszero(mod(mantissa, 1000000000000)) {
mantissa := div(mantissa, 1000000000000)
exponent := add(exponent, 12)
}
if iszero(mod(mantissa, 1000000)) {
mantissa := div(mantissa, 1000000)
exponent := add(exponent, 6)
}
if iszero(mod(mantissa, 10000)) {
mantissa := div(mantissa, 10000)
exponent := add(exponent, 4)
}
if iszero(mod(mantissa, 100)) {
mantissa := div(mantissa, 100)
exponent := add(exponent, 2)
}
if iszero(mod(mantissa, 10)) {
mantissa := div(mantissa, 10)
exponent := add(exponent, 1)
}
}
}
}
/// @dev Convenience function for packing `x` into a smaller number using `sci`.
/// The `mantissa` will be in bits [7..255] (the upper 249 bits).
/// The `exponent` will be in bits [0..6] (the lower 7 bits).
/// Use `SafeCastLib` to safely ensure that the `packed` number is small
/// enough to fit in the desired unsigned integer type:
/// ```
/// uint32 packed = SafeCastLib.toUint32(FixedPointMathLib.packSci(777 ether));
/// ```
function packSci(uint256 x) internal pure returns (uint256 packed) {
(x, packed) = sci(x); // Reuse for `mantissa` and `exponent`.
/// @solidity memory-safe-assembly
assembly {
if shr(249, x) {
mstore(0x00, 0xce30380c) // `MantissaOverflow()`.
revert(0x1c, 0x04)
}
packed := or(shl(7, x), packed)
}
}
/// @dev Convenience function for unpacking a packed number from `packSci`.
function unpackSci(uint256 packed) internal pure returns (uint256 unpacked) {
unchecked {
unpacked = (packed >> 7) * 10 ** (packed & 0x7f);
}
}
/// @dev Returns the average of `x` and `y`.
function avg(uint256 x, uint256 y) internal pure returns (uint256 z) {
unchecked {
z = (x & y) + ((x ^ y) >> 1);
}
}
/// @dev Returns the average of `x` and `y`.
function avg(int256 x, int256 y) internal pure returns (int256 z) {
unchecked {
z = (x >> 1) + (y >> 1) + (((x & 1) + (y & 1)) >> 1);
}
}
/// @dev Returns the absolute value of `x`.
function abs(int256 x) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(sub(0, shr(255, x)), add(sub(0, shr(255, x)), x))
}
}
/// @dev Returns the absolute distance between `x` and `y`.
function dist(int256 x, int256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(mul(xor(sub(y, x), sub(x, y)), sgt(x, y)), sub(y, x))
}
}
/// @dev Returns the minimum of `x` and `y`.
function min(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, y), lt(y, x)))
}
}
/// @dev Returns the minimum of `x` and `y`.
function min(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, y), slt(y, x)))
}
}
/// @dev Returns the maximum of `x` and `y`.
function max(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, y), gt(y, x)))
}
}
/// @dev Returns the maximum of `x` and `y`.
function max(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, y), sgt(y, x)))
}
}
/// @dev Returns `x`, bounded to `minValue` and `maxValue`.
function clamp(uint256 x, uint256 minValue, uint256 maxValue)
internal
pure
returns (uint256 z)
{
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, minValue), gt(minValue, x)))
z := xor(z, mul(xor(z, maxValue), lt(maxValue, z)))
}
}
/// @dev Returns `x`, bounded to `minValue` and `maxValue`.
function clamp(int256 x, int256 minValue, int256 maxValue) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, minValue), sgt(minValue, x)))
z := xor(z, mul(xor(z, maxValue), slt(maxValue, z)))
}
}
/// @dev Returns greatest common divisor of `x` and `y`.
function gcd(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
for { z := x } y {} {
let t := y
y := mod(z, y)
z := t
}
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* RAW NUMBER OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns `x + y`, without checking for overflow.
function rawAdd(uint256 x, uint256 y) internal pure returns (uint256 z) {
unchecked {
z = x + y;
}
}
/// @dev Returns `x + y`, without checking for overflow.
function rawAdd(int256 x, int256 y) internal pure returns (int256 z) {
unchecked {
z = x + y;
}
}
/// @dev Returns `x - y`, without checking for underflow.
function rawSub(uint256 x, uint256 y) internal pure returns (uint256 z) {
unchecked {
z = x - y;
}
}
/// @dev Returns `x - y`, without checking for underflow.
function rawSub(int256 x, int256 y) internal pure returns (int256 z) {
unchecked {
z = x - y;
}
}
/// @dev Returns `x * y`, without checking for overflow.
function rawMul(uint256 x, uint256 y) internal pure returns (uint256 z) {
unchecked {
z = x * y;
}
}
/// @dev Returns `x * y`, without checking for overflow.
function rawMul(int256 x, int256 y) internal pure returns (int256 z) {
unchecked {
z = x * y;
}
}
/// @dev Returns `x / y`, returning 0 if `y` is zero.
function rawDiv(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := div(x, y)
}
}
/// @dev Returns `x / y`, returning 0 if `y` is zero.
function rawSDiv(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := sdiv(x, y)
}
}
/// @dev Returns `x % y`, returning 0 if `y` is zero.
function rawMod(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mod(x, y)
}
}
/// @dev Returns `x % y`, returning 0 if `y` is zero.
function rawSMod(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := smod(x, y)
}
}
/// @dev Returns `(x + y) % d`, return 0 if `d` if zero.
function rawAddMod(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := addmod(x, y, d)
}
}
/// @dev Returns `(x * y) % d`, return 0 if `d` if zero.
function rawMulMod(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mulmod(x, y, d)
}
}
}//SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import { ICatalystV1Structs } from "./ICatalystV1VaultState.sol";
import { ICrossChainReceiver } from "GeneralisedIncentives/src/interfaces/ICrossChainReceiver.sol";
// Autogenerated
interface ICatalystChainInterface is ICatalystV1Structs, ICrossChainReceiver {
function EXPIRE_CALLER_REWARD() external view returns (uint256);
function EXPIRE_CALLER_REWARD_DENOMINATOR() external view returns (uint256);
function UNDERWRITING_COLLATERAL() external view returns (uint256);
function UNDERWRITING_COLLATERAL_DENOMINATOR() external view returns (uint256);
function chainIdentifierToDestinationAddress(bytes32) external view returns (bytes memory);
function connectNewChain(bytes32 chainIdentifier, bytes memory remoteCCI, bytes memory remoteGARP) external;
function estimateAdditionalCost() external view returns (address asset, uint256 amount);
function expireUnderwrite(
address targetVault,
address toAsset,
uint256 U,
uint256 minOut,
address toAccount,
uint16 underwriteIncentiveX16,
bytes memory cdata
) external;
function getUnderwriteIdentifier(
address targetVault,
address toAsset,
uint256 U,
uint256 minOut,
address toAccount,
uint16 underwriteIncentiveX16,
bytes memory cdata
) external pure returns (bytes32 identifier);
function maxUnderwritingDuration() external view returns (uint256);
function minGasFor(bytes32) external view returns (uint48);
function sendCrossChainAsset(
RouteDescription memory routeDescription,
uint8 toAssetIndex,
uint256 U,
uint256 minOut,
uint256 fromAmount,
address fromAsset,
uint16 underwriteIncentiveX16,
bytes memory calldata_
) external payable;
function sendCrossChainLiquidity(
RouteDescription memory routeDescription,
uint256 U,
uint256[2] memory minOut,
uint256 fromAmount,
bytes memory calldata_
) external payable;
function setMaxUnderwritingDuration(uint256 newMaxUnderwriteDuration) external;
function setMinGasFor(bytes32 chainIdentifier, uint48 minGas) external;
function underwrite(
address targetVault,
address toAsset,
uint256 U,
uint256 minOut,
address toAccount,
uint16 underwriteIncentiveX16,
bytes memory cdata
) external returns (bytes32 identifier);
function underwriteAndCheckConnection(
bytes32 sourceIdentifier,
bytes memory fromVault,
address targetVault,
address toAsset,
uint256 U,
uint256 minOut,
address toAccount,
uint16 underwriteIncentiveX16,
bytes memory cdata
) external;
function underwritingStorage(bytes32) external view returns (uint256 tokens, address refundTo, uint96 expiry);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
int256 constant WADWAD = 1e36;
uint256 constant LN2 = 693147180559945344; // from numpy import np; int(np.log(2)*10**18).
// library MathConstants {
// int256 internal constant WADWAD = 1e36;
// uint256 internal constant LN2 = 693147180559945344; // from numpy import np; int(np.log(2)*10**18).
// }//SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.19;
import { Ownable } from "solady/auth/Ownable.sol";
import {ERC20} from 'solady/tokens/ERC20.sol';
import {SafeTransferLib} from 'solady/utils/SafeTransferLib.sol';
import { ReentrancyGuard} from "solady/utils/ReentrancyGuard.sol";
import { Initializable } from "solady/utils/Initializable.sol";
import { Multicallable } from "solady/utils/Multicallable.sol";
import { FixedPointMathLib} from "solady/utils/FixedPointMathLib.sol";
import { IMessageEscrowStructs } from "GeneralisedIncentives/src/interfaces/IMessageEscrowStructs.sol";
import { ICatalystReceiver} from "./interfaces/IOnCatalyst.sol";
import { ICatalystV1Factory } from "./interfaces/ICatalystV1Factory.sol";
import "./interfaces/ICatalystV1VaultErrors.sol";
import { MAX_GOVERNANCE_FEE_SHARE } from"./CatalystFactory.sol";
import { ICatalystV1Vault } from "./ICatalystV1Vault.sol";
/**
* @title Catalyst: Common Vault Logic
* @author Cata Labs Inc.
* @notice This abstract contract defines general logic of a Catalyst vault like:
* - Vault Token through Solmate's ERC20 implementation.
* - Connection management
* - Security limit
* - Swap Escrow
*
* By inheriting this abstract contract, a Vault automatically implements common vault logic.
* @dev This contract uses the following special notation:
* CAPITAL_LETTER_VARIABLES are constants or immutable.
* _ prefixed varaibles are storage.
* _ prefixed functions are internal.
* Unless otherwise required, variables are exposed directly. Such that storage functions are
* prefixed with _.
*
* Upon deleting the escrow, this contract special logic in case of refunds. We want to ensure that
* any acks does not revert to clear up the escrows. However, some tokens can revert on demand (blacklist tokens)
* For these tokens, we make an optimistic call to the token to send the assets to the user. We don't
* care if it actually goes through. Cases where this call would fail the user does not get anything.
* A caveat of the implementation is that tokens that revert by PANIC'ing or spending all gas, are not supported
* since there is a catch of OOO gas that reverts. It is then dependent on replaying the ack to release the escrow.
*/
abstract contract CatalystVaultCommon is
Initializable,
Multicallable,
ReentrancyGuard,
ERC20,
ICatalystV1Vault
{
/** @notice The fallback user used as a FALLBACK placeholder when underwrite escrows are set. */
address constant UNDERWRITE_FALLBACK_USER = address(uint160(1));
//--- Config ---//
// The following section contains the configurable variables.
/**
* @notice Determines how fast the security limit decreases.
* @dev Needs to be long enough for vault token providers to be notified of a breach but short enough for volatility to not soft-freeze the vault.
*/
uint256 constant DECAY_RATE = 1 days;
/** @notice Number of decimals used by the vault's vault tokens */
uint8 constant DECIMALS = 18;
/**
* @notice The vault tokens initially minted to the user who set up the vault.
* @dev The initial deposit along with this value determines the base value of a vault token.
*/
uint256 constant INITIAL_MINT_AMOUNT = 1e18; // 10**decimals
/**
* @notice Maximum number of assets supported
* @dev Impacts the cost of some for loops. Can be changed without breaking compatibility.
*/
uint8 constant MAX_ASSETS = 3;
//-- ERC20 --//
string _name;
string _symbol;
function name() public override view returns(string memory) {
return _name;
}
function symbol() public override view returns(string memory) {
return _symbol;
}
//-- Variables --//
// immutable variables can be read by proxies, thus it is safe to set this on the constructor.
address public immutable FACTORY;
address public _chainInterface;
/**
* @notice The approved connections for this vault, stored as _vaultConnection[connectionId][toVault]
* @dev to vault is encoded as 64 + 1 bytes.
*/
mapping(bytes32 => mapping(bytes => bool)) public _vaultConnection;
/**
* @notice To indicate which token is desired on the target vault,
* the desired tokens are provided as an integer which maps to the
* asset address. This variable is the map.
*/
mapping(uint256 => address) public _tokenIndexing;
/** @notice The token weights. Used for maintaining a non-symmetric vault asset balance. */
mapping(address => uint256) public _weight;
//-- Parameter Flow & Change variables --//
// Use getUnitCapacity to indirectly access these variables
uint256 _usedUnitCapacity;
uint48 public _adjustmentTarget;
uint48 public _lastModificationTime;
uint48 _usedUnitCapacityTimestamp;
//-- Vault fee variables --//
/**
* @notice The total vault fee. Multiplied by 10**18.
* @dev To compute the respective fee, use mulWad: FixedPointMathLib.mulWad(amount, _vaultFee);
*/
uint64 public _vaultFee;
/**
* @notice The governance's cut of _vaultFee.
* @dev Usage: FixedPointMathLib.mulWad(FixedPointMathLib.mulWad(amount, _vaultFee), _governanceFeeShare);
*/
uint64 public _governanceFeeShare;
/** @notice The vault fee can be changed. _feeAdministrator is the address allowed to change it */
address public _feeAdministrator;
/**
* @notice The setupMaster is the short-term owner of the vault.
* They can connect the vault to vaults on other chains.
* @dev !Can extract all of the vault value! Should be set to address(0) once setup is complete via 'finishSetup()'.
*/
address public _setupMaster;
//--- Messaging router limit ---//
// The router is not completely trusted. Some limits are
// imposed on the DECAY_RATE-ly unidirectional liquidity flow. That is:
// if the vault observes more than _maxUnitCapacity of incoming
// units, then it will not accept further incoming units. This means the router
// can only drain a prefigured percentage of the vault every DECAY_RATE.
// For amplified vaults, the security limit is denominated in assets rather than Units.
// Outgoing flow is subtracted from incoming flow until 0.
/** @notice The max incoming liquidity flow from the router. */
uint256 public _maxUnitCapacity;
// Escrow reference
/** @notice Total current escrowed tokens. */
mapping(address => uint256) public _escrowedTokens;
/** @notice Total current escrowed vault tokens. */
uint256 public _escrowedVaultTokens;
/** @notice Find escrow information. Used for both normal swaps and liquidity swaps. */
mapping(bytes32 => address) public _escrowLookup;
/**
* @notice A mathematical lib that describes various properties of this contract.
* These helper functions are not contained in the swap template, since they notisably inflate
* the contract side which reduceses the number of optimizer runs => increase the gas cost.
*/
address immutable public MATHLIB;
constructor(address factory_, address mathlib) payable {
FACTORY = factory_;
MATHLIB = mathlib;
_name = "Catalyst Vault Template";
_symbol = "";
// Disable the contract from being initialized. This ensures the factory is
// used to deploy vaults.
_disableInitializers();
}
/** @notice Get the factory owner. That is the owner that can configure this vault post finishSetup(). */
function factoryOwner() public view override returns (address) {
return Ownable(FACTORY).owner();
}
/** @notice Governance fee destination. This is the address the governance fee is sent to. */
function governanceFeeDestination() public view override returns (address) {
return ICatalystV1Factory(FACTORY)._governanceFeeDestination();
}
/**
* @notice Only allow Governance to change vault parameters
* @dev Because of dangerous permissions (setConnection, weight changes):
* !CatalystFactory(_factory).owner() must be set to a timelock!
*/
modifier onlyFactoryOwner() {
require(msg.sender == factoryOwner()); // dev: Only factory owner
_;
}
/**
* @notice Require the sender of the transaction to be the chain interface.
*/
modifier onlyChainInterface() {
require(msg.sender == _chainInterface); // dev: Only chain interface
_;
}
/**
* @notice Verify a connected pool.
*/
modifier onlyConnectedPool(bytes32 channelId, bytes memory vault) {
// Only allow connected vaults
if (!_vaultConnection[channelId][vault]) revert VaultNotConnected();
_;
}
// -- Receive Abstract Functions -- //
function _receiveAsset(
address toAsset,
uint256 U,
uint256 minOut
) virtual internal returns (uint256);
// -- Setup Functions -- //
/**
* @notice Setup a vault.
* @dev Is initializer.
* @param name_ Name of the vault token.
* @param symbol_ Symbol of the vault token.
* @param chainInterface The chain interface to use. Set address(0) to disable cross-chain swaps.
* @param vaultFee Initial vault fee, that is the fee charged on swaps.
* @param governanceFee Initial governance fee, that is the percentage of the vault fee that is sent to designated address.
* @param feeAdministrator Special address that can modify the pool fees.
* @param setupMaster User that is configuring the vault.
*/
function setup(
string calldata name_,
string calldata symbol_,
address chainInterface,
uint64 vaultFee,
uint64 governanceFee,
address feeAdministrator,
address setupMaster
) initializer external override {
// The vault is designed to be used by a proxy and not as a standalone vault.
// initializer ensures this function is only called once.
_chainInterface = chainInterface;
_setupMaster = setupMaster;
_setVaultFee(vaultFee);
_setGovernanceFee(governanceFee);
_setFeeAdministrator(feeAdministrator);
// Name the ERC20 vault token
_name = name_;
_symbol = symbol_;
}
/**
* @notice Creates a connection to toVault on the channelId.
* @dev Encoding addresses in 64 + 1 bytes for EVM.
* For Solidity, this can be done as bytes.concat(bytes1(0x14), bytes32(0), abi.encode(toAddress))
* @param channelId Target chain identifier. Varies from AMB to AMB.
* @param toVault 64 + 1 bytes representation of the target vault.
* @param state Boolean indicating if the connection should be open or closed.
*/
function setConnection(
bytes32 channelId,
bytes calldata toVault,
bool state
) external override {
require(msg.sender == _setupMaster); // dev: No auth
require(toVault.length == 65); // dev: Vault addresses are uint8 + 64 bytes.
_vaultConnection[channelId][toVault] = state;
emit SetConnection(channelId, toVault, state);
}
/**
* @notice Gives up short-term ownership of the vault. This makes the vault unstoppable.
* @dev This function should ALWAYS be called before other liquidity providers deposit liquidity.
* While it is not recommended, swapping should be relativly safe since because of the escrow (assuming a minimum output is set).
*/
function finishSetup() external override {
require(msg.sender == _setupMaster); // dev: No auth
_setupMaster = address(0);
emit FinishSetup();
}
/**
* @notice View function to signal if a vault is safe to use.
* @dev Checks if setupMaster has been set to ZERO_ADDRESS. In other words, has finishSetup been called?
* This function is not "safe()". To properly verify if a pool is "ready", verify:
* - The vault template is trusted.
* - The cross-chain interfce is trusted.
* - All connections are correctly set. (Valid chains, valid vaults)
*
* If you are providing liquidity to a vault, furthermore check:
* - All assets in the pool are trusted.
*
* The above checks have to be done on every vault in the pool.
*/
function ready() external view override returns (bool) {
// _setupMaster == address(0) ensures a safe pool cannot be made unsafe. The setup master can drain the pool!
// _tokenIndexing[0] != address(0) check if the pool has been initialized correctly.
// The additional check is there to ensure that the initial deployment returns false.
return _setupMaster == address(0) && _tokenIndexing[0] != address(0);
}
/**
* @notice Returns the current cross-chain swap capacity.
* @dev can be overridden to implement other limit curves.
*/
function getUnitCapacity() public view virtual override returns (uint256) {
uint256 MUC = _maxUnitCapacity;
// The delta change to the limit is: timePassed · slope = timePassed · Max/decayrate
uint256 unitCapacityReleased;
unchecked {
// block.timestamp >= _usedUnitCapacityTimestamp, always.
// MUC is generally low.
unitCapacityReleased = block.timestamp - _usedUnitCapacityTimestamp;
// This line can overflow. While unlikely to, if it does it would semi-freeze the pool until
// some assets are withdrawn. As a fix, let if overflow. If it overflows, then
// unitCapacityReleased becomes smaller so there are no security implications.
unitCapacityReleased *= MUC;
// DECAY_RATE != 0.
unitCapacityReleased /= DECAY_RATE;
}
uint256 UC = _usedUnitCapacity;
// If the change is greater than the units than the spent security limit return maximum.
//If we computed it as (MUC - UC + unitCapacityReleased > MUC) it would obviously be wrong.
if (UC <= unitCapacityReleased) return MUC;
// Amplified vaults can have MUC <= UC since MUC is modified when swapping.
unchecked {
// We know UC > unitCapacityReleased.
if (MUC <= UC - unitCapacityReleased) return 0;
// We know UC > unitCapacityReleased and with the above statement we know
// MUC > (UC - unitCapacityReleased). Thus we can compute the difference unchecked.
return MUC - (UC - unitCapacityReleased);
}
}
// -- Utils -- //
/**
* @notice Check if the vault supports an inflow of units and decrease
* unit capacity by the inflow.
* @dev Implement a lot of similar logic to getUnitCapacity.
* @param Units The number of units to check and set.
*/
function _updateUnitCapacity(uint256 Units) internal {
uint256 MUC = _maxUnitCapacity;
// The delta change to the limit is: timePassed · slope = timePassed · Max/decayrate
uint256 unitCapacityReleased;
unchecked {
// block.timestamp > _usedUnitCapacityTimestamp, always.
// MUC is generally low.
unitCapacityReleased = (block.timestamp - _usedUnitCapacityTimestamp);
// This line can overflow. While unlikely to, if it does it would semi-freeze the pool until
// some assets are withdrawn. As a fix, let if overflow. If it overflows, then
// unitCapacityReleased becomes smaller so there are no security implications.
unitCapacityReleased *= MUC;
// DECAY_RATE != 0.
unitCapacityReleased /= DECAY_RATE;
}
uint256 UC = _usedUnitCapacity;
// If the change is greater than the units than the spent security limit it is at max.
if (UC <= unitCapacityReleased) {
// The new limit is MUC, check if more units than MUC are getting spent.
if (Units > MUC) revert ExceedsSecurityLimit();
// Set last change and the new spent security limit.
_usedUnitCapacityTimestamp = uint48(block.timestamp);
_usedUnitCapacity = Units;
return;
}
// Compute the new spent security limit. Start by adding used unit capacity
// and to be spent units
uint256 newUnitFlow = UC + Units;
unchecked {
// Then subtract the units that have been decayed. We know UC + Units >= UC > unitCapacityReleased
newUnitFlow -= unitCapacityReleased;
}
// Then check if the new spent security limit is larger than maximum.
if (newUnitFlow > MUC) revert ExceedsSecurityLimit();
// Set last change and the new spent security limit.
_usedUnitCapacityTimestamp = uint48(block.timestamp);
_usedUnitCapacity = newUnitFlow;
}
// -- Governance Functions -- //
/** @notice Sets a new fee administrator that can configure vault fees. */
function _setFeeAdministrator(address administrator) internal {
_feeAdministrator = administrator;
emit SetFeeAdministrator(administrator);
}
/**
* @notice Sets a new vault fee, taken from input amount.
* @param fee Fee in WAD terms. 12e16 is 12%.
*/
function _setVaultFee(uint64 fee) internal {
require(fee <= FixedPointMathLib.WAD); // dev: VaultFee is maximum 100%.
_vaultFee = fee;
emit SetVaultFee(fee);
}
/**
* @notice Sets a new governance fee. Taken of the vault fee.
* @param fee Fee in WAD terms. 12e16 is 12%.
*/
function _setGovernanceFee(uint64 fee) internal {
require(fee <= MAX_GOVERNANCE_FEE_SHARE); // dev: Maximum GovernanceFeeSare exceeded.
_governanceFeeShare = fee;
emit SetGovernanceFee(fee);
}
/** @notice Allows the factory owner to set a new fee administrator. */
function setFeeAdministrator(address administrator) public override onlyFactoryOwner {
_setFeeAdministrator(administrator);
}
/**
* @notice Allows the factory owner to set the governance fee.
* @dev Can only be called by factory owner.
* @param fee Fee in WAD terms. 12e16 is 12%.
*/
function setGovernanceFee(uint64 fee) public override onlyFactoryOwner {
_setGovernanceFee(fee);
}
/**
* @notice Allows the feeAdministrator to modify the vault fee.
* @dev Can only be called by feeAdministrator
* @param fee Fee in WAD terms. 12e16 is 12%.
*/
function setVaultFee(uint64 fee) public override {
require(msg.sender == _feeAdministrator); // dev: Only feeAdministrator can set new fee
_setVaultFee(fee);
}
/**
* @notice Collect the governance fee share of the specified vault fee.
* @dev The governance fee share is transfered to governanceFeeDestination.
*/
function _collectGovernanceFee(address asset, uint256 vaultFeeAmount) internal {
uint256 governanceFeeShare = _governanceFeeShare;
// If governanceFeeShare == 0, then skip the rest of the logic.
if (governanceFeeShare != 0) {
uint256 governanceFeeAmount = FixedPointMathLib.mulWad(vaultFeeAmount, governanceFeeShare);
SafeTransferLib.safeTransfer(asset, governanceFeeDestination(), governanceFeeAmount);
}
}
//-- Escrow Functions --//
/**
* @notice Create a token escrow for a swap.
* @dev It is not checked if fallbackUser is set to address(0) but if it is, the escrow is lost.
* @param sendAssetHash The escrow context hash. Will be used to recover the escrow.
* From a implementation / usage perspective, if this hash contains fromAsset and amount
* it will improves by allowing on to verify these values independently.
* @param fallbackUser The user who the escrow belongs to. Do not set to address(0).
* @param fromAsset Asset to escrow.
* @param amount Amount to escrow.
*/
function _setTokenEscrow(
bytes32 sendAssetHash,
address fallbackUser,
address fromAsset,
uint256 amount
) internal {
if (_escrowLookup[sendAssetHash] != address(0)) revert EscrowAlreadyExists();
_escrowLookup[sendAssetHash] = fallbackUser;
unchecked {
// Must be less than the vault balance.
_escrowedTokens[fromAsset] += amount;
}
}
/**
* @notice Create a liquidity escrow for a swap.
* @dev It is not checked if fallbackUser is set to address(0) but if it is, the escrow is lost.
* @param sendLiquidityHash The escrow context hash. Will be used to recover the escrow.
* From a implementation / usage perspective, if this hash contains vaultTokens
* it will improves by allowing on to verify these values independently.
* @param fallbackUser The user who the escrow belongs to. Do not set to address(0).
* @param vaultTokens Number of vault tokens to escrow.
*/
function _setLiquidityEscrow(
bytes32 sendLiquidityHash,
address fallbackUser,
uint256 vaultTokens
) internal {
if (_escrowLookup[sendLiquidityHash] != address(0)) revert EscrowAlreadyExists();
_escrowLookup[sendLiquidityHash] = fallbackUser;
// Escrow vault tokens are first burned and then escrowed. As a result, this may overflow unlike _escrowedTokens.
_escrowedVaultTokens += vaultTokens;
}
/**
* @notice Returns the fallbackUser for the escrow and cleans up the escrow information.
* @dev 'delete _escrowLookup[sendAssetHash]' ensures this function can only be called once.
*/
function _releaseAssetEscrow(
bytes32 sendAssetHash,
uint256 escrowAmount,
address escrowToken
) internal returns(address) {
address fallbackUser = _escrowLookup[sendAssetHash]; // Passing in an invalid swapHash returns address(0).
require(fallbackUser != address(0)); // dev: Invalid swapHash. Alt: Escrow doesn't exist.
delete _escrowLookup[sendAssetHash]; // Stops timeout and further acks from being called.
unchecked {
// escrowAmount \subseteq _escrowedTokens => escrowAmount <= _escrowedTokens.
// Cannot be called twice since the 3 lines before ensure this can only be reached once.
_escrowedTokens[escrowToken] -= escrowAmount;
}
return fallbackUser;
}
/**
* @notice Returns the fallbackUser for the escrow and cleans up the escrow information.
* @dev 'delete _escrowLookup[sendAssetHash]' ensures this function can only be called once.
*/
function _releaseLiquidityEscrow(
bytes32 sendLiquidityHash,
uint256 escrowAmount
) internal returns(address) {
address fallbackUser = _escrowLookup[sendLiquidityHash]; // Passing in an invalid swapHash returns address(0).
require(fallbackUser != address(0)); // dev: Invalid swapHash. Alt: Escrow doesn't exist.
delete _escrowLookup[sendLiquidityHash]; // Stops timeout and further acks from being called.
unchecked {
// escrowAmount \subseteq _escrowedVaultTokens => escrowAmount <= _escrowedVaultTokens.
// Cannot be called twice since the 3 lines before ensure this can only be reached once.
_escrowedVaultTokens -= escrowAmount;
}
return fallbackUser;
}
/**
* @notice Implements basic ack logic: Deletes and releases tokens to the vault
* @dev Should never revert! For security limit adjustments, the implementation may have to be overwritten.
* @param toAccount Recipient of the transaction on the target chain.
* @param U Number of units initially purchased.
* @param escrowAmount Number of tokens escrowed.
* @param escrowToken Address of the escrowed token.
* @param blockNumberMod Block number when the transaction was commited (mod 32)
*/
function onSendAssetSuccess(
bytes32 channelId,
bytes calldata toAccount,
uint256 U,
uint256 escrowAmount,
address escrowToken,
uint32 blockNumberMod
) onlyChainInterface public override virtual {
// We need to find the location of the escrow using the information below.
// We need to do this twice: 1. Get the address. 2. Delete the escrow.
// To save a bit of gas, this hash is computed, cached, and then used.
bytes32 sendAssetHash = _computeSendAssetHash( // Computing the hash doesn't revert.
toAccount, // Ensures no collisions between different users
U, // Used to randomise the hash
escrowAmount, // Required! to validate release escrow data
escrowToken, // Required! to validate release escrow data
blockNumberMod // Used to randomize the hash.
);
_releaseAssetEscrow(sendAssetHash, escrowAmount, escrowToken); // Only reverts for missing escrow
emit SendAssetSuccess(
channelId,
toAccount,
U,
escrowAmount,
escrowToken,
blockNumberMod
);
}
/**
* @notice Implements basic timeout logic: Deletes and sends tokens to the user.
* @dev Should never revert!
* For blacklist tokens, this function contains custom logic to support failing ERC20 transfer.
* If an ERC20 transfer fails (say because of a blocklist), we only revert if it was because of OOO.
* This implies that if an ERC20 transfer fails, then the escrow is lost. This shouldn't be the cast
* except if a token is paused, blacklisted, or the vault is exploited such that it has less assets
* than the escrow.
* @param toAccount Recipient of the transaction on the target chain. Encoded in bytes32.
* @param U Number of units initially purchased.
* @param escrowAmount Number of tokens escrowed.
* @param escrowToken Token escrowed.
* @param blockNumberMod Block number of the transaction that commited the swap (mod 32)
*/
function onSendAssetFailure(
bytes32 channelId,
bytes calldata toAccount,
uint256 U,
uint256 escrowAmount,
address escrowToken,
uint32 blockNumberMod
) onlyChainInterface public override virtual {
// We need to find the location of the escrow using the information below.
// We need to do this twice: 1. Get the address. 2. Delete the escrow.
// To save a bit of gas, this hash is computed and saved and then used.
bytes32 sendAssetHash = _computeSendAssetHash( // Computing the hash doesn't revert.
toAccount, // Ensures no collisions between different users
U, // Used to randomise the hash
escrowAmount, // Required! to validate release escrow data
escrowToken, // Required! to validate release escrow data
blockNumberMod // Used to randomize the hash.
);
// This call provides re-entry protection against re-entering this call. Otherwise, this call can always be called.
address fallbackAddress = _releaseAssetEscrow(sendAssetHash, escrowAmount, escrowToken); // Only reverts for missing escrow,
// We are going to make a low-level call. It may revert (see comment below) but it should not revert if it runs out of gas (that should be raised).
// As such, get the current gas in the contract.
uint256 gasLeftBeforeCall = gasleft();
bool success;
// Make a low level call such that the transfer never fails. This is important for tokens using block lists.
// This also implies that if you get blacklisted between when you initiated the swap and the swap failed, you would lose the tokens.
bytes memory payload = abi.encodeWithSignature("transfer(address,uint256)", fallbackAddress, escrowAmount);
assembly ("memory-safe") {
// The gas limit is set to 0x8000000000000000000000000000000000000000000000000000000000000000.
// This is essentially all gas since the actual gas forwarded is min(gasForwarded, gasleft * 63/64).
success := call(0x8000000000000000000000000000000000000000000000000000000000000000, escrowToken, 0, add(payload, 0x20), mload(payload), 0, 0)
// SafeTransferLib.safeTransferFrom(escrowToken, fallbackAddress, escrowAmount);
}
// If the call failed, check if it failed with OOO (If the call used all of the gas it has available).
if (!success) if (gasleft() < gasLeftBeforeCall * 1 / 63) revert NotEnoughGas();
emit SendAssetFailure(
channelId,
toAccount,
U,
escrowAmount,
escrowToken,
blockNumberMod
);
}
/**
* @notice Implements basic liquidity ack logic: Deletes and releases vault tokens to the vault.
* @dev Should never revert! For security limit adjustments, the implementation should be overwritten.
* @param toAccount Recipient of the transaction on the target chain.
* @param U Number of units initially acquired.
* @param escrowAmount Number of vault tokens escrowed.
* @param blockNumberMod Block number at which the swap transaction was commited (mod 32)
*/
function onSendLiquiditySuccess(
bytes32 channelId,
bytes calldata toAccount,
uint256 U,
uint256 escrowAmount,
uint32 blockNumberMod
) onlyChainInterface public override virtual {
// We need to find the location of the escrow using the information below.
// We need to do this twice: 1. Get the address. 2. Delete the escrow.
// To save a bit of gas, this hash is computed and saved and then used.
bytes32 sendLiquidityHash = _computeSendLiquidityHash(
toAccount, // Ensures no collisions between different users
U, // Used to randomise the hash
escrowAmount, // Required! to validate release escrow data
blockNumberMod // Used to randomize the hash.
);
_releaseLiquidityEscrow(sendLiquidityHash, escrowAmount); // Reverts for missing escrow
emit SendLiquiditySuccess(
channelId,
toAccount,
U,
escrowAmount,
blockNumberMod
);
}
/**
* @notice Implements basic liquidity timeout logic: Deletes and sends vault tokens to the user.
* @dev Should never revert!
* @param toAccount Recipient of the transaction on the target chain. Encoded in bytes32.
* @param U Number of units initially acquired.
* @param escrowAmount Number of vault tokens escrowed.
* @param blockNumberMod Block number at which the swap transaction was commited (mod 32)
*/
function onSendLiquidityFailure(
bytes32 channelId,
bytes calldata toAccount,
uint256 U,
uint256 escrowAmount,
uint32 blockNumberMod
) onlyChainInterface public override virtual {
bytes32 sendLiquidityHash = _computeSendLiquidityHash(
toAccount, // Ensures no collisions between different users
U, // Used to randomise the hash
escrowAmount, // Required! to validate release escrow data
blockNumberMod // Used to randomize the hash.
);
// This function only allows entering this function once. Once called, it can never be called without reverting again.
address fallbackAddress = _releaseLiquidityEscrow(sendLiquidityHash, escrowAmount); // Reverts for missing escrow
_mint(fallbackAddress, escrowAmount); // Never reverts.
emit SendLiquidityFailure(
channelId,
toAccount,
U,
escrowAmount,
blockNumberMod
);
}
/**
* @notice Computes a unique identifier for a swap. This unique identifier can be used to identify swaps cross-chain.
* However, it is never exposed. This is done to let the hashing algorithm be flexible between implementations.
*/
function _computeSendAssetHash(
bytes calldata toAccount,
uint256 U,
uint256 amount,
address fromAsset,
uint32 blockNumberMod
) internal pure returns(bytes32) {
return keccak256(
bytes.concat(
toAccount, // Ensures no collisions between different users.
bytes32(U), // Used to randomise the hash.
bytes32(amount), // Required! to validate release escrow data.
bytes20(fromAsset), // Required! to validate release escrow data.
bytes4(blockNumberMod) // Used to randomize the hash.
)
);
}
/**
* @notice Computes a unique identifier for a swap. This unique identifier can be used to identify swaps cross-chain.
* However, it is never exposed. This is done to let the hashing algorithm be flexible between implementations.
*/
function _computeSendLiquidityHash(
bytes calldata toAccount,
uint256 U,
uint256 amount,
uint32 blockNumberMod
) internal pure returns(bytes32) {
return keccak256(
bytes.concat(
toAccount, // Ensures no collisions between different users.
bytes32(U), // Used to randomise the hash.
bytes32(amount), // Required! to validate release escrow data.
bytes4(blockNumberMod) // Used to randomize the hash.
)
);
}
// -- Underwrite Asset Swaps -- //
function underwriteAsset(
bytes32 identifier,
address toAsset,
uint256 U,
uint256 minOut
) onlyChainInterface virtual public returns (uint256 purchasedTokens) {
// Simulate a receiveAsset call. This gets us the purchased tokens.
purchasedTokens = _receiveAsset(toAsset, U, minOut);
// Set the escrow.
_setTokenEscrow(
identifier,
UNDERWRITE_FALLBACK_USER,
toAsset,
purchasedTokens
);
emit SwapUnderwritten(
identifier,
toAsset,
U,
purchasedTokens
);
}
/**
* @notice Release assets associated with an underwrite escrow.
* @param refundTo Released assets are sent to this address.
* @param identifier Underwriting identifier. Is used to index the storage for valid escrows.
* @param escrowAmount Number of tokens escrowed.
* @param escrowToken Escrowed token address.
* @param sourceIdentifier The source chain identifier.
* @param fromVault The originating vault.
*/
function releaseUnderwriteAsset(
address refundTo,
bytes32 identifier,
uint256 escrowAmount,
address escrowToken,
bytes32 sourceIdentifier,
bytes calldata fromVault
) onlyChainInterface onlyConnectedPool(sourceIdentifier, fromVault) virtual public {
_releaseAssetEscrow(identifier, escrowAmount, escrowToken); // Reverts for missing escrow.
// Send the assets to the user.
SafeTransferLib.safeTransfer(escrowToken, refundTo, escrowAmount);
}
/**
* @notice Delete an underwrite escrow without releasing any tokens.
* @dev The unsued parameter U is used for overwrites. (see CataulystVaultAmplified.sol)
* @param identifier Underwriting identifier. Is used to index the storage for valid escrows.
* param U Number of underwritten units. Is used for Amplified vaults to modify the unit tracker.
* @param escrowAmount Number of tokens escrowed.
* @param escrowToken Escrowed token address.
*/
function deleteUnderwriteAsset(
bytes32 identifier,
uint256 /* U */,
uint256 escrowAmount,
address escrowToken
) onlyChainInterface virtual public {
_releaseAssetEscrow(identifier, escrowAmount, escrowToken); // Reverts for missing escrow.
}
}//SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.19;
import { FixedPointMathLib } from "solady/utils/FixedPointMathLib.sol";
import { WADWAD } from "./utils/MathConstants.sol";
/**
* @title Catalyst: Amplified Integrals
* @author Catalyst Labs Inc.
*/
contract IntegralsAmplified {
/**
* @notice Computes the integral \int_{wA}^{wA+wx} 1/w^k · (1-k) dw
* = (wA + wx)^(1-k) - wA^(1-k)
* The value is returned as units, which is always WAD.
* @dev All input amounts should be the raw numbers and not WAD.
* Since units are always denominated in WAD, the function should be treated as mathematically *native*.
* @param input Input amount.
* @param A Current vault balance of the x token.
* @param W Weight of the x token.
* @param oneMinusAmp Amplification. Provided as (1-k).
* @return uint256 Units (units are **always** WAD).
*/
function _calcPriceCurveArea(
uint256 input,
uint256 A,
uint256 W,
int256 oneMinusAmp
) internal pure returns (uint256) {
// Will revert if W = 0.
// Or if A + input == 0.
int256 calc = FixedPointMathLib.powWad(
int256(W * (A + input) * FixedPointMathLib.WAD), // If casting overflows to a negative number, powWad fails.
oneMinusAmp
);
// If the vault contains 0 assets, the below computation will fail. This is bad.
// Instead, check if A is 0. If it is then skip because: (W · A)^(1-k) = (W · 0)^(1-k) = 0
if (A != 0) {
unchecked {
// W * A * FixedPointMathLib.WAD < W * (A + input) * FixedPointMathLib.WAD
calc -= FixedPointMathLib.powWad(
int256(W * A * FixedPointMathLib.WAD), // If casting overflows to a negative number, powWad fails
oneMinusAmp
);
}
}
return uint256(calc); // Casting always safe, as calc always > =0
}
/**
* @notice Solves the equation U = \int_{wA-_wy}^{wA} W/w^k · (1-k) dw for y
* = B · (1 - (
* (wB^(1-k) - U) / (wB^(1-k))
* )^(1/(1-k))
* )
* The value is returned as output token. (not WAD)
* @dev All input amounts should be the raw numbers and not WAD.
* Since units are always multiplied by WAD, the function should be treated as mathematically *native*.
* @param U Incoming vault specific units.
* @param B Current vault balance of the y token.
* @param W Weight of the y token.
* @return uint25 Output denominated in output token. (not WAD)
*/
function _calcPriceCurveLimit(
uint256 U,
uint256 B,
uint256 W,
int256 oneMinusAmp
) internal pure returns (uint256) {
// W_B · B^(1-k) is repeated twice and requires 1 power. As a result, we compute it and cache it.
uint256 W_BxBtoOMA = uint256( // Always casts a positive value.
FixedPointMathLib.powWad(
int256(W * B * FixedPointMathLib.WAD), // If casting overflows to a negative number, powWad fails.
oneMinusAmp
)
);
return FixedPointMathLib.mulWad(
B,
FixedPointMathLib.WAD - uint256( // Always casts a positive value
FixedPointMathLib.powWad(
int256(FixedPointMathLib.divWadUp(W_BxBtoOMA - U, W_BxBtoOMA)), // Casting never overflows, as division result is always < 1
WADWAD / oneMinusAmp
)
)
);
}
/**
* @notice Solves the equation
* \int_{wA}^{wA + wx} 1/w^k · (1-k) dw = \int_{wB-wy}^{wB} 1/w^k · (1-k) dw for y
* => out = B · (1 - (
* (wB^(1-k) - (wA+wx)^(1-k) - wA^(1-k)) / (wB^(1-k))
* )^(1/(1-k))
* )
* Alternatively, the integral can be computed through:
* _calcPriceCurveLimit(_calcPriceCurveArea(input, A, W_A, amp), B, W_B, amp).
* @dev All input amounts should be the raw numbers and not WAD.
* @param input Input amount.
* @param A Current vault balance of the x token.
* @param B Current vault balance of the y token.
* @param W_A Weight of the x token.
* @param W_B Weight of the y token.
* @param oneMinusAmp Amplification.
* @return uint256 Output denominated in output token.
*/
function _calcCombinedPriceCurves(
uint256 input,
uint256 A,
uint256 B,
uint256 W_A,
uint256 W_B,
int256 oneMinusAmp
) internal pure returns (uint256) {
// uint256 W_BxBtoOMA = uint256(FixedPointMathLib.powWad(
// int256(W_B * B * FixedPointMathLib.WAD),
// oneMinusAmp
// ));
// uint256 U = uint256(FixedPointMathLib.powWad(
// int256(W_A * (A + input) * FixedPointMathLib.WAD),
// oneMinusAmp
// ) - FixedPointMathLib.powWad(
// int256(W_A * A * FixedPointMathLib.WAD),
// oneMinusAmp
// )); // _calcPriceCurveArea(input, A, W_A, amp)
// return B * (FixedPointMathLib.WAD - uint256(FixedPointMathLib.powWad(
// int256(FixedPointMathLib.divWadUp(W_BxBtoOMA - U, W_BxBtoOMA)),
// int256(FixedPointMathLib.WAD * FixedPointMathLib.WAD / uint256(oneMinusAmp)))
// )) / FixedPointMathLib.WAD; // _calcPriceCurveLimit
return _calcPriceCurveLimit(_calcPriceCurveArea(input, A, W_A, oneMinusAmp), B, W_B, oneMinusAmp);
}
/**
* @notice Converts units into vault tokens with the below formula
* pt = PT · (((N · wa_0^(1-k) + U)/(N · wa_0^(1-k))^(1/(1-k)) - 1)
* @dev The function leaves a lot of computation to the external implementation. This is done to avoid recomputing values several times.
* @param U Number of units to convert into vault tokens.
* @param ts Current vault token supply. The escrowed vault tokens should not be added, since the function then returns more.
* @param it_times_walpha_amped wa_0^(1-k)
* @param oneMinusAmpInverse Vault amplification.
* @return uint256 Output denominated in vault tokens.
*/
function _calcPriceCurveLimitShare(uint256 U, uint256 ts, uint256 it_times_walpha_amped, int256 oneMinusAmpInverse) internal pure returns (uint256) {
uint256 vaultTokens = FixedPointMathLib.mulWad(
ts,
uint256( // Always casts a positive value, as powWad >= 1, hence powWad - WAD >= 0
FixedPointMathLib.powWad( // poWad always >= 1, as the 'base' is always >= 1
int256(FixedPointMathLib.divWad( // If casting overflows to a negative number, powWad fails
it_times_walpha_amped + U,
it_times_walpha_amped
)),
oneMinusAmpInverse
) - int256(FixedPointMathLib.WAD)
)
);
return vaultTokens;
}
}//SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
interface ICatalystReceiver {
/**
* @notice The callback from a catalyst call. To determine if the swap was an asset or liquidity swap, either the current balance should be checked or it should be encoded into data.
* @dev If you want full finality (not just economical finality)
* revert on underwritten == true.
*/
function onCatalystCall(uint256 purchasedTokens, bytes calldata data, bool underwritten) external;
}//SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.19;
import "./interfaces/ICatalystV1VaultSuccessFailure.sol";
import "./interfaces/ICatalystV1VaultAdministration.sol";
import "./interfaces/ICatalystV1VaultDerived.sol";
import "./interfaces/ICatalystV1VaultErrors.sol";
import "./interfaces/ICatalystV1VaultEvents.sol";
import "./interfaces/ICatalystV1VaultImmutables.sol";
import "./interfaces/ICatalystV1VaultPermissionless.sol";
import "./interfaces/ICatalystV1VaultState.sol";
import "./interfaces/ICatalystV1Underwriting.sol";
interface ICatalystV1Vault is
ICatalystV1VaultSuccessFailure,
ICatalystV1VaultAdministration,
ICatalystV1VaultDerived,
ICatalystV1VaultEvents,
ICatalystV1VaultImmutables,
ICatalystV1VaultPermissionless,
ICatalystV1VaultState,
ICatalystV1Structs,
ICatalystV1Underwriting
{}//SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import { IMessageEscrowStructs } from "GeneralisedIncentives/src/interfaces/IMessageEscrowStructs.sol";
interface ICatalystV1Structs is IMessageEscrowStructs {
/**
* @param chainIdentifier target chain identifier.
* @param toVault Target vault on the target chain. Encoded in 64 + 1 bytes.
* @param toAccount Recipient of the transaction on the target chain. Encoded in 64 + 1 bytes.
* @param incentive Cross-chain relaying incentive description.
*/
struct RouteDescription {
bytes32 chainIdentifier;
bytes toVault;
bytes toAccount;
IncentiveDescription incentive;
uint64 deadline;
}
}
/**
* @title Vault state
* @notice Contains all vault storage which depends on the vault state.
*/
interface ICatalystV1VaultState {
/** @notice Token weights. Used for maintaining a non symmetric vault asset balance. */
function _weight(address token) external view returns (uint256);
function _adjustmentTarget() external view returns (uint48);
function _lastModificationTime() external view returns (uint48);
/** @notice The vault fee in WAD. Implementation of fee: mulWadDown(_amount, _vaultFee) */
function _vaultFee() external view returns (uint64);
function _governanceFeeShare() external view returns (uint64);
/** @notice The address of the responsible for adjusting the fees. */
function _feeAdministrator() external view returns (address);
/** @notice The setupMaster is the short-term owner of the vault. They can connect the vault to vaults on other chains. */
function _setupMaster() external view returns (address);
// Security limit
/** @notice The max incoming liquidity flow from the router. */
function _maxUnitCapacity() external view returns (uint256);
// Escrow reference
/** @notice Total current escrowed tokens */
function _escrowedTokens(address token) external view returns (uint256);
/** @notice Find escrow information. Used for both normal swaps and liquidity swaps. */
function _escrowLookup(bytes32 sendAssetHash) external view returns (address);
/** @notice Total current escrowed vault tokens */
function _escrowedVaultTokens() external view returns (uint256);
/** @notice Checks if there is a connection to the described vault */
function _vaultConnection(bytes32 sourceIdentifier, bytes calldata fromVault) external view returns (bool);
function factoryOwner() external view returns (address);
function governanceFeeDestination() external view returns (address);
/**
* @notice External view function purely used to signal if a vault is safe to use.
* @dev Just checks if the setup master has been set to ZERO_ADDRESS. In other words, has finishSetup been called?
*/
function ready() external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
interface ICrossChainReceiver {
/**
* @notice Handles the acknowledgement from the destination
* @dev acknowledgement is exactly the output of receiveMessage except if receiveMessage failed, then it is error code (0xff or 0xfe) + original message.
* If an acknowledgement isn't needed, this can be implemented as {}.
* - This function can be called by someone else again! Ensure that if this endpoint is called twice with the same message nothing bad happens.
* - If the application expects that the maxGasAck will be provided, then it should check that it got enough and revert if it didn't.
* Otherwise, it is assumed that you didn't need the extra gas.
* @param destinationIdentifier An identifier for the destination chain.
* @param messageIdentifier A unique identifier for the message. The identifier matches the identifier returned when escrowed the message.
* This identifier can be mismanaged by the messaging protocol.
* @param acknowledgement The acknowledgement sent back by receiveMessage. Is 0xff if receiveMessage reverted.
*/
function receiveAck(bytes32 destinationIdentifier, bytes32 messageIdentifier, bytes calldata acknowledgement) external;
/**
* @notice receiveMessage from a cross-chain call.
* @dev The application needs to check the fromApplication combined with sourceIdentifierbytes to figure out if the call is authenticated.
* - If the application expects that the maxGasDelivery will be provided, then it should check that it got enough and revert if it didn't.
* Otherwise, it is assumed that you didn't need the extra gas.
* @return acknowledgement Information which is passed to receiveAck.
* If you return 0xff, you cannot know the difference between Executed but "failed" and outright failed.
*/
function receiveMessage(bytes32 sourceIdentifierbytes, bytes32 messageIdentifier, bytes calldata fromApplication, bytes calldata message) external returns(bytes memory acknowledgement);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Simple single owner authorization mixin.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol)
///
/// @dev Note:
/// This implementation does NOT auto-initialize the owner to `msg.sender`.
/// You MUST call the `_initializeOwner` in the constructor / initializer.
///
/// While the ownable portion follows
/// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility,
/// the nomenclature for the 2-step ownership handover may be unique to this codebase.
abstract contract Ownable {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The caller is not authorized to call the function.
error Unauthorized();
/// @dev The `newOwner` cannot be the zero address.
error NewOwnerIsZeroAddress();
/// @dev The `pendingOwner` does not have a valid handover request.
error NoHandoverRequest();
/// @dev Cannot double-initialize.
error AlreadyInitialized();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EVENTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The ownership is transferred from `oldOwner` to `newOwner`.
/// This event is intentionally kept the same as OpenZeppelin's Ownable to be
/// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173),
/// despite it not being as lightweight as a single argument event.
event OwnershipTransferred(address indexed oldOwner, address indexed newOwner);
/// @dev An ownership handover to `pendingOwner` has been requested.
event OwnershipHandoverRequested(address indexed pendingOwner);
/// @dev The ownership handover to `pendingOwner` has been canceled.
event OwnershipHandoverCanceled(address indexed pendingOwner);
/// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`.
uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE =
0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0;
/// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`.
uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE =
0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d;
/// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`.
uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE =
0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STORAGE */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The owner slot is given by:
/// `bytes32(~uint256(uint32(bytes4(keccak256("_OWNER_SLOT_NOT")))))`.
/// It is intentionally chosen to be a high value
/// to avoid collision with lower slots.
/// The choice of manual storage layout is to enable compatibility
/// with both regular and upgradeable contracts.
bytes32 internal constant _OWNER_SLOT =
0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927;
/// The ownership handover slot of `newOwner` is given by:
/// ```
/// mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED))
/// let handoverSlot := keccak256(0x00, 0x20)
/// ```
/// It stores the expiry timestamp of the two-step ownership handover.
uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INTERNAL FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Override to return true to make `_initializeOwner` prevent double-initialization.
function _guardInitializeOwner() internal pure virtual returns (bool guard) {}
/// @dev Initializes the owner directly without authorization guard.
/// This function must be called upon initialization,
/// regardless of whether the contract is upgradeable or not.
/// This is to enable generalization to both regular and upgradeable contracts,
/// and to save gas in case the initial owner is not the caller.
/// For performance reasons, this function will not check if there
/// is an existing owner.
function _initializeOwner(address newOwner) internal virtual {
if (_guardInitializeOwner()) {
/// @solidity memory-safe-assembly
assembly {
let ownerSlot := _OWNER_SLOT
if sload(ownerSlot) {
mstore(0x00, 0x0dc149f0) // `AlreadyInitialized()`.
revert(0x1c, 0x04)
}
// Clean the upper 96 bits.
newOwner := shr(96, shl(96, newOwner))
// Store the new value.
sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner))))
// Emit the {OwnershipTransferred} event.
log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)
}
} else {
/// @solidity memory-safe-assembly
assembly {
// Clean the upper 96 bits.
newOwner := shr(96, shl(96, newOwner))
// Store the new value.
sstore(_OWNER_SLOT, newOwner)
// Emit the {OwnershipTransferred} event.
log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)
}
}
}
/// @dev Sets the owner directly without authorization guard.
function _setOwner(address newOwner) internal virtual {
if (_guardInitializeOwner()) {
/// @solidity memory-safe-assembly
assembly {
let ownerSlot := _OWNER_SLOT
// Clean the upper 96 bits.
newOwner := shr(96, shl(96, newOwner))
// Emit the {OwnershipTransferred} event.
log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)
// Store the new value.
sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner))))
}
} else {
/// @solidity memory-safe-assembly
assembly {
let ownerSlot := _OWNER_SLOT
// Clean the upper 96 bits.
newOwner := shr(96, shl(96, newOwner))
// Emit the {OwnershipTransferred} event.
log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)
// Store the new value.
sstore(ownerSlot, newOwner)
}
}
}
/// @dev Throws if the sender is not the owner.
function _checkOwner() internal view virtual {
/// @solidity memory-safe-assembly
assembly {
// If the caller is not the stored owner, revert.
if iszero(eq(caller(), sload(_OWNER_SLOT))) {
mstore(0x00, 0x82b42900) // `Unauthorized()`.
revert(0x1c, 0x04)
}
}
}
/// @dev Returns how long a two-step ownership handover is valid for in seconds.
/// Override to return a different value if needed.
/// Made internal to conserve bytecode. Wrap it in a public function if needed.
function _ownershipHandoverValidFor() internal view virtual returns (uint64) {
return 48 * 3600;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* PUBLIC UPDATE FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Allows the owner to transfer the ownership to `newOwner`.
function transferOwnership(address newOwner) public payable virtual onlyOwner {
/// @solidity memory-safe-assembly
assembly {
if iszero(shl(96, newOwner)) {
mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`.
revert(0x1c, 0x04)
}
}
_setOwner(newOwner);
}
/// @dev Allows the owner to renounce their ownership.
function renounceOwnership() public payable virtual onlyOwner {
_setOwner(address(0));
}
/// @dev Request a two-step ownership handover to the caller.
/// The request will automatically expire in 48 hours (172800 seconds) by default.
function requestOwnershipHandover() public payable virtual {
unchecked {
uint256 expires = block.timestamp + _ownershipHandoverValidFor();
/// @solidity memory-safe-assembly
assembly {
// Compute and set the handover slot to `expires`.
mstore(0x0c, _HANDOVER_SLOT_SEED)
mstore(0x00, caller())
sstore(keccak256(0x0c, 0x20), expires)
// Emit the {OwnershipHandoverRequested} event.
log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller())
}
}
}
/// @dev Cancels the two-step ownership handover to the caller, if any.
function cancelOwnershipHandover() public payable virtual {
/// @solidity memory-safe-assembly
assembly {
// Compute and set the handover slot to 0.
mstore(0x0c, _HANDOVER_SLOT_SEED)
mstore(0x00, caller())
sstore(keccak256(0x0c, 0x20), 0)
// Emit the {OwnershipHandoverCanceled} event.
log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller())
}
}
/// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`.
/// Reverts if there is no existing ownership handover requested by `pendingOwner`.
function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner {
/// @solidity memory-safe-assembly
assembly {
// Compute and set the handover slot to 0.
mstore(0x0c, _HANDOVER_SLOT_SEED)
mstore(0x00, pendingOwner)
let handoverSlot := keccak256(0x0c, 0x20)
// If the handover does not exist, or has expired.
if gt(timestamp(), sload(handoverSlot)) {
mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`.
revert(0x1c, 0x04)
}
// Set the handover slot to 0.
sstore(handoverSlot, 0)
}
_setOwner(pendingOwner);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* PUBLIC READ FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the owner of the contract.
function owner() public view virtual returns (address result) {
/// @solidity memory-safe-assembly
assembly {
result := sload(_OWNER_SLOT)
}
}
/// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`.
function ownershipHandoverExpiresAt(address pendingOwner)
public
view
virtual
returns (uint256 result)
{
/// @solidity memory-safe-assembly
assembly {
// Compute the handover slot.
mstore(0x0c, _HANDOVER_SLOT_SEED)
mstore(0x00, pendingOwner)
// Load the handover slot.
result := sload(keccak256(0x0c, 0x20))
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* MODIFIERS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Marks a function as only callable by the owner.
modifier onlyOwner() virtual {
_checkOwner();
_;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Reentrancy guard mixin.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/ReentrancyGuard.sol)
abstract contract ReentrancyGuard {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Unauthorized reentrant call.
error Reentrancy();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STORAGE */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Equivalent to: `uint72(bytes9(keccak256("_REENTRANCY_GUARD_SLOT")))`.
/// 9 bytes is large enough to avoid collisions with lower slots,
/// but not too large to result in excessive bytecode bloat.
uint256 private constant _REENTRANCY_GUARD_SLOT = 0x929eee149b4bd21268;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* REENTRANCY GUARD */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Guards a function from reentrancy.
modifier nonReentrant() virtual {
/// @solidity memory-safe-assembly
assembly {
if eq(sload(_REENTRANCY_GUARD_SLOT), address()) {
mstore(0x00, 0xab143c06) // `Reentrancy()`.
revert(0x1c, 0x04)
}
sstore(_REENTRANCY_GUARD_SLOT, address())
}
_;
/// @solidity memory-safe-assembly
assembly {
sstore(_REENTRANCY_GUARD_SLOT, codesize())
}
}
/// @dev Guards a view function from read-only reentrancy.
modifier nonReadReentrant() virtual {
/// @solidity memory-safe-assembly
assembly {
if eq(sload(_REENTRANCY_GUARD_SLOT), address()) {
mstore(0x00, 0xab143c06) // `Reentrancy()`.
revert(0x1c, 0x04)
}
}
_;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Initializable mixin for the upgradeable contracts.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/Initializable.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/proxy/utils/Initializable.sol)
abstract contract Initializable {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The contract is already initialized.
error InvalidInitialization();
/// @dev The contract is not initializing.
error NotInitializing();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EVENTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Triggered when the contract has been initialized.
event Initialized(uint64 version);
/// @dev `keccak256(bytes("Initialized(uint64)"))`.
bytes32 private constant _INTIALIZED_EVENT_SIGNATURE =
0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STORAGE */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The default initializable slot is given by:
/// `bytes32(~uint256(uint32(bytes4(keccak256("_INITIALIZABLE_SLOT")))))`.
///
/// Bits Layout:
/// - [0] `initializing`
/// - [1..64] `initializedVersion`
bytes32 private constant _INITIALIZABLE_SLOT =
0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffbf601132;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Override to return a custom storage slot if required.
function _initializableSlot() internal pure virtual returns (bytes32) {
return _INITIALIZABLE_SLOT;
}
/// @dev Guards an initializer function so that it can be invoked at most once.
///
/// You can guard a function with `onlyInitializing` such that it can be called
/// through a function guarded with `initializer`.
///
/// This is similar to `reinitializer(1)`, except that in the context of a constructor,
/// an `initializer` guarded function can be invoked multiple times.
/// This can be useful during testing and is not expected to be used in production.
///
/// Emits an {Initialized} event.
modifier initializer() virtual {
bytes32 s = _initializableSlot();
/// @solidity memory-safe-assembly
assembly {
let i := sload(s)
// Set `initializing` to 1, `initializedVersion` to 1.
sstore(s, 3)
// If `!(initializing == 0 && initializedVersion == 0)`.
if i {
// If `!(address(this).code.length == 0 && initializedVersion == 1)`.
if iszero(lt(extcodesize(address()), eq(shr(1, i), 1))) {
mstore(0x00, 0xf92ee8a9) // `InvalidInitialization()`.
revert(0x1c, 0x04)
}
s := shl(shl(255, i), s) // Skip initializing if `initializing == 1`.
}
}
_;
/// @solidity memory-safe-assembly
assembly {
if s {
// Set `initializing` to 0, `initializedVersion` to 1.
sstore(s, 2)
// Emit the {Initialized} event.
mstore(0x20, 1)
log1(0x20, 0x20, _INTIALIZED_EVENT_SIGNATURE)
}
}
}
/// @dev Guards an reinitialzer function so that it can be invoked at most once.
///
/// You can guard a function with `onlyInitializing` such that it can be called
/// through a function guarded with `reinitializer`.
///
/// Emits an {Initialized} event.
modifier reinitializer(uint64 version) virtual {
bytes32 s = _initializableSlot();
/// @solidity memory-safe-assembly
assembly {
version := and(version, 0xffffffffffffffff) // Clean upper bits.
let i := sload(s)
// If `initializing == 1 || initializedVersion >= version`.
if iszero(lt(and(i, 1), lt(shr(1, i), version))) {
mstore(0x00, 0xf92ee8a9) // `InvalidInitialization()`.
revert(0x1c, 0x04)
}
// Set `initializing` to 1, `initializedVersion` to `version`.
sstore(s, or(1, shl(1, version)))
}
_;
/// @solidity memory-safe-assembly
assembly {
// Set `initializing` to 0, `initializedVersion` to `version`.
sstore(s, shl(1, version))
// Emit the {Initialized} event.
mstore(0x20, version)
log1(0x20, 0x20, _INTIALIZED_EVENT_SIGNATURE)
}
}
/// @dev Guards a function such that it can only be called in the scope
/// of a function guarded with `initializer` or `reinitializer`.
modifier onlyInitializing() virtual {
_checkInitializing();
_;
}
/// @dev Reverts if the contract is not initializing.
function _checkInitializing() internal view virtual {
bytes32 s = _initializableSlot();
/// @solidity memory-safe-assembly
assembly {
if iszero(and(1, sload(s))) {
mstore(0x00, 0xd7e6bcf8) // `NotInitializing()`.
revert(0x1c, 0x04)
}
}
}
/// @dev Locks any future initializations by setting the initialized version to `2**64 - 1`.
///
/// Calling this in the constructor will prevent the contract from being initialized
/// or reinitialized. It is recommended to use this to lock implementation contracts
/// that are designed to be called through proxies.
///
/// Emits an {Initialized} event the first time it is successfully called.
function _disableInitializers() internal virtual {
bytes32 s = _initializableSlot();
/// @solidity memory-safe-assembly
assembly {
let i := sload(s)
if and(i, 1) {
mstore(0x00, 0xf92ee8a9) // `InvalidInitialization()`.
revert(0x1c, 0x04)
}
let uint64max := shr(192, s) // Computed to save bytecode.
if iszero(eq(shr(1, i), uint64max)) {
// Set `initializing` to 0, `initializedVersion` to `2**64 - 1`.
sstore(s, shl(1, uint64max))
// Emit the {Initialized} event.
mstore(0x20, uint64max)
log1(0x20, 0x20, _INTIALIZED_EVENT_SIGNATURE)
}
}
}
/// @dev Returns the highest version that has been initialized.
function _getInitializedVersion() internal view virtual returns (uint64 version) {
bytes32 s = _initializableSlot();
/// @solidity memory-safe-assembly
assembly {
version := shr(1, sload(s))
}
}
/// @dev Returns whether the contract is currently initializing.
function _isInitializing() internal view virtual returns (bool result) {
bytes32 s = _initializableSlot();
/// @solidity memory-safe-assembly
assembly {
result := and(1, sload(s))
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Contract that enables a single call to call multiple methods on itself.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/Multicallable.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/Multicallable.sol)
///
/// WARNING:
/// This implementation is NOT to be used with ERC2771 out-of-the-box.
/// https://blog.openzeppelin.com/arbitrary-address-spoofing-vulnerability-erc2771context-multicall-public-disclosure
/// This also applies to potentially other ERCs / patterns appending to the back of calldata.
///
/// We do NOT have a check for ERC2771, as we do not inherit from OpenZeppelin's context.
/// Moreover, it is infeasible and inefficient for us to add checks and mitigations
/// for all possible ERC / patterns appending to the back of calldata.
///
/// We would highly recommend using an alternative pattern such as
/// https://github.com/Vectorized/multicaller
/// which is more flexible, futureproof, and safer by default.
abstract contract Multicallable {
/// @dev Apply `DELEGATECALL` with the current contract to each calldata in `data`,
/// and store the `abi.encode` formatted results of each `DELEGATECALL` into `results`.
/// If any of the `DELEGATECALL`s reverts, the entire context is reverted,
/// and the error is bubbled up.
///
/// This function is deliberately made non-payable to guard against double-spending.
/// (See: https://www.paradigm.xyz/2021/08/two-rights-might-make-a-wrong)
///
/// For efficiency, this function will directly return the results, terminating the context.
/// If called internally, it must be called at the end of a function
/// that returns `(bytes[] memory)`.
function multicall(bytes[] calldata data) public virtual returns (bytes[] memory) {
assembly {
mstore(0x00, 0x20)
mstore(0x20, data.length) // Store `data.length` into `results`.
// Early return if no data.
if iszero(data.length) { return(0x00, 0x40) }
let results := 0x40
// `shl` 5 is equivalent to multiplying by 0x20.
let end := shl(5, data.length)
// Copy the offsets from calldata into memory.
calldatacopy(0x40, data.offset, end)
// Offset into `results`.
let resultsOffset := end
// Pointer to the end of `results`.
end := add(results, end)
for {} 1 {} {
// The offset of the current bytes in the calldata.
let o := add(data.offset, mload(results))
let m := add(resultsOffset, 0x40)
// Copy the current bytes from calldata to the memory.
calldatacopy(
m,
add(o, 0x20), // The offset of the current bytes' bytes.
calldataload(o) // The length of the current bytes.
)
if iszero(delegatecall(gas(), address(), m, calldataload(o), codesize(), 0x00)) {
// Bubble up the revert if the delegatecall reverts.
returndatacopy(0x00, 0x00, returndatasize())
revert(0x00, returndatasize())
}
// Append the current `resultsOffset` into `results`.
mstore(results, resultsOffset)
results := add(results, 0x20)
// Append the `returndatasize()`, and the return data.
mstore(m, returndatasize())
returndatacopy(add(m, 0x20), 0x00, returndatasize())
// Advance the `resultsOffset` by `returndatasize() + 0x20`,
// rounded up to the next multiple of 32.
resultsOffset :=
and(add(add(resultsOffset, returndatasize()), 0x3f), 0xffffffffffffffe0)
if iszero(lt(results, end)) { break }
}
return(0x00, add(resultsOffset, 0x40))
}
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
interface IMessageEscrowStructs {
struct IncentiveDescription {
uint48 maxGasDelivery; // 0: 6/32 bytes
uint48 maxGasAck; // 0: 12/32 bytes
address refundGasTo; // 0: 32/32 bytes
uint96 priceOfDeliveryGas; // 1: 12/32 bytes
uint96 priceOfAckGas; // 1: 24/32 bytes
uint64 targetDelta; // 1: 32/32 bytes
}
}//SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import { ICatalystV1FactoryEvents } from "./ICatalystV1FactoryEvents.sol";
interface ICatalystV1Factory is ICatalystV1FactoryEvents {
function _defaultGovernanceFee() external view returns (uint64);
function _governanceFeeDestination() external view returns (address);
function deployVault(
address vaultTemplate,
address[] memory assets,
uint256[] memory init_balances,
uint256[] memory weights,
uint64 amp,
uint64 vaultFee,
string memory name,
string memory symbol,
address chainInterface
) external returns (address);
function isCreatedByFactory(address, address) external view returns (bool);
function setDefaultGovernanceFee(uint64 fee) external;
function setGovernanceFeeDestination(address feeDestination) external;
}//SPDX-License-Identifier: MIT pragma solidity ^0.8.17; error EscrowAlreadyExists(); // 0xed778779 error ExceedsSecurityLimit(); // 0x7c1e66d0 error NotEnoughGas(); // 0xdd629f86 error ReturnInsufficient(uint256,uint256); // 0x24557f05 error UnusedUnitsAfterWithdrawal(uint256); // 0x0289311f error VaultNotConnected(); // 0x2c64c1b2 error WithdrawRatioNotZero(); // 0xb8003bfa
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.19;
import { Ownable } from "solady/auth/Ownable.sol";
import { SafeTransferLib } from 'solady/utils/SafeTransferLib.sol';
import { LibClone } from "solady/utils/LibClone.sol";
import { ICatalystV1Factory } from "./interfaces/ICatalystV1Factory.sol";
import { ICatalystV1Vault } from "./ICatalystV1Vault.sol";
uint256 constant MAX_GOVERNANCE_FEE_SHARE = 75e16; // 75%
/**
* @title Catalyst Swap Factory
* @author Cata Labs Inc.
* @notice Allows permissionless deployment Catalyst vaults and defines governance address for vaults to read.
* Importantly, this vault allows anyone to deploy a vault using any vault template and vault cross-chain interface.
* As a result, just because a vault was deployed using this contract does not imply that it is safe. Vaults should
* be cross-checked for their template, cross-chain interface, and if they are setup correctly. It may even be
* that some vault templates only work with some cross-chain interfaces.
*
* Using the reference Catalyst Vault Templates, the owner of the factory is also the _owner_ of the Vaults.
* They have certain privilege that may be able to be abused depending on the vault. One of these is configurating
* fees. As a result:
* !The owner of the factory must be a timelock!
*/
contract CatalystFactory is Ownable, ICatalystV1Factory {
error InvalidAssetCount();
error InvalidWeightCount();
error FeeDestinationAddress0();
error MaximumGovernanceFeeShare();
/**
* @notice A mapping which describes if a vault has been created by this factory.
* Indexed by chainInterface then vault address.
*/
mapping(address => mapping(address => bool)) public isCreatedByFactory;
/**
* @notice Default governance fee. When a vault is created, this is the governance fee applied to that vault.
*/
uint64 public _defaultGovernanceFee;
/**
* @notice The address to send governance fees to.
* @dev Not enforced by the factory but vaults are expected to follow it.
*/
address public _governanceFeeDestination;
// The 2 above storage slots are packed together.
constructor(address defaultOwner) payable {
_initializeOwner(defaultOwner);
_governanceFeeDestination = defaultOwner;
}
/**
* @notice Set default governance fee share.
* @dev The set governance fee only applies to newly created vaults. Vaults have to be individual modified post creation.
* Is in WAD, (1e18 terms). So 1e16 is 1%. Cannot be set larger than 75% (75e16).
*/
function setDefaultGovernanceFee(uint64 fee) override public onlyOwner {
if (fee > MAX_GOVERNANCE_FEE_SHARE) revert MaximumGovernanceFeeShare();
emit SetDefaultGovernanceFee(fee);
_defaultGovernanceFee = fee;
}
/**
* @notice Set the recipient of the governance.
* @dev It is expected that vaults read this value and send their governance fees here.
* This contract has no way to enforce if vaults honour this value.
* Cannot be set to address(0). If wish to burn, set to 0xdead.
*/
function setGovernanceFeeDestination(address feeDestination) override public onlyOwner {
if (feeDestination == address(0)) revert FeeDestinationAddress0();
emit SetGovernanceFeeDestination(feeDestination);
_governanceFeeDestination = feeDestination;
}
/**
* @notice Deploys a Catalyst vault, funds the vault with tokens, and calls setup.
* When deploying vaults, there are 2 stages that needs to happen:
* 1. We need to setup the vaults with the correct configuration.
* 2. We need to set the vault swap curve. This consists of setting assets, vaults, amplification, etc.
* The reason it is done in 2 steps is because of the stack limit. By spreading it across 2 calls, it is
* cheaper gas wise.
* This is done in a safe way by expecting both of these init. calls to be done in a single transaction.
* As a result, the vaults are never left in a vulnerable state. It is expected that the latter call
* (initializeSwapCurves) completes initialization and blocks the setup functions from being called again.
* @dev The deployer needs to set relevant approvals to this contract before calling deployVault.
* @param vaultTemplate The template the transparent proxy should target.
* @param assets The list of assets the vault should support.
* @param init_balances The initial balances of the vault. (Should be approved)
* @param weights The weights of the tokens.
* @param amp Token parameter 1. (Amplification)
* @param vaultFee The vault fee.
* @param name Name of the Vault token.
* @param symbol Symbol for the Vault token.
* @param chainInterface The cross chain interface used for cross-chain swaps. (Can be address(0) to disable cross-chain swaps.)
* @return vault The address of the created Catalyst Vault. (minimal transparent proxy)
*/
function deployVault(
address vaultTemplate,
address[] calldata assets,
uint256[] calldata init_balances,
uint256[] calldata weights,
uint64 amp,
uint64 vaultFee,
string memory name,
string memory symbol,
address chainInterface
) override external returns (address vault) {
// Check if an invalid asset count has been provided
if (assets.length == 0) revert InvalidAssetCount();
// Check if an invalid weight count has been provided
if (weights.length != assets.length) revert InvalidWeightCount();
// init_balances length not checked: if shorter than assets, the funds transfer loop
// will fail. If longer, values will just be ignored.
// Create a minimal transparent proxy:
vault = LibClone.clone(vaultTemplate);
// The vault expects the balances to exist in the vault when setup is called.
uint256 assetLength = assets.length;
for (uint256 it; it < assetLength;) {
SafeTransferLib.safeTransferFrom(
assets[it],
msg.sender,
vault,
init_balances[it]
);
unchecked {
++it;
}
}
// Call setup
ICatalystV1Vault(vault).setup(
name,
symbol,
chainInterface,
vaultFee,
_defaultGovernanceFee,
owner(), // Fee administrator
msg.sender // setup master
);
// Initialize swap curves
ICatalystV1Vault(vault).initializeSwapCurves(
assets,
weights,
amp,
msg.sender
);
// Emit event for vault discovery.
emit VaultDeployed(
vaultTemplate,
chainInterface,
msg.sender,
vault,
assets,
amp
);
isCreatedByFactory[chainInterface][vault] = true;
return vault;
}
}//SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
/**
* @title Escrow related functions defined by Catalyst v1 Vaults
* @notice Contains the functions used to manage escrows by the cross-chain interface.
*/
interface ICatalystV1VaultSuccessFailure {
/** @notice Release the escrowed tokens into the vault. */
function onSendAssetSuccess(
bytes32 channelId,
bytes calldata toAccount,
uint256 U,
uint256 escrowAmount,
address escrowToken,
uint32 blockNumberMod
) external;
/** @notice Returned the escrowed tokens to the user */
function onSendAssetFailure(
bytes32 channelId,
bytes calldata toAccount,
uint256 U,
uint256 escrowAmount,
address escrowToken,
uint32 blockNumberMod
) external;
/** @notice Release the escrowed tokens into the vault. */
function onSendLiquiditySuccess(
bytes32 channelId,
bytes calldata toAccount,
uint256 U,
uint256 escrowAmount,
uint32 blockNumberMod
) external;
/** @notice Returned the escrowed tokens to the user */
function onSendLiquidityFailure(
bytes32 channelId,
bytes calldata toAccount,
uint256 U,
uint256 escrowAmount,
uint32 blockNumberMod
) external;
}//SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
/**
* @title Administrative actions defined by Catalyst v1 Vaults
* @notice Contains all functions which can only be called by privileged users.
*/
interface ICatalystV1VaultAdministration {
function setFeeAdministrator(address administrator) external;
function setVaultFee(uint64 fee) external;
function setGovernanceFee(uint64 fee) external;
/**
* @notice Initializes the vault pricing parameters.
* @param assets The list of assets the vault will support.
* @param weights The weights of the tokens.
* @param amp Vault amplification.
* @param depositor The account to which the initial vault tokens are minted to.
*/
function initializeSwapCurves(
address[] calldata assets,
uint256[] calldata weights,
uint64 amp,
address depositor
) external;
/**
* @notice Creates a connection to the vault toVault on the channel _channelId.
* @dev if _vaultReceiving is an EVM vault, it can be computes as:
* Vyper: convert(_vaultAddress, bytes32)
* Solidity: abi.encode(_vaultAddress)
* Brownie: brownie.convert.to_bytes(_vaultAddress, type_str="bytes32")
* setupMaster == ZERO_ADDRESS
* @param channelId The _channelId of the target vault.
* @param toVault The bytes32 representation of the target vault
* @param state Boolean indicating if the connection should be open or closed.
*/
function setConnection(
bytes32 channelId,
bytes calldata toVault,
bool state
) external;
/**
* @notice Gives up short term ownership of the vault. This makes the vault unstoppable.
*/
function finishSetup() external;
}//SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
/**
* @title Derived Vault state
* @notice Contains all vault state which is derived from vault storage
*/
interface ICatalystV1VaultDerived {
/** @notice Returns the current cross-chain unit capacity. */
function getUnitCapacity() external view returns (uint256);
function calcSendAsset(address from, uint256 amount) external view returns (uint256);
/**
* @notice Computes the output of ReceiveAsset, without executing one.
* @param to The address of the token to buy.
* @param U The number of units used to buy to.
* @return uint256 Number of purchased tokens.
*/
function calcReceiveAsset(address to, uint256 U) external view returns (uint256);
/**
* @notice Computes the output of localSwap, without executing one.
* @param from The address of the token to sell.
* @param to The address of the token to buy.
* @param amount The amount of from token to sell for to token.
* @return Output denominated in to token.
*/
function calcLocalSwap(address from, address to, uint256 amount) external view returns (uint256);
}//SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
/**
* @title Events emitted by Catalyst v1 Vaults
* @notice Contains all events emitted by the vault
* @dev When using events to match transations, the combination of: channelId, fromVault, toAccount, toAsset, units, and block number is semi-guranteed to be unique.
* If more than 2**32 blocks exist, then all instances are guaranteed to be non-overlapping
*/
interface ICatalystV1VaultEvents {
/**
* @notice Describes an atomic swap between the 2 tokens: _fromAsset and _toAsset.
* @param account The user / exchange who facilitated the trade (msg.sender)
* @param fromAsset The asset which was sold in exchange for _toAsset
* @param toAsset The asset which was purchased with _fromAsset
* @param fromAmount The number of _fromAsset sold
* @param toAmount The number of tokens provided to toAccount
*/
event LocalSwap(
address indexed account,
address fromAsset,
address toAsset,
uint256 fromAmount,
uint256 toAmount
);
/**
* @notice Describes the creation of an external swap: Cross-chain swap.
* @param channelId The target chain identifier
* @param toVault The target vault.
* @param toAccount The recipient of the trade. The person who bought the trade is not present.
* @param fromAsset The asset which was sold in exchange for _toAsset.
* @param toAssetIndex The token index of the asset to purchase on _toChain.
* @param fromAmount The number of _fromAsset sold.
* @param minOut The minimum output to be accepted of fromAsset.
* @param units The calculated number of units bought. Will be sold to buy _toAsset
* @param underwriteIncentiveX16 The incentive out of 2**16 - 1 provided to the underwriter.
* @param fee The number of tokens paid to the vault in fees.
*/
event SendAsset(
bytes32 channelId,
bytes toVault,
bytes toAccount,
address fromAsset,
uint8 toAssetIndex,
uint256 fromAmount,
uint256 minOut,
uint256 units,
uint256 fee,
uint16 underwriteIncentiveX16
);
/**
* @notice Describes the arrival of an external swap: Cross-chain swap.
* If toAccount is used to match trades, remember to convert it into 64 + 1 bytes.
* @param channelId The target chain identifier
* @param fromVault The source vault.
* @param toAccount The recipient of the trade.
* @param toAsset The asset which was purchased with _fromAsset
* @param units The number of units sent from the other chain.
* @param toAmount The number of tokens provided to toAccount
* @param fromAmount The amount spent to get units on the source side.
* @param fromAsset The provided asset on the source side.
* @param sourceBlockNumberMod The block number of the sending transaction mod 2**32 - 1
*/
event ReceiveAsset(
bytes32 channelId,
bytes fromVault,
address toAccount,
address toAsset,
uint256 units,
uint256 toAmount,
uint256 fromAmount,
bytes fromAsset,
uint32 sourceBlockNumberMod
);
/**
* @notice Describes the creation of a liquidity swap
* @param channelId The target chain identifier
* @param toVault The target vault.
* @param toAccount The recipient of the liquidity. The person who bought the trade is not present.
* @param fromAmount The number of _fromAsset sold
* @param minOut An array containing a list of minimum outputs [minVaultTokens, minReferenceAssets]
* @param units The calculated number of liquidity units bought.
*/
event SendLiquidity(
bytes32 channelId,
bytes toVault,
bytes toAccount,
uint256 fromAmount,
uint256[2] minOut,
uint256 units
);
/**
* @notice Describes the arrival of a liquidity swap
* @param channelId The target chain identifier
* @param fromVault The source vault.
* @param toAccount The recipient of the liquidity.
* @param units The number of liquidity units sent from the other chain.
* @param toAmount The number of vault tokens provided to toAccount
* @param fromAmount The amount spent to get units on the source side.
* @param sourceBlockNumberMod The block number of the sending transaction mod 2**32 - 1
*/
event ReceiveLiquidity(
bytes32 channelId,
bytes fromVault,
address toAccount,
uint256 units,
uint256 toAmount,
uint256 fromAmount,
uint256 sourceBlockNumberMod
);
/**
* @notice Emitted on liquidity deposits.
* @param toAccount The depositor. Is credited with _mints vault tokens.
* @param mint The number of minted vault tokens credited to toAccount
* @param assets An array of the number of deposited assets.
*/
event VaultDeposit(address indexed toAccount, uint256 mint, uint256[] assets);
/**
* @notice Emitted on liquidity withdrawal.
* @param toAccount The withdrawer. Is debited _burns vault tokens.
* @param burn The number of burned vault tokens.
* @param assets An array of the token amounts returned
*/
event VaultWithdraw(address indexed toAccount, uint256 burn, uint256[] assets);
/** @notice Called upon successful asset swap. */
event SendAssetSuccess(
bytes32 channelId,
bytes toAccount,
uint256 units,
uint256 escrowAmount,
address escrowToken,
uint32 blockNumberMod
);
/** @notice Called upon failed asset swap. */
event SendAssetFailure(
bytes32 channelId,
bytes toAccount,
uint256 units,
uint256 escrowAmount,
address escrowToken,
uint32 blockNumberMod
);
/** @notice Called upon successful liquidity swap. */
event SendLiquiditySuccess(
bytes32 channelId,
bytes toAccount,
uint256 units,
uint256 escrowAmount,
uint32 blockNumberMod
);
/** @notice Called upon failed liquidity swap. */
event SendLiquidityFailure(
bytes32 channelId,
bytes toAccount,
uint256 units,
uint256 escrowAmount,
uint32 blockNumberMod
);
/** @notice Vault setup has been finalised. */
event FinishSetup();
/**
* @notice Emitted on fee administrator adjustment
* @param administrator The new vault fee administrator
*/
event SetFeeAdministrator(
address administrator
);
/**
* @notice Emitted on vault fee adjustment
* @param fee The new vault fee
*/
event SetVaultFee(
uint64 fee
);
/**
* @notice Emitted on governance fee adjustment
* @param fee The new governance fee
*/
event SetGovernanceFee(
uint64 fee
);
/**
* @notice Emitted on weights modification
* @param targetTime Time at which the weights adjustment must complete.
* @param targetWeights The desired new weights.
*/
event SetWeights(
uint248 targetTime,
uint256[] targetWeights
);
/**
* @notice Amplification has been modification
* @param targetTime Time at which the amplification adjustment must complete.
* @param targetAmplification The desired new amplification.
*/
event SetAmplification(
uint48 targetTime,
uint256 targetAmplification
);
/**
* @notice A connection has been modified
* @param channelId Target chain identifier.
* @param toVault Bytes32 representation of the target vault.
* @param newState Boolean indicating if the connection should be open or closed.
*/
event SetConnection(
bytes32 channelId,
bytes toVault,
bool newState
);
//-- Underwriting Events --//
/**
* @notice A swap has been underwritten.
*/
event SwapUnderwritten(
bytes32 indexed identifier,
address toAsset,
uint256 U,
uint256 purchasedTokens
);
}//SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
/**
* @title Immutable vault state
* @notice Contains all vault state which doesn't change once set.
*/
interface ICatalystV1VaultImmutables {
function _chainInterface() external view returns (address);
function FACTORY() external view returns (address);
function MATHLIB() external view returns (address);
/**
* @notice To indicate which token is desired on the target vault,the _toAsset is an integer
* from 0 to MAX_ASSETS indicating which asset the vault should purchase with units.
*/
function _tokenIndexing(uint256 tokenIndex) external view returns (address);
}//SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import { ICatalystV1Structs } from "./ICatalystV1VaultState.sol";
interface ICatalystV1VaultPermissionless {
/**
* @notice Setup a vault.
* @param name_ Name of the Vault token.
* @param symbol_ Symbol for the Vault token.
* @param chainInterface Cross chain interface used for cross-chain swaps. (Can be address(0) to disable cross-chain swaps.)
* @param vaultFee Vault fee.
* @param governanceFee Governance fee share.
* @param feeAdministrator Account that can modify the fees.
* @param setupMaster Short-term owner of the vault (until finishSetup is called).
*/
function setup(
string calldata name_,
string calldata symbol_,
address chainInterface,
uint64 vaultFee,
uint64 governanceFee,
address feeAdministrator,
address setupMaster
) external;
//--- Balance Changes ---//
/**
* @notice Deposits a user configurable amount of tokens.
* @dev Requires approvals for all deposited tokens within the vault.
* Volatile: It is advised that the deposit matches the vault's %token distribution.
* Amplified: It is advised that the deposit is as close to 1,1,... as possible.
* Otherwise between 1,1,... and the vault's %token distribution.
* @param tokenAmounts Array of the tokens amounts to be deposited.
* @param minOut Minimum number of vault tokens to be minted.
*/
function depositMixed(uint256[] calldata tokenAmounts, uint256 minOut)
external returns(uint256);
/**
* @notice Burns baseAmount and releases the symmetrical share
* of tokens to the burner. This doesn't change the vault price.
* @param baseAmount Number of vault tokens to burn.
*/
function withdrawAll(uint256 baseAmount, uint256[] calldata minOut)
external returns(uint256[] memory);
/**
* @notice Burns vaultTokens and release a token distribution which can be set by the user.
* @dev Requires approvals for all tokens within the vault.
* Volatile: It is advised that the deposit matches the vault's %token distribution.
* Amplified: It is advised that the deposit matches the vault's %token distribution.
* Otherwise it should be weighted towards the tokens the vault has more of.
* @param vaultTokens Number of vault tokens to withdraw.
* @param withdrawRatio Percentage of units used to withdraw. In the following special scheme: U_0 = U · withdrawRatio[0], U_1 = (U - U_0) · withdrawRatio[1], U_2 = (U - U_0 - U_1) · withdrawRatio[2], .... Is WAD.
* @param minOut Minimum number of tokens minted.
*/
function withdrawMixed(
uint256 vaultTokens,
uint256[] calldata withdrawRatio,
uint256[] calldata minOut
) external returns(uint256[] memory);
//--- Swaps ---//
/**
* @notice A swap between 2 assets which both are inside the vault. Is atomic.
* @param fromAsset Asset the user wants to sell.
* @param toAsset Asset the user wants to buy.
* @param amount Amount of fromAsset the user wants to sell.
* @param minOut Minimum output of _toAsset the user wants.
*/
function localSwap(
address fromAsset,
address toAsset,
uint256 amount,
uint256 minOut
) external returns (uint256);
/**
* @notice Initiate a cross-chain swap by purchasing units and transfer them to another vault.
* @dev Addresses are encoded in 64 + 1 bytes. To encode for EVM, encode as:
* Solidity: abi.encodePacket(uint8(20), bytes32(0), abi.encode(<vaultAddress>))
* @param routeDescription A cross-chain route description which contains the chainIdentifier, toAccount, toVault and relaying incentive.
* @param fromAsset Asset the user wants to sell.
* @param toAssetIndex Index of the asset the user wants to buy in the target vault.
* @param amount Number of fromAsset to sell to the vault.
* @param minOut Minimum number of returned tokens to the toAccount on the target chain.
* @param fallbackUser If the transaction fails, send the escrowed funds to this address.
* @param underwriteIncentiveX16 Payment for underwriting the swap (out of type(uint16.max))
* @param calldata_ Data field if a call should be made on the target chain.
* Encoding depends on the target chain, with EVM: abi.encodePacket(bytes20(<address>), <data>). At maximum 65535 bytes can be passed.
* @return uint256 The number of units minted.
*/
function sendAsset(
ICatalystV1Structs.RouteDescription calldata routeDescription,
address fromAsset,
uint8 toAssetIndex,
uint256 amount,
uint256 minOut,
address fallbackUser,
uint16 underwriteIncentiveX16,
bytes calldata calldata_
) external payable returns (uint256);
/**
* @notice Initiate a cross-chain swap by purchasing units and transfer them to another vault using a fixed number of units.
* @dev Addresses are encoded in 64 + 1 bytes. To encode for EVM, encode as:
* Solidity: abi.encodePacket(uint8(20), bytes32(0), abi.encode(<vaultAddress>))
* @param routeDescription A cross-chain route description which contains the chainIdentifier, toAccount, toVault and relaying incentive.
* @param fromAsset Asset the user wants to sell.
* @param toAssetIndex Index of the asset the user wants to buy in the target vault.
* @param amount Number of fromAsset to sell to the vault.
* @param minOut Minimum number of returned tokens to the toAccount on the target chain.
* @param minU Minimum and exact number of units sent.
* @param fallbackUser If the transaction fails, send the escrowed funds to this address.
* @param calldata_ Data field if a call should be made on the target chain.
* Encoding depends on the target chain, with evm being: abi.encodePacket(bytes20(<address>), <data>)
* @param underwriteIncentiveX16 Payment for underwriting the swap (out of type(uint16.max))
* @return uint256 Number of units minted.
*/
function sendAssetFixedUnit(
ICatalystV1Structs.RouteDescription calldata routeDescription,
address fromAsset,
uint8 toAssetIndex,
uint256 amount,
uint256 minOut,
uint256 minU,
address fallbackUser,
uint16 underwriteIncentiveX16,
bytes calldata calldata_
) external payable returns (uint256);
/**
* @notice Completes a cross-chain swap by converting units to the desired token (toAsset)
* @dev Can only be called by the chainInterface.
* @param channelId The incoming connection identifier.
* @param fromVault The source vault.
* @param toAssetIndex Index of the asset to be purchased with Units.
* @param toAccount The recipient.
* @param U Number of units to convert into toAsset.
* @param minOut Minimum number of tokens bought. Reverts if less.
* @param fromAmount Used to match cross-chain swap events. The input amount on the sending chain.
* @param fromAsset Used to match cross-chain swap events. The input asset on the sending chain.
* @param blockNumberMod Used to match cross-chain swap events. The block number from the host side.
*/
function receiveAsset(
bytes32 channelId,
bytes calldata fromVault,
uint256 toAssetIndex,
address toAccount,
uint256 U,
uint256 minOut,
uint256 fromAmount,
bytes calldata fromAsset,
uint32 blockNumberMod
) external returns(uint256 purchasedTokens);
/**
* @notice Initiate a cross-chain liquidity swap by withdrawing tokens and converting them to units.
* @dev While the description says tokens are withdrawn and then converted to units, vault tokens are converted
* directly into units through the following equation:
* U = ln(PT/(PT-pt)) * \sum W_i
* @param routeDescription A cross-chain route description which contains the chainIdentifier, toAccount, toVault and relaying incentive.
* @param vaultTokens Number of vault tokens to exchange.
* @param minOut Array of minout describing: [the minimum number of vault tokens, the minimum number of reference assets].
* @param fallbackUser If the transaction fails, send the escrowed funds to this address.
* @param calldata_ Data field if a call should be made on the target chain.
* Encoding depends on the target chain, with EVM: abi.encodePacket(bytes20(<address>), <data>). At maximum 65535 bytes can be passed.
* @return uint256 Number of units minted.
*/
function sendLiquidity(
ICatalystV1Structs.RouteDescription calldata routeDescription,
uint256 vaultTokens,
uint256[2] calldata minOut,
address fallbackUser,
bytes calldata calldata_
) external payable returns (uint256);
/**
* @notice Completes a cross-chain liquidity swap by converting units to tokens and depositing.
* @dev Called exclusively by the chainInterface.
* @param fromVault Source vault
* @param toAccount Recipient of the vault tokens
* @param U Number of units to convert into vault tokens.
* @param minVaultTokens Minimum number of vault tokens to mint on target vault. Otherwise: Reject
* @param minReferenceAsset Minimum number of reference asset the vaults tokens are worth. Otherwise: Reject
* @param fromAmount Used to match cross-chain swap events. The input amount on the sending chain.
* @param blockNumberMod Used to match cross-chain swap events. The block number from the host side.
*/
function receiveLiquidity(
bytes32 channelId,
bytes calldata fromVault,
address toAccount,
uint256 U,
uint256 minVaultTokens,
uint256 minReferenceAsset,
uint256 fromAmount,
uint32 blockNumberMod
) external returns(uint256 purchasedVaultTokens);
}//SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
/** @title Extensions to vaults which supports underwriting. */
interface ICatalystV1Underwriting {
function underwriteAsset(
bytes32 identifier,
address toAsset,
uint256 U,
uint256 minOut
) external returns (uint256);
function releaseUnderwriteAsset(
address refundTo,
bytes32 identifier,
uint256 escrowAmount,
address escrowToken,
bytes32 sourceIdentifier,
bytes calldata fromVault
) external;
function deleteUnderwriteAsset(
bytes32 identifier,
uint256 U,
uint256 escrowAmount,
address escrowToken
) external;
}//SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
/**
* @title Events emitted by Catalyst v1 Factory
* @notice Contains all events emitted by the Factory
*/
interface ICatalystV1FactoryEvents {
/**
* @notice Describes the deployment of a new vault as a proxy of the given vault template.
* @dev Should be used for vault discovery and pathing.
* @param vaultTemplate The address of the template used by the transparent proxy.
* @param chainInterface The address of the CCI used by the transparent proxy.
* @param vaultAddress The minimal transparent proxy address for the vault.
* @param assets List of the assets the vault supports.
* @param k Set to 10**18 if the vault is volatile, otherwise the vault is an amplified vault.
*/
event VaultDeployed(
address indexed vaultTemplate,
address indexed chainInterface,
address indexed deployer,
address vaultAddress,
address[] assets,
uint256 k
);
/**
* @notice Describes governance fee changes.
* @dev Only applies to new vaults, has no impact on existing vaults.
* @param fee The new governance fee.
*/
event SetDefaultGovernanceFee(
uint256 fee
);
/**
* @notice Sets a new destination for governance fees.
*/
event SetGovernanceFeeDestination(
address newFeeDestination
);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Minimal proxy library.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibClone.sol)
/// @author Minimal proxy by 0age (https://github.com/0age)
/// @author Clones with immutable args by wighawag, zefram.eth, Saw-mon & Natalie
/// (https://github.com/Saw-mon-and-Natalie/clones-with-immutable-args)
/// @author Minimal ERC1967 proxy by jtriley-eth (https://github.com/jtriley-eth/minimum-viable-proxy)
///
/// @dev Minimal proxy:
/// Although the sw0nt pattern saves 5 gas over the erc-1167 pattern during runtime,
/// it is not supported out-of-the-box on Etherscan. Hence, we choose to use the 0age pattern,
/// which saves 4 gas over the erc-1167 pattern during runtime, and has the smallest bytecode.
///
/// @dev Minimal proxy (PUSH0 variant):
/// This is a new minimal proxy that uses the PUSH0 opcode introduced during Shanghai.
/// It is optimized first for minimal runtime gas, then for minimal bytecode.
/// The PUSH0 clone functions are intentionally postfixed with a jarring "_PUSH0" as
/// many EVM chains may not support the PUSH0 opcode in the early months after Shanghai.
/// Please use with caution.
///
/// @dev Clones with immutable args (CWIA):
/// The implementation of CWIA here implements a `receive()` method that emits the
/// `ReceiveETH(uint256)` event. This skips the `DELEGATECALL` when there is no calldata,
/// enabling us to accept hard gas-capped `sends` & `transfers` for maximum backwards
/// composability. The minimal proxy implementation does not offer this feature.
///
/// @dev Minimal ERC1967 proxy:
/// An minimal ERC1967 proxy, intended to be upgraded with UUPS.
/// This is NOT the same as ERC1967Factory's transparent proxy, which includes admin logic.
///
/// @dev ERC1967I proxy:
/// An variant of the minimal ERC1967 proxy, with a special code path that activates
/// if `calldatasize() == 1`. This code path skips the delegatecall and directly returns the
/// `implementation` address. The returned implementation is guaranteed to be valid if the
/// keccak256 of the proxy's code is equal to `ERC1967I_CODE_HASH`.
library LibClone {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The keccak256 of the deployed code for the ERC1967 proxy.
bytes32 internal constant ERC1967_CODE_HASH =
0xaaa52c8cc8a0e3fd27ce756cc6b4e70c51423e9b597b11f32d3e49f8b1fc890d;
/// @dev The keccak256 of the deployed code for the ERC1967I proxy.
bytes32 internal constant ERC1967I_CODE_HASH =
0xce700223c0d4cea4583409accfc45adac4a093b3519998a9cbbe1504dadba6f7;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Unable to deploy the clone.
error DeploymentFailed();
/// @dev The salt must start with either the zero address or `by`.
error SaltDoesNotStartWith();
/// @dev The ETH transfer has failed.
error ETHTransferFailed();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* MINIMAL PROXY OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Deploys a clone of `implementation`.
function clone(address implementation) internal returns (address instance) {
instance = clone(0, implementation);
}
/// @dev Deploys a clone of `implementation`.
/// Deposits `value` ETH during deployment.
function clone(uint256 value, address implementation) internal returns (address instance) {
/// @solidity memory-safe-assembly
assembly {
/**
* --------------------------------------------------------------------------+
* CREATION (9 bytes) |
* --------------------------------------------------------------------------|
* Opcode | Mnemonic | Stack | Memory |
* --------------------------------------------------------------------------|
* 60 runSize | PUSH1 runSize | r | |
* 3d | RETURNDATASIZE | 0 r | |
* 81 | DUP2 | r 0 r | |
* 60 offset | PUSH1 offset | o r 0 r | |
* 3d | RETURNDATASIZE | 0 o r 0 r | |
* 39 | CODECOPY | 0 r | [0..runSize): runtime code |
* f3 | RETURN | | [0..runSize): runtime code |
* --------------------------------------------------------------------------|
* RUNTIME (44 bytes) |
* --------------------------------------------------------------------------|
* Opcode | Mnemonic | Stack | Memory |
* --------------------------------------------------------------------------|
* |
* ::: keep some values in stack ::::::::::::::::::::::::::::::::::::::::::: |
* 3d | RETURNDATASIZE | 0 | |
* 3d | RETURNDATASIZE | 0 0 | |
* 3d | RETURNDATASIZE | 0 0 0 | |
* 3d | RETURNDATASIZE | 0 0 0 0 | |
* |
* ::: copy calldata to memory ::::::::::::::::::::::::::::::::::::::::::::: |
* 36 | CALLDATASIZE | cds 0 0 0 0 | |
* 3d | RETURNDATASIZE | 0 cds 0 0 0 0 | |
* 3d | RETURNDATASIZE | 0 0 cds 0 0 0 0 | |
* 37 | CALLDATACOPY | 0 0 0 0 | [0..cds): calldata |
* |
* ::: delegate call to the implementation contract :::::::::::::::::::::::: |
* 36 | CALLDATASIZE | cds 0 0 0 0 | [0..cds): calldata |
* 3d | RETURNDATASIZE | 0 cds 0 0 0 0 | [0..cds): calldata |
* 73 addr | PUSH20 addr | addr 0 cds 0 0 0 0 | [0..cds): calldata |
* 5a | GAS | gas addr 0 cds 0 0 0 0 | [0..cds): calldata |
* f4 | DELEGATECALL | success 0 0 | [0..cds): calldata |
* |
* ::: copy return data to memory :::::::::::::::::::::::::::::::::::::::::: |
* 3d | RETURNDATASIZE | rds success 0 0 | [0..cds): calldata |
* 3d | RETURNDATASIZE | rds rds success 0 0 | [0..cds): calldata |
* 93 | SWAP4 | 0 rds success 0 rds | [0..cds): calldata |
* 80 | DUP1 | 0 0 rds success 0 rds | [0..cds): calldata |
* 3e | RETURNDATACOPY | success 0 rds | [0..rds): returndata |
* |
* 60 0x2a | PUSH1 0x2a | 0x2a success 0 rds | [0..rds): returndata |
* 57 | JUMPI | 0 rds | [0..rds): returndata |
* |
* ::: revert :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
* fd | REVERT | | [0..rds): returndata |
* |
* ::: return :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
* 5b | JUMPDEST | 0 rds | [0..rds): returndata |
* f3 | RETURN | | [0..rds): returndata |
* --------------------------------------------------------------------------+
*/
mstore(0x21, 0x5af43d3d93803e602a57fd5bf3)
mstore(0x14, implementation)
mstore(0x00, 0x602c3d8160093d39f33d3d3d3d363d3d37363d73)
instance := create(value, 0x0c, 0x35)
if iszero(instance) {
mstore(0x00, 0x30116425) // `DeploymentFailed()`.
revert(0x1c, 0x04)
}
mstore(0x21, 0) // Restore the overwritten part of the free memory pointer.
}
}
/// @dev Deploys a deterministic clone of `implementation` with `salt`.
function cloneDeterministic(address implementation, bytes32 salt)
internal
returns (address instance)
{
instance = cloneDeterministic(0, implementation, salt);
}
/// @dev Deploys a deterministic clone of `implementation` with `salt`.
/// Deposits `value` ETH during deployment.
function cloneDeterministic(uint256 value, address implementation, bytes32 salt)
internal
returns (address instance)
{
/// @solidity memory-safe-assembly
assembly {
mstore(0x21, 0x5af43d3d93803e602a57fd5bf3)
mstore(0x14, implementation)
mstore(0x00, 0x602c3d8160093d39f33d3d3d3d363d3d37363d73)
instance := create2(value, 0x0c, 0x35, salt)
if iszero(instance) {
mstore(0x00, 0x30116425) // `DeploymentFailed()`.
revert(0x1c, 0x04)
}
mstore(0x21, 0) // Restore the overwritten part of the free memory pointer.
}
}
/// @dev Returns the initialization code of the clone of `implementation`.
function initCode(address implementation) internal pure returns (bytes memory result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
mstore(add(result, 0x40), 0x5af43d3d93803e602a57fd5bf30000000000000000000000)
mstore(add(result, 0x28), implementation)
mstore(add(result, 0x14), 0x602c3d8160093d39f33d3d3d3d363d3d37363d73)
mstore(result, 0x35) // Store the length.
mstore(0x40, add(result, 0x60)) // Allocate memory.
}
}
/// @dev Returns the initialization code hash of the clone of `implementation`.
/// Used for mining vanity addresses with create2crunch.
function initCodeHash(address implementation) internal pure returns (bytes32 hash) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x21, 0x5af43d3d93803e602a57fd5bf3)
mstore(0x14, implementation)
mstore(0x00, 0x602c3d8160093d39f33d3d3d3d363d3d37363d73)
hash := keccak256(0x0c, 0x35)
mstore(0x21, 0) // Restore the overwritten part of the free memory pointer.
}
}
/// @dev Returns the address of the deterministic clone of `implementation`,
/// with `salt` by `deployer`.
/// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly.
function predictDeterministicAddress(address implementation, bytes32 salt, address deployer)
internal
pure
returns (address predicted)
{
bytes32 hash = initCodeHash(implementation);
predicted = predictDeterministicAddress(hash, salt, deployer);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* MINIMAL PROXY OPERATIONS (PUSH0 VARIANT) */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Deploys a PUSH0 clone of `implementation`.
function clone_PUSH0(address implementation) internal returns (address instance) {
instance = clone_PUSH0(0, implementation);
}
/// @dev Deploys a PUSH0 clone of `implementation`.
/// Deposits `value` ETH during deployment.
function clone_PUSH0(uint256 value, address implementation)
internal
returns (address instance)
{
/// @solidity memory-safe-assembly
assembly {
/**
* --------------------------------------------------------------------------+
* CREATION (9 bytes) |
* --------------------------------------------------------------------------|
* Opcode | Mnemonic | Stack | Memory |
* --------------------------------------------------------------------------|
* 60 runSize | PUSH1 runSize | r | |
* 5f | PUSH0 | 0 r | |
* 81 | DUP2 | r 0 r | |
* 60 offset | PUSH1 offset | o r 0 r | |
* 5f | PUSH0 | 0 o r 0 r | |
* 39 | CODECOPY | 0 r | [0..runSize): runtime code |
* f3 | RETURN | | [0..runSize): runtime code |
* --------------------------------------------------------------------------|
* RUNTIME (45 bytes) |
* --------------------------------------------------------------------------|
* Opcode | Mnemonic | Stack | Memory |
* --------------------------------------------------------------------------|
* |
* ::: keep some values in stack ::::::::::::::::::::::::::::::::::::::::::: |
* 5f | PUSH0 | 0 | |
* 5f | PUSH0 | 0 0 | |
* |
* ::: copy calldata to memory ::::::::::::::::::::::::::::::::::::::::::::: |
* 36 | CALLDATASIZE | cds 0 0 | |
* 5f | PUSH0 | 0 cds 0 0 | |
* 5f | PUSH0 | 0 0 cds 0 0 | |
* 37 | CALLDATACOPY | 0 0 | [0..cds): calldata |
* |
* ::: delegate call to the implementation contract :::::::::::::::::::::::: |
* 36 | CALLDATASIZE | cds 0 0 | [0..cds): calldata |
* 5f | PUSH0 | 0 cds 0 0 | [0..cds): calldata |
* 73 addr | PUSH20 addr | addr 0 cds 0 0 | [0..cds): calldata |
* 5a | GAS | gas addr 0 cds 0 0 | [0..cds): calldata |
* f4 | DELEGATECALL | success | [0..cds): calldata |
* |
* ::: copy return data to memory :::::::::::::::::::::::::::::::::::::::::: |
* 3d | RETURNDATASIZE | rds success | [0..cds): calldata |
* 5f | PUSH0 | 0 rds success | [0..cds): calldata |
* 5f | PUSH0 | 0 0 rds success | [0..cds): calldata |
* 3e | RETURNDATACOPY | success | [0..rds): returndata |
* |
* 60 0x29 | PUSH1 0x29 | 0x29 success | [0..rds): returndata |
* 57 | JUMPI | | [0..rds): returndata |
* |
* ::: revert :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
* 3d | RETURNDATASIZE | rds | [0..rds): returndata |
* 5f | PUSH0 | 0 rds | [0..rds): returndata |
* fd | REVERT | | [0..rds): returndata |
* |
* ::: return :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
* 5b | JUMPDEST | | [0..rds): returndata |
* 3d | RETURNDATASIZE | rds | [0..rds): returndata |
* 5f | PUSH0 | 0 rds | [0..rds): returndata |
* f3 | RETURN | | [0..rds): returndata |
* --------------------------------------------------------------------------+
*/
mstore(0x24, 0x5af43d5f5f3e6029573d5ffd5b3d5ff3) // 16
mstore(0x14, implementation) // 20
mstore(0x00, 0x602d5f8160095f39f35f5f365f5f37365f73) // 9 + 9
instance := create(value, 0x0e, 0x36)
if iszero(instance) {
mstore(0x00, 0x30116425) // `DeploymentFailed()`.
revert(0x1c, 0x04)
}
mstore(0x24, 0) // Restore the overwritten part of the free memory pointer.
}
}
/// @dev Deploys a deterministic PUSH0 clone of `implementation` with `salt`.
function cloneDeterministic_PUSH0(address implementation, bytes32 salt)
internal
returns (address instance)
{
instance = cloneDeterministic_PUSH0(0, implementation, salt);
}
/// @dev Deploys a deterministic PUSH0 clone of `implementation` with `salt`.
/// Deposits `value` ETH during deployment.
function cloneDeterministic_PUSH0(uint256 value, address implementation, bytes32 salt)
internal
returns (address instance)
{
/// @solidity memory-safe-assembly
assembly {
mstore(0x24, 0x5af43d5f5f3e6029573d5ffd5b3d5ff3) // 16
mstore(0x14, implementation) // 20
mstore(0x00, 0x602d5f8160095f39f35f5f365f5f37365f73) // 9 + 9
instance := create2(value, 0x0e, 0x36, salt)
if iszero(instance) {
mstore(0x00, 0x30116425) // `DeploymentFailed()`.
revert(0x1c, 0x04)
}
mstore(0x24, 0) // Restore the overwritten part of the free memory pointer.
}
}
/// @dev Returns the initialization code of the PUSH0 clone of `implementation`.
function initCode_PUSH0(address implementation) internal pure returns (bytes memory result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
mstore(add(result, 0x40), 0x5af43d5f5f3e6029573d5ffd5b3d5ff300000000000000000000) // 16
mstore(add(result, 0x26), implementation) // 20
mstore(add(result, 0x12), 0x602d5f8160095f39f35f5f365f5f37365f73) // 9 + 9
mstore(result, 0x36) // Store the length.
mstore(0x40, add(result, 0x60)) // Allocate memory.
}
}
/// @dev Returns the initialization code hash of the PUSH0 clone of `implementation`.
/// Used for mining vanity addresses with create2crunch.
function initCodeHash_PUSH0(address implementation) internal pure returns (bytes32 hash) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x24, 0x5af43d5f5f3e6029573d5ffd5b3d5ff3) // 16
mstore(0x14, implementation) // 20
mstore(0x00, 0x602d5f8160095f39f35f5f365f5f37365f73) // 9 + 9
hash := keccak256(0x0e, 0x36)
mstore(0x24, 0) // Restore the overwritten part of the free memory pointer.
}
}
/// @dev Returns the address of the deterministic PUSH0 clone of `implementation`,
/// with `salt` by `deployer`.
/// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly.
function predictDeterministicAddress_PUSH0(
address implementation,
bytes32 salt,
address deployer
) internal pure returns (address predicted) {
bytes32 hash = initCodeHash_PUSH0(implementation);
predicted = predictDeterministicAddress(hash, salt, deployer);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CLONES WITH IMMUTABLE ARGS OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
// Note: This implementation of CWIA differs from the original implementation.
// If the calldata is empty, it will emit a `ReceiveETH(uint256)` event and skip the `DELEGATECALL`.
/// @dev Deploys a clone of `implementation` with immutable arguments encoded in `data`.
function clone(address implementation, bytes memory data) internal returns (address instance) {
instance = clone(0, implementation, data);
}
/// @dev Deploys a clone of `implementation` with immutable arguments encoded in `data`.
/// Deposits `value` ETH during deployment.
function clone(uint256 value, address implementation, bytes memory data)
internal
returns (address instance)
{
assembly {
// Compute the boundaries of the data and cache the memory slots around it.
let mBefore3 := mload(sub(data, 0x60))
let mBefore2 := mload(sub(data, 0x40))
let mBefore1 := mload(sub(data, 0x20))
let dataLength := mload(data)
let dataEnd := add(add(data, 0x20), dataLength)
let mAfter1 := mload(dataEnd)
// +2 bytes for telling how much data there is appended to the call.
let extraLength := add(dataLength, 2)
// The `creationSize` is `extraLength + 108`
// The `runSize` is `creationSize - 10`.
/**
* ---------------------------------------------------------------------------------------------------+
* CREATION (10 bytes) |
* ---------------------------------------------------------------------------------------------------|
* Opcode | Mnemonic | Stack | Memory |
* ---------------------------------------------------------------------------------------------------|
* 61 runSize | PUSH2 runSize | r | |
* 3d | RETURNDATASIZE | 0 r | |
* 81 | DUP2 | r 0 r | |
* 60 offset | PUSH1 offset | o r 0 r | |
* 3d | RETURNDATASIZE | 0 o r 0 r | |
* 39 | CODECOPY | 0 r | [0..runSize): runtime code |
* f3 | RETURN | | [0..runSize): runtime code |
* ---------------------------------------------------------------------------------------------------|
* RUNTIME (98 bytes + extraLength) |
* ---------------------------------------------------------------------------------------------------|
* Opcode | Mnemonic | Stack | Memory |
* ---------------------------------------------------------------------------------------------------|
* |
* ::: if no calldata, emit event & return w/o `DELEGATECALL` ::::::::::::::::::::::::::::::::::::::: |
* 36 | CALLDATASIZE | cds | |
* 60 0x2c | PUSH1 0x2c | 0x2c cds | |
* 57 | JUMPI | | |
* 34 | CALLVALUE | cv | |
* 3d | RETURNDATASIZE | 0 cv | |
* 52 | MSTORE | | [0..0x20): callvalue |
* 7f sig | PUSH32 0x9e.. | sig | [0..0x20): callvalue |
* 59 | MSIZE | 0x20 sig | [0..0x20): callvalue |
* 3d | RETURNDATASIZE | 0 0x20 sig | [0..0x20): callvalue |
* a1 | LOG1 | | [0..0x20): callvalue |
* 00 | STOP | | [0..0x20): callvalue |
* 5b | JUMPDEST | | |
* |
* ::: copy calldata to memory :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
* 36 | CALLDATASIZE | cds | |
* 3d | RETURNDATASIZE | 0 cds | |
* 3d | RETURNDATASIZE | 0 0 cds | |
* 37 | CALLDATACOPY | | [0..cds): calldata |
* |
* ::: keep some values in stack :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
* 3d | RETURNDATASIZE | 0 | [0..cds): calldata |
* 3d | RETURNDATASIZE | 0 0 | [0..cds): calldata |
* 3d | RETURNDATASIZE | 0 0 0 | [0..cds): calldata |
* 3d | RETURNDATASIZE | 0 0 0 0 | [0..cds): calldata |
* 61 extra | PUSH2 extra | e 0 0 0 0 | [0..cds): calldata |
* |
* ::: copy extra data to memory :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
* 80 | DUP1 | e e 0 0 0 0 | [0..cds): calldata |
* 60 0x62 | PUSH1 0x62 | 0x62 e e 0 0 0 0 | [0..cds): calldata |
* 36 | CALLDATASIZE | cds 0x62 e e 0 0 0 0 | [0..cds): calldata |
* 39 | CODECOPY | e 0 0 0 0 | [0..cds): calldata, [cds..cds+e): extraData |
* |
* ::: delegate call to the implementation contract ::::::::::::::::::::::::::::::::::::::::::::::::: |
* 36 | CALLDATASIZE | cds e 0 0 0 0 | [0..cds): calldata, [cds..cds+e): extraData |
* 01 | ADD | cds+e 0 0 0 0 | [0..cds): calldata, [cds..cds+e): extraData |
* 3d | RETURNDATASIZE | 0 cds+e 0 0 0 0 | [0..cds): calldata, [cds..cds+e): extraData |
* 73 addr | PUSH20 addr | addr 0 cds+e 0 0 0 0 | [0..cds): calldata, [cds..cds+e): extraData |
* 5a | GAS | gas addr 0 cds+e 0 0 0 0 | [0..cds): calldata, [cds..cds+e): extraData |
* f4 | DELEGATECALL | success 0 0 | [0..cds): calldata, [cds..cds+e): extraData |
* |
* ::: copy return data to memory ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
* 3d | RETURNDATASIZE | rds success 0 0 | [0..cds): calldata, [cds..cds+e): extraData |
* 3d | RETURNDATASIZE | rds rds success 0 0 | [0..cds): calldata, [cds..cds+e): extraData |
* 93 | SWAP4 | 0 rds success 0 rds | [0..cds): calldata, [cds..cds+e): extraData |
* 80 | DUP1 | 0 0 rds success 0 rds | [0..cds): calldata, [cds..cds+e): extraData |
* 3e | RETURNDATACOPY | success 0 rds | [0..rds): returndata |
* |
* 60 0x60 | PUSH1 0x60 | 0x60 success 0 rds | [0..rds): returndata |
* 57 | JUMPI | 0 rds | [0..rds): returndata |
* |
* ::: revert ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
* fd | REVERT | | [0..rds): returndata |
* |
* ::: return ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
* 5b | JUMPDEST | 0 rds | [0..rds): returndata |
* f3 | RETURN | | [0..rds): returndata |
* ---------------------------------------------------------------------------------------------------+
*/
mstore(data, 0x5af43d3d93803e606057fd5bf3) // Write the bytecode before the data.
mstore(sub(data, 0x0d), implementation) // Write the address of the implementation.
// Write the rest of the bytecode.
mstore(
sub(data, 0x21),
or(shl(0x48, extraLength), 0x593da1005b363d3d373d3d3d3d610000806062363936013d73)
)
// `keccak256("ReceiveETH(uint256)")`
mstore(
sub(data, 0x3a), 0x9e4ac34f21c619cefc926c8bd93b54bf5a39c7ab2127a895af1cc0691d7e3dff
)
mstore(
// Do a out-of-gas revert if `extraLength` is too big. 0xffff - 0x62 + 0x01 = 0xff9e.
// The actual EVM limit may be smaller and may change over time.
sub(data, add(0x59, lt(extraLength, 0xff9e))),
or(shl(0x78, add(extraLength, 0x62)), 0xfd6100003d81600a3d39f336602c57343d527f)
)
mstore(dataEnd, shl(0xf0, extraLength))
instance := create(value, sub(data, 0x4c), add(extraLength, 0x6c))
if iszero(instance) {
mstore(0x00, 0x30116425) // `DeploymentFailed()`.
revert(0x1c, 0x04)
}
// Restore the overwritten memory surrounding `data`.
mstore(dataEnd, mAfter1)
mstore(data, dataLength)
mstore(sub(data, 0x20), mBefore1)
mstore(sub(data, 0x40), mBefore2)
mstore(sub(data, 0x60), mBefore3)
}
}
/// @dev Deploys a deterministic clone of `implementation`
/// with immutable arguments encoded in `data` and `salt`.
function cloneDeterministic(address implementation, bytes memory data, bytes32 salt)
internal
returns (address instance)
{
instance = cloneDeterministic(0, implementation, data, salt);
}
/// @dev Deploys a deterministic clone of `implementation`
/// with immutable arguments encoded in `data` and `salt`.
function cloneDeterministic(
uint256 value,
address implementation,
bytes memory data,
bytes32 salt
) internal returns (address instance) {
assembly {
// Compute the boundaries of the data and cache the memory slots around it.
let mBefore3 := mload(sub(data, 0x60))
let mBefore2 := mload(sub(data, 0x40))
let mBefore1 := mload(sub(data, 0x20))
let dataLength := mload(data)
let dataEnd := add(add(data, 0x20), dataLength)
let mAfter1 := mload(dataEnd)
// +2 bytes for telling how much data there is appended to the call.
let extraLength := add(dataLength, 2)
mstore(data, 0x5af43d3d93803e606057fd5bf3) // Write the bytecode before the data.
mstore(sub(data, 0x0d), implementation) // Write the address of the implementation.
// Write the rest of the bytecode.
mstore(
sub(data, 0x21),
or(shl(0x48, extraLength), 0x593da1005b363d3d373d3d3d3d610000806062363936013d73)
)
// `keccak256("ReceiveETH(uint256)")`
mstore(
sub(data, 0x3a), 0x9e4ac34f21c619cefc926c8bd93b54bf5a39c7ab2127a895af1cc0691d7e3dff
)
mstore(
// Do a out-of-gas revert if `extraLength` is too big. 0xffff - 0x62 + 0x01 = 0xff9e.
// The actual EVM limit may be smaller and may change over time.
sub(data, add(0x59, lt(extraLength, 0xff9e))),
or(shl(0x78, add(extraLength, 0x62)), 0xfd6100003d81600a3d39f336602c57343d527f)
)
mstore(dataEnd, shl(0xf0, extraLength))
instance := create2(value, sub(data, 0x4c), add(extraLength, 0x6c), salt)
if iszero(instance) {
mstore(0x00, 0x30116425) // `DeploymentFailed()`.
revert(0x1c, 0x04)
}
// Restore the overwritten memory surrounding `data`.
mstore(dataEnd, mAfter1)
mstore(data, dataLength)
mstore(sub(data, 0x20), mBefore1)
mstore(sub(data, 0x40), mBefore2)
mstore(sub(data, 0x60), mBefore3)
}
}
/// @dev Returns the initialization code hash of the clone of `implementation`
/// using immutable arguments encoded in `data`.
function initCode(address implementation, bytes memory data)
internal
pure
returns (bytes memory result)
{
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
let dataLength := mload(data)
// Do a out-of-gas revert if `dataLength` is too big. 0xffff - 0x02 - 0x62 = 0xff9b.
// The actual EVM limit may be smaller and may change over time.
returndatacopy(returndatasize(), returndatasize(), gt(dataLength, 0xff9b))
let o := add(result, 0x8c)
let end := add(o, dataLength)
// Copy the `data` into `result`.
for { let d := sub(add(data, 0x20), o) } 1 {} {
mstore(o, mload(add(o, d)))
o := add(o, 0x20)
if iszero(lt(o, end)) { break }
}
// +2 bytes for telling how much data there is appended to the call.
let extraLength := add(dataLength, 2)
mstore(add(result, 0x6c), 0x5af43d3d93803e606057fd5bf3) // Write the bytecode before the data.
mstore(add(result, 0x5f), implementation) // Write the address of the implementation.
// Write the rest of the bytecode.
mstore(
add(result, 0x4b),
or(shl(0x48, extraLength), 0x593da1005b363d3d373d3d3d3d610000806062363936013d73)
)
// `keccak256("ReceiveETH(uint256)")`
mstore(
add(result, 0x32),
0x9e4ac34f21c619cefc926c8bd93b54bf5a39c7ab2127a895af1cc0691d7e3dff
)
mstore(
add(result, 0x12),
or(shl(0x78, add(extraLength, 0x62)), 0x6100003d81600a3d39f336602c57343d527f)
)
mstore(end, shl(0xf0, extraLength))
mstore(add(end, 0x02), 0) // Zeroize the slot after the result.
mstore(result, add(extraLength, 0x6c)) // Store the length.
mstore(0x40, add(0x22, end)) // Allocate memory.
}
}
/// @dev Returns the initialization code hash of the clone of `implementation`
/// using immutable arguments encoded in `data`.
/// Used for mining vanity addresses with create2crunch.
function initCodeHash(address implementation, bytes memory data)
internal
pure
returns (bytes32 hash)
{
assembly {
// Compute the boundaries of the data and cache the memory slots around it.
let mBefore3 := mload(sub(data, 0x60))
let mBefore2 := mload(sub(data, 0x40))
let mBefore1 := mload(sub(data, 0x20))
let dataLength := mload(data)
let dataEnd := add(add(data, 0x20), dataLength)
let mAfter1 := mload(dataEnd)
// Do a out-of-gas revert if `dataLength` is too big. 0xffff - 0x02 - 0x62 = 0xff9b.
// The actual EVM limit may be smaller and may change over time.
returndatacopy(returndatasize(), returndatasize(), gt(dataLength, 0xff9b))
// +2 bytes for telling how much data there is appended to the call.
let extraLength := add(dataLength, 2)
mstore(data, 0x5af43d3d93803e606057fd5bf3) // Write the bytecode before the data.
mstore(sub(data, 0x0d), implementation) // Write the address of the implementation.
// Write the rest of the bytecode.
mstore(
sub(data, 0x21),
or(shl(0x48, extraLength), 0x593da1005b363d3d373d3d3d3d610000806062363936013d73)
)
// `keccak256("ReceiveETH(uint256)")`
mstore(
sub(data, 0x3a), 0x9e4ac34f21c619cefc926c8bd93b54bf5a39c7ab2127a895af1cc0691d7e3dff
)
mstore(
sub(data, 0x5a),
or(shl(0x78, add(extraLength, 0x62)), 0x6100003d81600a3d39f336602c57343d527f)
)
mstore(dataEnd, shl(0xf0, extraLength))
hash := keccak256(sub(data, 0x4c), add(extraLength, 0x6c))
// Restore the overwritten memory surrounding `data`.
mstore(dataEnd, mAfter1)
mstore(data, dataLength)
mstore(sub(data, 0x20), mBefore1)
mstore(sub(data, 0x40), mBefore2)
mstore(sub(data, 0x60), mBefore3)
}
}
/// @dev Returns the address of the deterministic clone of
/// `implementation` using immutable arguments encoded in `data`, with `salt`, by `deployer`.
/// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly.
function predictDeterministicAddress(
address implementation,
bytes memory data,
bytes32 salt,
address deployer
) internal pure returns (address predicted) {
bytes32 hash = initCodeHash(implementation, data);
predicted = predictDeterministicAddress(hash, salt, deployer);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* MINIMAL ERC1967 PROXY OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
// Note: The ERC1967 proxy here is intended to be upgraded with UUPS.
// This is NOT the same as ERC1967Factory's transparent proxy, which includes admin logic.
/// @dev Deploys a minimal ERC1967 proxy with `implementation`.
function deployERC1967(address implementation) internal returns (address instance) {
instance = deployERC1967(0, implementation);
}
/// @dev Deploys a minimal ERC1967 proxy with `implementation`.
/// Deposits `value` ETH during deployment.
function deployERC1967(uint256 value, address implementation)
internal
returns (address instance)
{
/// @solidity memory-safe-assembly
assembly {
/**
* ---------------------------------------------------------------------------------+
* CREATION (34 bytes) |
* ---------------------------------------------------------------------------------|
* Opcode | Mnemonic | Stack | Memory |
* ---------------------------------------------------------------------------------|
* 60 runSize | PUSH1 runSize | r | |
* 3d | RETURNDATASIZE | 0 r | |
* 81 | DUP2 | r 0 r | |
* 60 offset | PUSH1 offset | o r 0 r | |
* 3d | RETURNDATASIZE | 0 o r 0 r | |
* 39 | CODECOPY | 0 r | [0..runSize): runtime code |
* 73 impl | PUSH20 impl | impl 0 r | [0..runSize): runtime code |
* 60 slotPos | PUSH1 slotPos | slotPos impl 0 r | [0..runSize): runtime code |
* 51 | MLOAD | slot impl 0 r | [0..runSize): runtime code |
* 55 | SSTORE | 0 r | [0..runSize): runtime code |
* f3 | RETURN | | [0..runSize): runtime code |
* ---------------------------------------------------------------------------------|
* RUNTIME (61 bytes) |
* ---------------------------------------------------------------------------------|
* Opcode | Mnemonic | Stack | Memory |
* ---------------------------------------------------------------------------------|
* |
* ::: copy calldata to memory :::::::::::::::::::::::::::::::::::::::::::::::::::: |
* 36 | CALLDATASIZE | cds | |
* 3d | RETURNDATASIZE | 0 cds | |
* 3d | RETURNDATASIZE | 0 0 cds | |
* 37 | CALLDATACOPY | | [0..calldatasize): calldata |
* |
* ::: delegatecall to implementation ::::::::::::::::::::::::::::::::::::::::::::: |
* 3d | RETURNDATASIZE | 0 | |
* 3d | RETURNDATASIZE | 0 0 | |
* 36 | CALLDATASIZE | cds 0 0 | [0..calldatasize): calldata |
* 3d | RETURNDATASIZE | 0 cds 0 0 | [0..calldatasize): calldata |
* 7f slot | PUSH32 slot | s 0 cds 0 0 | [0..calldatasize): calldata |
* 54 | SLOAD | i 0 cds 0 0 | [0..calldatasize): calldata |
* 5a | GAS | g i 0 cds 0 0 | [0..calldatasize): calldata |
* f4 | DELEGATECALL | succ | [0..calldatasize): calldata |
* |
* ::: copy returndata to memory :::::::::::::::::::::::::::::::::::::::::::::::::: |
* 3d | RETURNDATASIZE | rds succ | [0..calldatasize): calldata |
* 60 0x00 | PUSH1 0x00 | 0 rds succ | [0..calldatasize): calldata |
* 80 | DUP1 | 0 0 rds succ | [0..calldatasize): calldata |
* 3e | RETURNDATACOPY | succ | [0..returndatasize): returndata |
* |
* ::: branch on delegatecall status :::::::::::::::::::::::::::::::::::::::::::::: |
* 60 0x38 | PUSH1 0x38 | dest succ | [0..returndatasize): returndata |
* 57 | JUMPI | | [0..returndatasize): returndata |
* |
* ::: delegatecall failed, revert :::::::::::::::::::::::::::::::::::::::::::::::: |
* 3d | RETURNDATASIZE | rds | [0..returndatasize): returndata |
* 60 0x00 | PUSH1 0x00 | 0 rds | [0..returndatasize): returndata |
* fd | REVERT | | [0..returndatasize): returndata |
* |
* ::: delegatecall succeeded, return ::::::::::::::::::::::::::::::::::::::::::::: |
* 5b | JUMPDEST | | [0..returndatasize): returndata |
* 3d | RETURNDATASIZE | rds | [0..returndatasize): returndata |
* 60 0x00 | PUSH1 0x00 | 0 rds | [0..returndatasize): returndata |
* f3 | RETURN | | [0..returndatasize): returndata |
* ---------------------------------------------------------------------------------+
*/
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x60, 0xcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f3)
mstore(0x40, 0x5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e2076)
mstore(0x20, 0x6009)
mstore(0x1e, implementation)
mstore(0x0a, 0x603d3d8160223d3973)
instance := create(value, 0x21, 0x5f)
if iszero(instance) {
mstore(0x00, 0x30116425) // `DeploymentFailed()`.
revert(0x1c, 0x04)
}
mstore(0x40, m) // Restore the free memory pointer.
mstore(0x60, 0) // Restore the zero slot.
}
}
/// @dev Deploys a deterministic minimal ERC1967 proxy with `implementation` and `salt`.
function deployDeterministicERC1967(address implementation, bytes32 salt)
internal
returns (address instance)
{
instance = deployDeterministicERC1967(0, implementation, salt);
}
/// @dev Deploys a deterministic minimal ERC1967 proxy with `implementation` and `salt`.
/// Deposits `value` ETH during deployment.
function deployDeterministicERC1967(uint256 value, address implementation, bytes32 salt)
internal
returns (address instance)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x60, 0xcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f3)
mstore(0x40, 0x5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e2076)
mstore(0x20, 0x6009)
mstore(0x1e, implementation)
mstore(0x0a, 0x603d3d8160223d3973)
instance := create2(value, 0x21, 0x5f, salt)
if iszero(instance) {
mstore(0x00, 0x30116425) // `DeploymentFailed()`.
revert(0x1c, 0x04)
}
mstore(0x40, m) // Restore the free memory pointer.
mstore(0x60, 0) // Restore the zero slot.
}
}
/// @dev Creates a deterministic minimal ERC1967 proxy with `implementation` and `salt`.
/// Note: This method is intended for use in ERC4337 factories,
/// which are expected to NOT revert if the proxy is already deployed.
function createDeterministicERC1967(address implementation, bytes32 salt)
internal
returns (bool alreadyDeployed, address instance)
{
return createDeterministicERC1967(0, implementation, salt);
}
/// @dev Creates a deterministic minimal ERC1967 proxy with `implementation` and `salt`.
/// Deposits `value` ETH during deployment.
/// Note: This method is intended for use in ERC4337 factories,
/// which are expected to NOT revert if the proxy is already deployed.
function createDeterministicERC1967(uint256 value, address implementation, bytes32 salt)
internal
returns (bool alreadyDeployed, address instance)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x60, 0xcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f3)
mstore(0x40, 0x5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e2076)
mstore(0x20, 0x6009)
mstore(0x1e, implementation)
mstore(0x0a, 0x603d3d8160223d3973)
// Compute and store the bytecode hash.
mstore(add(m, 0x35), keccak256(0x21, 0x5f))
mstore(m, shl(88, address()))
mstore8(m, 0xff) // Write the prefix.
mstore(add(m, 0x15), salt)
instance := keccak256(m, 0x55)
for {} 1 {} {
if iszero(extcodesize(instance)) {
instance := create2(value, 0x21, 0x5f, salt)
if iszero(instance) {
mstore(0x00, 0x30116425) // `DeploymentFailed()`.
revert(0x1c, 0x04)
}
break
}
alreadyDeployed := 1
if iszero(value) { break }
if iszero(call(gas(), instance, value, codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
revert(0x1c, 0x04)
}
break
}
mstore(0x40, m) // Restore the free memory pointer.
mstore(0x60, 0) // Restore the zero slot.
}
}
/// @dev Returns the initialization code of the minimal ERC1967 proxy of `implementation`.
function initCodeERC1967(address implementation) internal pure returns (bytes memory result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
mstore(
add(result, 0x60),
0x3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f300
)
mstore(
add(result, 0x40),
0x55f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e2076cc
)
mstore(add(result, 0x20), or(shl(24, implementation), 0x600951))
mstore(add(result, 0x09), 0x603d3d8160223d3973)
mstore(result, 0x5f) // Store the length.
mstore(0x40, add(result, 0x80)) // Allocate memory.
}
}
/// @dev Returns the initialization code hash of the minimal ERC1967 proxy of `implementation`.
/// Used for mining vanity addresses with create2crunch.
function initCodeHashERC1967(address implementation) internal pure returns (bytes32 hash) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x60, 0xcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f3)
mstore(0x40, 0x5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e2076)
mstore(0x20, 0x6009)
mstore(0x1e, implementation)
mstore(0x0a, 0x603d3d8160223d3973)
hash := keccak256(0x21, 0x5f)
mstore(0x40, m) // Restore the free memory pointer.
mstore(0x60, 0) // Restore the zero slot.
}
}
/// @dev Returns the address of the deterministic ERC1967 proxy of `implementation`,
/// with `salt` by `deployer`.
/// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly.
function predictDeterministicAddressERC1967(
address implementation,
bytes32 salt,
address deployer
) internal pure returns (address predicted) {
bytes32 hash = initCodeHashERC1967(implementation);
predicted = predictDeterministicAddress(hash, salt, deployer);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ERC1967I PROXY OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
// Note: This proxy has a special code path that activates if `calldatasize() == 1`.
// This code path skips the delegatecall and directly returns the `implementation` address.
// The returned implementation is guaranteed to be valid if the keccak256 of the
// proxy's code is equal to `ERC1967I_CODE_HASH`.
/// @dev Deploys a minimal ERC1967I proxy with `implementation`.
function deployERC1967I(address implementation) internal returns (address instance) {
instance = deployERC1967I(0, implementation);
}
/// @dev Deploys a ERC1967I proxy with `implementation`.
/// Deposits `value` ETH during deployment.
function deployERC1967I(uint256 value, address implementation)
internal
returns (address instance)
{
/// @solidity memory-safe-assembly
assembly {
/**
* ---------------------------------------------------------------------------------+
* CREATION (34 bytes) |
* ---------------------------------------------------------------------------------|
* Opcode | Mnemonic | Stack | Memory |
* ---------------------------------------------------------------------------------|
* 60 runSize | PUSH1 runSize | r | |
* 3d | RETURNDATASIZE | 0 r | |
* 81 | DUP2 | r 0 r | |
* 60 offset | PUSH1 offset | o r 0 r | |
* 3d | RETURNDATASIZE | 0 o r 0 r | |
* 39 | CODECOPY | 0 r | [0..runSize): runtime code |
* 73 impl | PUSH20 impl | impl 0 r | [0..runSize): runtime code |
* 60 slotPos | PUSH1 slotPos | slotPos impl 0 r | [0..runSize): runtime code |
* 51 | MLOAD | slot impl 0 r | [0..runSize): runtime code |
* 55 | SSTORE | 0 r | [0..runSize): runtime code |
* f3 | RETURN | | [0..runSize): runtime code |
* ---------------------------------------------------------------------------------|
* RUNTIME (82 bytes) |
* ---------------------------------------------------------------------------------|
* Opcode | Mnemonic | Stack | Memory |
* ---------------------------------------------------------------------------------|
* |
* ::: check calldatasize ::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
* 36 | CALLDATASIZE | cds | |
* 58 | PC | 1 cds | |
* 14 | EQ | eqs | |
* 60 0x43 | PUSH1 0x43 | dest eqs | |
* 57 | JUMPI | | |
* |
* ::: copy calldata to memory :::::::::::::::::::::::::::::::::::::::::::::::::::: |
* 36 | CALLDATASIZE | cds | |
* 3d | RETURNDATASIZE | 0 cds | |
* 3d | RETURNDATASIZE | 0 0 cds | |
* 37 | CALLDATACOPY | | [0..calldatasize): calldata |
* |
* ::: delegatecall to implementation ::::::::::::::::::::::::::::::::::::::::::::: |
* 3d | RETURNDATASIZE | 0 | |
* 3d | RETURNDATASIZE | 0 0 | |
* 36 | CALLDATASIZE | cds 0 0 | [0..calldatasize): calldata |
* 3d | RETURNDATASIZE | 0 cds 0 0 | [0..calldatasize): calldata |
* 7f slot | PUSH32 slot | s 0 cds 0 0 | [0..calldatasize): calldata |
* 54 | SLOAD | i 0 cds 0 0 | [0..calldatasize): calldata |
* 5a | GAS | g i 0 cds 0 0 | [0..calldatasize): calldata |
* f4 | DELEGATECALL | succ | [0..calldatasize): calldata |
* |
* ::: copy returndata to memory :::::::::::::::::::::::::::::::::::::::::::::::::: |
* 3d | RETURNDATASIZE | rds succ | [0..calldatasize): calldata |
* 60 0x00 | PUSH1 0x00 | 0 rds succ | [0..calldatasize): calldata |
* 80 | DUP1 | 0 0 rds succ | [0..calldatasize): calldata |
* 3e | RETURNDATACOPY | succ | [0..returndatasize): returndata |
* |
* ::: branch on delegatecall status :::::::::::::::::::::::::::::::::::::::::::::: |
* 60 0x3E | PUSH1 0x3E | dest succ | [0..returndatasize): returndata |
* 57 | JUMPI | | [0..returndatasize): returndata |
* |
* ::: delegatecall failed, revert :::::::::::::::::::::::::::::::::::::::::::::::: |
* 3d | RETURNDATASIZE | rds | [0..returndatasize): returndata |
* 60 0x00 | PUSH1 0x00 | 0 rds | [0..returndatasize): returndata |
* fd | REVERT | | [0..returndatasize): returndata |
* |
* ::: delegatecall succeeded, return ::::::::::::::::::::::::::::::::::::::::::::: |
* 5b | JUMPDEST | | [0..returndatasize): returndata |
* 3d | RETURNDATASIZE | rds | [0..returndatasize): returndata |
* 60 0x00 | PUSH1 0x00 | 0 rds | [0..returndatasize): returndata |
* f3 | RETURN | | [0..returndatasize): returndata |
* |
* ::: implementation , return :::::::::::::::::::::::::::::::::::::::::::::::::::: |
* 5b | JUMPDEST | | |
* 60 0x20 | PUSH1 0x20 | 32 | |
* 60 0x0F | PUSH1 0x0F | o 32 | |
* 3d | RETURNDATASIZE | 0 o 32 | |
* 39 | CODECOPY | | [0..32): implementation slot |
* 3d | RETURNDATASIZE | 0 | [0..32): implementation slot |
* 51 | MLOAD | slot | [0..32): implementation slot |
* 54 | SLOAD | impl | [0..32): implementation slot |
* 3d | RETURNDATASIZE | 0 impl | [0..32): implementation slot |
* 52 | MSTORE | | [0..32): implementation address |
* 59 | MSIZE | 32 | [0..32): implementation address |
* 3d | RETURNDATASIZE | 0 32 | [0..32): implementation address |
* f3 | RETURN | | [0..32): implementation address |
* |
* ---------------------------------------------------------------------------------+
*/
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x60, 0x3d6000803e603e573d6000fd5b3d6000f35b6020600f3d393d51543d52593df3)
mstore(0x40, 0xa13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545af4)
mstore(0x20, 0x600f5155f3365814604357363d3d373d3d363d7f360894)
mstore(0x09, or(shl(160, 0x60523d8160223d3973), shr(96, shl(96, implementation))))
instance := create(value, 0x0c, 0x74)
if iszero(instance) {
mstore(0x00, 0x30116425) // `DeploymentFailed()`.
revert(0x1c, 0x04)
}
mstore(0x40, m) // Restore the free memory pointer.
mstore(0x60, 0) // Restore the zero slot.
}
}
/// @dev Deploys a deterministic ERC1967I proxy with `implementation` and `salt`.
function deployDeterministicERC1967I(address implementation, bytes32 salt)
internal
returns (address instance)
{
instance = deployDeterministicERC1967I(0, implementation, salt);
}
/// @dev Deploys a deterministic ERC1967I proxy with `implementation` and `salt`.
/// Deposits `value` ETH during deployment.
function deployDeterministicERC1967I(uint256 value, address implementation, bytes32 salt)
internal
returns (address instance)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x60, 0x3d6000803e603e573d6000fd5b3d6000f35b6020600f3d393d51543d52593df3)
mstore(0x40, 0xa13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545af4)
mstore(0x20, 0x600f5155f3365814604357363d3d373d3d363d7f360894)
mstore(0x09, or(shl(160, 0x60523d8160223d3973), shr(96, shl(96, implementation))))
instance := create2(value, 0x0c, 0x74, salt)
if iszero(instance) {
mstore(0x00, 0x30116425) // `DeploymentFailed()`.
revert(0x1c, 0x04)
}
mstore(0x40, m) // Restore the free memory pointer.
mstore(0x60, 0) // Restore the zero slot.
}
}
/// @dev Creates a deterministic ERC1967I proxy with `implementation` and `salt`.
/// Note: This method is intended for use in ERC4337 factories,
/// which are expected to NOT revert if the proxy is already deployed.
function createDeterministicERC1967I(address implementation, bytes32 salt)
internal
returns (bool alreadyDeployed, address instance)
{
return createDeterministicERC1967I(0, implementation, salt);
}
/// @dev Creates a deterministic ERC1967I proxy with `implementation` and `salt`.
/// Deposits `value` ETH during deployment.
/// Note: This method is intended for use in ERC4337 factories,
/// which are expected to NOT revert if the proxy is already deployed.
function createDeterministicERC1967I(uint256 value, address implementation, bytes32 salt)
internal
returns (bool alreadyDeployed, address instance)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x60, 0x3d6000803e603e573d6000fd5b3d6000f35b6020600f3d393d51543d52593df3)
mstore(0x40, 0xa13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545af4)
mstore(0x20, 0x600f5155f3365814604357363d3d373d3d363d7f360894)
mstore(0x09, or(shl(160, 0x60523d8160223d3973), shr(96, shl(96, implementation))))
// Compute and store the bytecode hash.
mstore(add(m, 0x35), keccak256(0x0c, 0x74))
mstore(m, shl(88, address()))
mstore8(m, 0xff) // Write the prefix.
mstore(add(m, 0x15), salt)
instance := keccak256(m, 0x55)
for {} 1 {} {
if iszero(extcodesize(instance)) {
instance := create2(value, 0x0c, 0x74, salt)
if iszero(instance) {
mstore(0x00, 0x30116425) // `DeploymentFailed()`.
revert(0x1c, 0x04)
}
break
}
alreadyDeployed := 1
if iszero(value) { break }
if iszero(call(gas(), instance, value, codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
revert(0x1c, 0x04)
}
break
}
mstore(0x40, m) // Restore the free memory pointer.
mstore(0x60, 0) // Restore the zero slot.
}
}
/// @dev Returns the initialization code of the minimal ERC1967 proxy of `implementation`.
function initCodeERC1967I(address implementation) internal pure returns (bytes memory result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
mstore(
add(result, 0x74),
0x3d6000803e603e573d6000fd5b3d6000f35b6020600f3d393d51543d52593df3
)
mstore(
add(result, 0x54),
0xa13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545af4
)
mstore(add(result, 0x34), 0x600f5155f3365814604357363d3d373d3d363d7f360894)
mstore(add(result, 0x1d), implementation)
mstore(add(result, 0x09), 0x60523d8160223d3973)
mstore(add(result, 0x94), 0)
mstore(result, 0x74) // Store the length.
mstore(0x40, add(result, 0xa0)) // Allocate memory.
}
}
/// @dev Returns the initialization code hash of the minimal ERC1967 proxy of `implementation`.
/// Used for mining vanity addresses with create2crunch.
function initCodeHashERC1967I(address implementation) internal pure returns (bytes32 hash) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x60, 0x3d6000803e603e573d6000fd5b3d6000f35b6020600f3d393d51543d52593df3)
mstore(0x40, 0xa13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545af4)
mstore(0x20, 0x600f5155f3365814604357363d3d373d3d363d7f360894)
mstore(0x09, or(shl(160, 0x60523d8160223d3973), shr(96, shl(96, implementation))))
hash := keccak256(0x0c, 0x74)
mstore(0x40, m) // Restore the free memory pointer.
mstore(0x60, 0) // Restore the zero slot.
}
}
/// @dev Returns the address of the deterministic ERC1967I proxy of `implementation`,
/// with `salt` by `deployer`.
/// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly.
function predictDeterministicAddressERC1967I(
address implementation,
bytes32 salt,
address deployer
) internal pure returns (address predicted) {
bytes32 hash = initCodeHashERC1967I(implementation);
predicted = predictDeterministicAddress(hash, salt, deployer);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* OTHER OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the address when a contract with initialization code hash,
/// `hash`, is deployed with `salt`, by `deployer`.
/// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly.
function predictDeterministicAddress(bytes32 hash, bytes32 salt, address deployer)
internal
pure
returns (address predicted)
{
/// @solidity memory-safe-assembly
assembly {
// Compute and store the bytecode hash.
mstore8(0x00, 0xff) // Write the prefix.
mstore(0x35, hash)
mstore(0x01, shl(96, deployer))
mstore(0x15, salt)
predicted := keccak256(0x00, 0x55)
mstore(0x35, 0) // Restore the overwritten part of the free memory pointer.
}
}
/// @dev Requires that `salt` starts with either the zero address or `by`.
function checkStartsWith(bytes32 salt, address by) internal pure {
/// @solidity memory-safe-assembly
assembly {
// If the salt does not start with the zero address or `by`.
if iszero(or(iszero(shr(96, salt)), eq(shr(96, shl(96, by)), shr(96, salt)))) {
mstore(0x00, 0x0c4549ef) // `SaltDoesNotStartWith()`.
revert(0x1c, 0x04)
}
}
}
}{
"remappings": [
"forge-std/=lib/forge-std/src/",
"ds-test/=lib/forge-std/lib/ds-test/src/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"solmate/=lib/solmate/src/",
"GeneralisedIncentives/=lib/GeneralisedIncentives/",
"@lazyledger/protobuf3-solidity-lib/=lib/GeneralisedIncentives/lib/vibc-core-smart-contracts/lib/protobuf3-solidity-lib/",
"@openzeppelin-upgradeable/=lib/GeneralisedIncentives/lib/vibc-core-smart-contracts/lib/openzeppelin-contracts-upgradeable/",
"@openzeppelin/=lib/GeneralisedIncentives/lib/vibc-core-smart-contracts/lib/openzeppelin-contracts/",
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"base64/=lib/GeneralisedIncentives/lib/vibc-core-smart-contracts/lib/base64/",
"clones-with-immutable-args/=lib/GeneralisedIncentives/lib/vibc-core-smart-contracts/lib/optimism/packages/contracts-bedrock/lib/clones-with-immutable-args/src/",
"erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
"openzeppelin-contracts-upgradeable/=lib/GeneralisedIncentives/lib/vibc-core-smart-contracts/lib/openzeppelin-contracts-upgradeable/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"openzeppelin/=lib/GeneralisedIncentives/lib/openzeppelin-contracts/contracts/",
"optimism/=lib/GeneralisedIncentives/lib/vibc-core-smart-contracts/lib/",
"proto/=lib/GeneralisedIncentives/lib/vibc-core-smart-contracts/lib/proto/",
"protobuf3-solidity-lib/=lib/GeneralisedIncentives/lib/vibc-core-smart-contracts/lib/protobuf3-solidity-lib/contracts/",
"safe-contracts/=lib/GeneralisedIncentives/lib/vibc-core-smart-contracts/lib/optimism/packages/contracts-bedrock/lib/safe-contracts/contracts/",
"solady/=lib/solady/src/",
"solmate/=lib/GeneralisedIncentives/lib/vibc-core-smart-contracts/lib/optimism/packages/contracts-bedrock/lib/solmate/src/",
"vibc-core-smart-contracts/=lib/GeneralisedIncentives/lib/vibc-core-smart-contracts/"
],
"optimizer": {
"enabled": true,
"runs": 10000
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"abi"
]
}
},
"evmVersion": "paris",
"viaIR": true,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"factory_","type":"address"},{"internalType":"address","name":"mathlib_","type":"address"}],"stateMutability":"payable","type":"constructor"},{"inputs":[],"name":"AllowanceOverflow","type":"error"},{"inputs":[],"name":"AllowanceUnderflow","type":"error"},{"inputs":[],"name":"EscrowAlreadyExists","type":"error"},{"inputs":[],"name":"ExceedsSecurityLimit","type":"error"},{"inputs":[],"name":"InsufficientAllowance","type":"error"},{"inputs":[],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"InvalidPermit","type":"error"},{"inputs":[],"name":"NotEnoughGas","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"PermitExpired","type":"error"},{"inputs":[],"name":"Reentrancy","type":"error"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"ReturnInsufficient","type":"error"},{"inputs":[],"name":"TotalSupplyOverflow","type":"error"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"UnusedUnitsAfterWithdrawal","type":"error"},{"inputs":[],"name":"VaultNotConnected","type":"error"},{"inputs":[],"name":"WithdrawRatioNotZero","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[],"name":"FinishSetup","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"address","name":"fromAsset","type":"address"},{"indexed":false,"internalType":"address","name":"toAsset","type":"address"},{"indexed":false,"internalType":"uint256","name":"fromAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"toAmount","type":"uint256"}],"name":"LocalSwap","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"channelId","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"fromVault","type":"bytes"},{"indexed":false,"internalType":"address","name":"toAccount","type":"address"},{"indexed":false,"internalType":"address","name":"toAsset","type":"address"},{"indexed":false,"internalType":"uint256","name":"units","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"toAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fromAmount","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"fromAsset","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"sourceBlockNumberMod","type":"uint32"}],"name":"ReceiveAsset","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"channelId","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"fromVault","type":"bytes"},{"indexed":false,"internalType":"address","name":"toAccount","type":"address"},{"indexed":false,"internalType":"uint256","name":"units","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"toAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fromAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sourceBlockNumberMod","type":"uint256"}],"name":"ReceiveLiquidity","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"channelId","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"toVault","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"toAccount","type":"bytes"},{"indexed":false,"internalType":"address","name":"fromAsset","type":"address"},{"indexed":false,"internalType":"uint8","name":"toAssetIndex","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"fromAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"minOut","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"units","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"},{"indexed":false,"internalType":"uint16","name":"underwriteIncentiveX16","type":"uint16"}],"name":"SendAsset","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"channelId","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"toAccount","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"units","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"escrowAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"escrowToken","type":"address"},{"indexed":false,"internalType":"uint32","name":"blockNumberMod","type":"uint32"}],"name":"SendAssetFailure","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"channelId","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"toAccount","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"units","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"escrowAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"escrowToken","type":"address"},{"indexed":false,"internalType":"uint32","name":"blockNumberMod","type":"uint32"}],"name":"SendAssetSuccess","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"channelId","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"toVault","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"toAccount","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"fromAmount","type":"uint256"},{"indexed":false,"internalType":"uint256[2]","name":"minOut","type":"uint256[2]"},{"indexed":false,"internalType":"uint256","name":"units","type":"uint256"}],"name":"SendLiquidity","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"channelId","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"toAccount","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"units","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"escrowAmount","type":"uint256"},{"indexed":false,"internalType":"uint32","name":"blockNumberMod","type":"uint32"}],"name":"SendLiquidityFailure","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"channelId","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"toAccount","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"units","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"escrowAmount","type":"uint256"},{"indexed":false,"internalType":"uint32","name":"blockNumberMod","type":"uint32"}],"name":"SendLiquiditySuccess","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint48","name":"targetTime","type":"uint48"},{"indexed":false,"internalType":"uint256","name":"targetAmplification","type":"uint256"}],"name":"SetAmplification","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"channelId","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"toVault","type":"bytes"},{"indexed":false,"internalType":"bool","name":"newState","type":"bool"}],"name":"SetConnection","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"administrator","type":"address"}],"name":"SetFeeAdministrator","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"fee","type":"uint64"}],"name":"SetGovernanceFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"fee","type":"uint64"}],"name":"SetVaultFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint248","name":"targetTime","type":"uint248"},{"indexed":false,"internalType":"uint256[]","name":"targetWeights","type":"uint256[]"}],"name":"SetWeights","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"identifier","type":"bytes32"},{"indexed":false,"internalType":"address","name":"toAsset","type":"address"},{"indexed":false,"internalType":"uint256","name":"U","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"purchasedTokens","type":"uint256"}],"name":"SwapUnderwritten","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"toAccount","type":"address"},{"indexed":false,"internalType":"uint256","name":"mint","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"assets","type":"uint256[]"}],"name":"VaultDeposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"toAccount","type":"address"},{"indexed":false,"internalType":"uint256","name":"burn","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"assets","type":"uint256[]"}],"name":"VaultWithdraw","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"result","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FACTORY","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MATHLIB","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_adjustmentTarget","outputs":[{"internalType":"uint48","name":"","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_chainInterface","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"_escrowLookup","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"_escrowedTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_escrowedVaultTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_feeAdministrator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_governanceFeeShare","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_lastModificationTime","outputs":[{"internalType":"uint48","name":"","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_maxUnitCapacity","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_oneMinusAmp","outputs":[{"internalType":"int64","name":"","type":"int64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_setupMaster","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_targetAmplification","outputs":[{"internalType":"int64","name":"","type":"int64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"_tokenIndexing","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"_underwriteEscrowMatchBalance0","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_unitTracker","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"_vaultConnection","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_vaultFee","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"_weight","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"fromAsset","type":"address"},{"internalType":"address","name":"toAsset","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"calcLocalSwap","outputs":[{"internalType":"uint256","name":"output","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"toAsset","type":"address"},{"internalType":"uint256","name":"U","type":"uint256"}],"name":"calcReceiveAsset","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"fromAsset","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"calcSendAsset","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"computeBalance0","outputs":[{"internalType":"uint256","name":"walpha_0","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"identifier","type":"bytes32"},{"internalType":"uint256","name":"U","type":"uint256"},{"internalType":"uint256","name":"escrowAmount","type":"uint256"},{"internalType":"address","name":"escrowToken","type":"address"}],"name":"deleteUnderwriteAsset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenAmounts","type":"uint256[]"},{"internalType":"uint256","name":"minOut","type":"uint256"}],"name":"depositMixed","outputs":[{"internalType":"uint256","name":"vaultTokens","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"factoryOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"finishSetup","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getUnitCapacity","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"governanceFeeDestination","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"assets","type":"address[]"},{"internalType":"uint256[]","name":"weights","type":"uint256[]"},{"internalType":"uint64","name":"amp","type":"uint64"},{"internalType":"address","name":"depositor","type":"address"}],"name":"initializeSwapCurves","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"fromAsset","type":"address"},{"internalType":"address","name":"toAsset","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minOut","type":"uint256"}],"name":"localSwap","outputs":[{"internalType":"uint256","name":"out","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"channelId","type":"bytes32"},{"internalType":"bytes","name":"toAccount","type":"bytes"},{"internalType":"uint256","name":"U","type":"uint256"},{"internalType":"uint256","name":"escrowAmount","type":"uint256"},{"internalType":"address","name":"escrowToken","type":"address"},{"internalType":"uint32","name":"blockNumberMod","type":"uint32"}],"name":"onSendAssetFailure","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"channelId","type":"bytes32"},{"internalType":"bytes","name":"toAccount","type":"bytes"},{"internalType":"uint256","name":"U","type":"uint256"},{"internalType":"uint256","name":"escrowAmount","type":"uint256"},{"internalType":"address","name":"escrowToken","type":"address"},{"internalType":"uint32","name":"blockNumberMod","type":"uint32"}],"name":"onSendAssetSuccess","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"channelId","type":"bytes32"},{"internalType":"bytes","name":"toAccount","type":"bytes"},{"internalType":"uint256","name":"U","type":"uint256"},{"internalType":"uint256","name":"escrowAmount","type":"uint256"},{"internalType":"uint32","name":"blockNumberMod","type":"uint32"}],"name":"onSendLiquidityFailure","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"channelId","type":"bytes32"},{"internalType":"bytes","name":"toAccount","type":"bytes"},{"internalType":"uint256","name":"U","type":"uint256"},{"internalType":"uint256","name":"escrowAmount","type":"uint256"},{"internalType":"uint32","name":"blockNumberMod","type":"uint32"}],"name":"onSendLiquiditySuccess","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"ready","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"channelId","type":"bytes32"},{"internalType":"bytes","name":"fromVault","type":"bytes"},{"internalType":"uint256","name":"toAssetIndex","type":"uint256"},{"internalType":"address","name":"toAccount","type":"address"},{"internalType":"uint256","name":"U","type":"uint256"},{"internalType":"uint256","name":"minOut","type":"uint256"},{"internalType":"uint256","name":"fromAmount","type":"uint256"},{"internalType":"bytes","name":"fromAsset","type":"bytes"},{"internalType":"uint32","name":"blockNumberMod","type":"uint32"}],"name":"receiveAsset","outputs":[{"internalType":"uint256","name":"purchasedTokens","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"channelId","type":"bytes32"},{"internalType":"bytes","name":"fromVault","type":"bytes"},{"internalType":"address","name":"toAccount","type":"address"},{"internalType":"uint256","name":"U","type":"uint256"},{"internalType":"uint256","name":"minVaultTokens","type":"uint256"},{"internalType":"uint256","name":"minReferenceAsset","type":"uint256"},{"internalType":"uint256","name":"fromAmount","type":"uint256"},{"internalType":"uint32","name":"blockNumberMod","type":"uint32"}],"name":"receiveLiquidity","outputs":[{"internalType":"uint256","name":"purchasedVaultTokens","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"refundTo","type":"address"},{"internalType":"bytes32","name":"identifier","type":"bytes32"},{"internalType":"uint256","name":"escrowAmount","type":"uint256"},{"internalType":"address","name":"escrowToken","type":"address"},{"internalType":"bytes32","name":"sourceIdentifier","type":"bytes32"},{"internalType":"bytes","name":"fromVault","type":"bytes"}],"name":"releaseUnderwriteAsset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"chainIdentifier","type":"bytes32"},{"internalType":"bytes","name":"toVault","type":"bytes"},{"internalType":"bytes","name":"toAccount","type":"bytes"},{"components":[{"internalType":"uint48","name":"maxGasDelivery","type":"uint48"},{"internalType":"uint48","name":"maxGasAck","type":"uint48"},{"internalType":"address","name":"refundGasTo","type":"address"},{"internalType":"uint96","name":"priceOfDeliveryGas","type":"uint96"},{"internalType":"uint96","name":"priceOfAckGas","type":"uint96"},{"internalType":"uint64","name":"targetDelta","type":"uint64"}],"internalType":"struct IMessageEscrowStructs.IncentiveDescription","name":"incentive","type":"tuple"},{"internalType":"uint64","name":"deadline","type":"uint64"}],"internalType":"struct ICatalystV1Structs.RouteDescription","name":"routeDescription","type":"tuple"},{"internalType":"address","name":"fromAsset","type":"address"},{"internalType":"uint8","name":"toAssetIndex","type":"uint8"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minOut","type":"uint256"},{"internalType":"address","name":"fallbackUser","type":"address"},{"internalType":"uint16","name":"underwriteIncentiveX16","type":"uint16"},{"internalType":"bytes","name":"calldata_","type":"bytes"}],"name":"sendAsset","outputs":[{"internalType":"uint256","name":"U","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"chainIdentifier","type":"bytes32"},{"internalType":"bytes","name":"toVault","type":"bytes"},{"internalType":"bytes","name":"toAccount","type":"bytes"},{"components":[{"internalType":"uint48","name":"maxGasDelivery","type":"uint48"},{"internalType":"uint48","name":"maxGasAck","type":"uint48"},{"internalType":"address","name":"refundGasTo","type":"address"},{"internalType":"uint96","name":"priceOfDeliveryGas","type":"uint96"},{"internalType":"uint96","name":"priceOfAckGas","type":"uint96"},{"internalType":"uint64","name":"targetDelta","type":"uint64"}],"internalType":"struct IMessageEscrowStructs.IncentiveDescription","name":"incentive","type":"tuple"},{"internalType":"uint64","name":"deadline","type":"uint64"}],"internalType":"struct ICatalystV1Structs.RouteDescription","name":"routeDescription","type":"tuple"},{"internalType":"address","name":"fromAsset","type":"address"},{"internalType":"uint8","name":"toAssetIndex","type":"uint8"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minOut","type":"uint256"},{"internalType":"uint256","name":"minU","type":"uint256"},{"internalType":"address","name":"fallbackUser","type":"address"},{"internalType":"uint16","name":"underwriteIncentiveX16","type":"uint16"},{"internalType":"bytes","name":"calldata_","type":"bytes"}],"name":"sendAssetFixedUnit","outputs":[{"internalType":"uint256","name":"U","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"chainIdentifier","type":"bytes32"},{"internalType":"bytes","name":"toVault","type":"bytes"},{"internalType":"bytes","name":"toAccount","type":"bytes"},{"components":[{"internalType":"uint48","name":"maxGasDelivery","type":"uint48"},{"internalType":"uint48","name":"maxGasAck","type":"uint48"},{"internalType":"address","name":"refundGasTo","type":"address"},{"internalType":"uint96","name":"priceOfDeliveryGas","type":"uint96"},{"internalType":"uint96","name":"priceOfAckGas","type":"uint96"},{"internalType":"uint64","name":"targetDelta","type":"uint64"}],"internalType":"struct IMessageEscrowStructs.IncentiveDescription","name":"incentive","type":"tuple"},{"internalType":"uint64","name":"deadline","type":"uint64"}],"internalType":"struct ICatalystV1Structs.RouteDescription","name":"routeDescription","type":"tuple"},{"internalType":"uint256","name":"vaultTokens","type":"uint256"},{"internalType":"uint256[2]","name":"minOut","type":"uint256[2]"},{"internalType":"address","name":"fallbackUser","type":"address"},{"internalType":"bytes","name":"calldata_","type":"bytes"}],"name":"sendLiquidity","outputs":[{"internalType":"uint256","name":"U","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"channelId","type":"bytes32"},{"internalType":"bytes","name":"toVault","type":"bytes"},{"internalType":"bool","name":"state","type":"bool"}],"name":"setConnection","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"administrator","type":"address"}],"name":"setFeeAdministrator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"fee","type":"uint64"}],"name":"setGovernanceFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"fee","type":"uint64"}],"name":"setVaultFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"},{"internalType":"address","name":"chainInterface","type":"address"},{"internalType":"uint64","name":"vaultFee","type":"uint64"},{"internalType":"uint64","name":"governanceFee","type":"uint64"},{"internalType":"address","name":"feeAdministrator","type":"address"},{"internalType":"address","name":"setupMaster","type":"address"}],"name":"setup","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"identifier","type":"bytes32"},{"internalType":"address","name":"toAsset","type":"address"},{"internalType":"uint256","name":"U","type":"uint256"},{"internalType":"uint256","name":"minOut","type":"uint256"}],"name":"underwriteAsset","outputs":[{"internalType":"uint256","name":"purchasedTokens","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"updateMaxUnitCapacity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"vaultTokens","type":"uint256"},{"internalType":"uint256[]","name":"minOut","type":"uint256[]"}],"name":"withdrawAll","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"vaultTokens","type":"uint256"},{"internalType":"uint256[]","name":"withdrawRatio","type":"uint256[]"},{"internalType":"uint256[]","name":"minOut","type":"uint256[]"}],"name":"withdrawMixed","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
6001600160401b0360c0601f62005d9138819003918201601f191683019184831184841017620001b6578084926040948552833981010312620001b1576200004781620001cc565b620000566020809301620001cc565b9060805260a0526000916200006c8354620001e1565b601f811162000185575b50602e7f436174616c797374205661756c742054656d706c617465000000000000000000018355600192620000ac8454620001e1565b601f811162000157575b506000845563409feecd19938454918183166200014a57501c8190036200010f575b604051615b7290816200021f8239608051818181610c330152818161182a0152818161378d01526143ca015260a051816123990152f35b6002600160411b039092559081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29080a1388080620000d8565b63f92ee8a990526004601cfd5b84825284601f858420920160051c8201915b82811062000179575050620000b6565b83815501859062000169565b838052601f838520910160051c8101905b818110620001a5575062000076565b84815560010162000196565b600080fd5b634e487b7160e01b600052604160045260246000fd5b51906001600160a01b0382168203620001b157565b90600182811c9216801562000213575b6020831014620001fd57565b634e487b7160e01b600052602260045260246000fd5b91607f1691620001f156fe6080604052600436101561001257600080fd5b60003560e01c8063033597b21461042757806306fdde0314610422578063095ea7b31461041d57806309de4fea146104185780630bc350d714610413578063119f8e681461040e578063128581001461040957806313193e6a1461040457806316604f4f146103ff57806318160ddd146103fa5780631fd1602b146103f5578063202ad2c5146103f057806323b872dd146103eb57806324351d57146103e65780632dd31000146103e15780632f48ed57146103dc578063313ce567146103d757806332a3385e146103d257806334420dbd146103cd5780633644e515146103c857806336ae087e146103c357806337fd5135146103be57806339a391de146103b95780633b49580d146103b45780633cf183fa146103af5780634273601c146103aa57806346c3a2fd146103a5578063505b0c12146103a0578063586f98001461039b5780635c459a5b1461039657806364d1e1c01461039157806366ae79e61461038c5780636caea8a3146103875780636d0f691b146103825780636defbf801461037d57806370a08231146103785780637265563114610373578063739fc9bc1461036e5780637ecebe0014610369578063818431be1461036457806386f25e4d1461035f578063904e0a011461035a5780639584c8881461035557806395d89b4114610350578063994e1ada1461034b5780639cf80f20146103465780639d29db4514610341578063a57ecf4f1461033c578063a9059cbb14610337578063aa14786214610332578063ac9650d81461032d578063b22889e414610328578063b9ff629b14610323578063bf5086421461031e578063c86380d914610319578063c8d710d514610314578063c90da0131461030f578063d505accf1461030a578063dd62ed3e14610305578063de6bbd9d14610300578063e6b91aba146102fb578063e75552fb146102f6578063eb80cd11146102f1578063f71f4026146102ec5763f754fc35146102e757600080fd5b613365565b613341565b6132d8565b612fc9565b612fab565b612f1d565b612ed6565b612d25565b612cfe565b612cc9565b612bbb565b612b94565b612b28565b612a3e565b612985565b612964565b6128db565b612848565b6127f3565b6127c9565b6126b4565b6125c1565b61259b565b612566565b6124f1565b6124d8565b6124a1565b612463565b612445565b61240e565b6123bd565b612379565b61234e565b6122bd565b61224e565b611e2e565b611d07565b611b16565b611aeb565b611ad0565b6117ad565b611226565b61111e565b6110eb565b610df6565b610d5e565b610cee565b610cb0565b610c94565b610c57565b610c13565b610bd5565b610b01565b610aa9565b610951565b6108d1565b610845565b610763565b6106f8565b610611565b6105eb565b6105b2565b6104e6565b6104a9565b61043c565b600091031261043757565b600080fd5b34610437576000600319360112610437576020600a54604051908152f35b60005b83811061046d5750506000910152565b818101518382015260200161045d565b601f19601f604093602084526104a2815180928160208801526020888801910161045a565b0116010190565b34610437576000600319360112610437576104d16104c5613494565b6040519182918261047d565b0390f35b6001600160a01b0381160361043757565b3461043757604060031936011261043757600435610503816104d5565b60243590602052637f5e9f20600c5233600052806034600c2055600052602c5160601c337f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560206000a3602060405160018152f35b6004359067ffffffffffffffff8216820361043757565b6084359067ffffffffffffffff8216820361043757565b6044359067ffffffffffffffff8216820361043757565b359067ffffffffffffffff8216820361043757565b34610437576020600319360112610437576105cb610558565b6001600160a01b0360085460401c163303610437576105e99061482b565b005b346104375760006003193601126104375760206106066148be565b60011c604051908152f35b3461043757608060031936011261043757600435602435610631816104d5565b604435907f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821015610437576001600160a01b039081600254163303610437576104d1937fd4228165b1b0dc50bd8ac0a74d2b5766000d5ee9f7488b9e74e183deb55c8f1d60606106e2946106a960643588876148fd565b966106b5888787615689565b60405191861682526020820152866040820152a26001600160a01b0316600052600e602052604060002090565b8054820190556040519081529081906020820190565b3461043757600060031936011261043757602065ffffffffffff60075460301c16604051908152f35b9181601f840112156104375782359167ffffffffffffffff8311610437576020838186019501011161043757565b610104359063ffffffff8216820361043757565b34610437576101206003193601126104375767ffffffffffffffff60243581811161043757610796903690600401610721565b6064929192356107a5816104d5565b60e435928311610437576104d1936107c46107e8943690600401610721565b9290916107cf61074f565b9460c4359260a43592608435926044359160043561357f565b6040519081529081906020820190565b9060a060031983011261043757600435916024359067ffffffffffffffff82116104375761082891600401610721565b9091604435906064359060843563ffffffff811681036104375790565b3461043757610853366107f8565b9490926001600160a01b0360029593955416330361043757858486836108b5836108b0816108ab6108cc9e7f97cc161fb90f5cdec9c65ba7aac2279e32df11368946590b82fd6fe8e76b39e09d886108c19c8f61508a565b615639565b614b44565b604051968796876147f5565b0390a1601054613718565b601055005b346104375760006003193601126104375760206805345cdf77eb68f44c54604051908152f35b9060c060031983011261043757600435916024359067ffffffffffffffff82116104375761092791600401610721565b9091604435906064359060843561093d816104d5565b9060a43563ffffffff811681036104375790565b346104375761095f366108f7565b929495936001600160a01b039291928060025416330361043757610a0a60008061099987876109948b8f8f84908c879361585a565b6158e1565b5a946040519060208201927fa9059cbb000000000000000000000000000000000000000000000000000000008452166024820152876044820152604481526109e081611d88565b519082897f8000000000000000000000000000000000000000000000000000000000000000f11590565b610a52575b6105e9610a4d887fcab6c1a18a9c89efaab5ea5a8c665ffe2c5aac9ddd9301ccad01fd4fed7c7e3d8b8a6108c18b8b8b878c60405197889788614a05565b601055565b610a6d610a66989497969395985a92613b6c565b603f900490565b11610a7f573896939194959296610a0f565b60046040517fdd629f86000000000000000000000000000000000000000000000000000000008152fd5b34610437576000600319360112610437576020610ac4613757565b6001600160a01b0360405191168152f35b600319606091011261043757600435610aed816104d5565b90602435610afa816104d5565b9060443590565b3461043757610b0f36610ad5565b8260601b91602092338452600c90637f5e9f2081178252603482209081549160018301610bb0575b506387a211a2915017815283812092835492838211610ba2577fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef94826001600160a01b039503905560005284822081815401905584525160601c93169180a360405160018152602090f35b63f4d678b86000526004601cfd5b828611610bc757856387a211a29303905538610b37565b6313be252b6000526004601cfd5b34610437576020600319360112610437576001600160a01b03600435610bfa816104d5565b16600052600b6020526020604060002054604051908152f35b346104375760006003193601126104375760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b3461043757602060031936011261043757600435610c74816104d5565b6001600160a01b03610c84614394565b163303610437576105e990614a4a565b3461043757600060031936011261043757602060405160128152f35b34610437576020600319360112610437576001600160a01b03600435610cd5816104d5565b1660005260056020526020604060002054604051908152f35b34610437576101006003193601126104375760243567ffffffffffffffff811161043757610d20903690600401610721565b60443591610d2d836104d5565b60e4359063ffffffff82168203610437576104d1936107e89360c4359260a4359260843592606435926004356137ea565b3461043757600060031936011261043757602060a0610d7b613494565b828151910120604051907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f8252838201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6604082015246606082015230608082015220604051908152f35b90816101409103126104375790565b60c060031936011261043757600467ffffffffffffffff813581811161043757610e239036908401610de7565b9160243591366084116104375760843590610e3d826104d5565b60a43590811161043757610e549036908401610721565b68929eee149b4bd2126894919492308454146110de573084558635966020810190610e89610e828383613abe565b3691612276565b9689600052600360205260ff610eb3602060409a8b600020828d519483868095519384920161045a565b8201908152030190205416156110b757610ed76001600160a01b0385161515613578565b610ee18633614ba4565b610f57610f46610f51610eff610ef9600f5460070b90565b60070b90565b610f4b610f0b82614c0b565b949092610f418d610f3c610f3582610f306805345cdf77eb68f44c54600c5490613b0f565b613b0f565b9182613b0f565b614d44565b614dc6565b613b32565b9061506d565b90613b9a565b98610f837f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8b10613578565b610f92610a4d8b601054613bad565b610fb6610faa610faa6002546001600160a01b031690565b6001600160a01b031690565b803b156104375783600093610ffb8a998e958e519c8d97889687967f318987c40000000000000000000000000000000000000000000000000000000088528701613d44565b039134905af19081156110b2576104d199611088967f8c9503be4db35b4e3d31565a9616d1dc3f1b3024e5e9e9d65052de46a5149f1c93611099575b506110808a878b85018c61107361106b6110648686611056878d613abe565b4363ffffffff16939161508a565b9a89613abe565b939098613abe565b9290915197889788613d7f565b0390a16150ec565b389055519081529081906020820190565b806110a66110ac92611d6f565b8061042c565b38611037565b61374b565b87517f2c64c1b2000000000000000000000000000000000000000000000000000000008152fd5b8463ab143c06600052601cfd5b3461043757604060031936011261043757602061111660043561110d816104d5565b60243590613e12565b604051908152f35b346104375760e06003193601126104375767ffffffffffffffff60043581811161043757611150903690600401610721565b60243583811161043757611168903690600401610721565b93604435611175816104d5565b6064359182168203610437576105e99561118d61056f565b9360a4359561119b876104d5565b60c435976111a8896104d5565b613ef3565b9181601f840112156104375782359167ffffffffffffffff8311610437576020808501948460051b01011161043757565b90815180825260208080930193019160005b8281106111fe575050505090565b8351855293810193928101926001016111f0565b9060206112239281815201906111de565b90565b346104375760606003193601126104375767ffffffffffffffff60046024358281116104375761125990369083016111ad565b9190926044359081116104375761127390369083016111ad565b92903068929eee149b4bd2126854146117a0579293903068929eee149b4bd21268556112a0833533614ba4565b6112af610ef9600f5460070b90565b936112b86142ab565b916112c16142ab565b926000805b600382106115e5575b90610f516112e58261131d946010549003613e03565b610f4b6113188c610f418d610f3c6113106805345cdf77eb68f44c54610f30843591600c5490613b0f565b913582613b5f565b613b1c565b97611326614315565b9760009586975b60038810611408575b5050505050505050836113cf576104d1935061135c61135782600a54613b5f565b600a55565b600654908082116113c05750506113736000600655565b7f7a5919fae19c7104c67635ca0c2ded0d01316a06da859fd961851aa12ac6c71b604051806113a58533953583614373565b0390a23868929eee149b4bd212685560405191829182611212565b6113ca9103600655565b611373565b6040517f0289311f00000000000000000000000000000000000000000000000000000000815280830185815281906020010390fd5b0390fd5b909192939495969761142d610faa6114208b896142ff565b516001600160a01b031690565b156115df576114476114408a8985614330565b358d61506d565b9b8c1561153d578c61145891613b5f565b9b6114638a886142ff565b516001600160a01b03166000908152600560205260409020549085826114898d886142ff565b5161149393615258565b8061149f8c898d614330565b35116114f257916114db6114e192848f818f6114d16114208f9260019b6114c9826114d698614340565b5233936142ff565b6149bc565b613b9a565b90613b0f565b9801955b949392919096959661132d565b8b6114046115018d8a8e614330565b604080517f24557f0500000000000000000000000000000000000000000000000000000000815293840194855290356020850152919283920190565b9b509761154b818884614330565b356115b65761155b81868a614330565b3561156957600101956114e5565b6115758a91868a614330565b35906114046040519283927f24557f050000000000000000000000000000000000000000000000000000000084528301919060206040840193600081520152565b896040517fb8003bfa000000000000000000000000000000000000000000000000000000008152fd5b97611336565b90611612611605829b94959896979a9b6000526004602052604060002090565b546001600160a01b031690565b6001600160a01b038116801561179057906116a99161164382611635868a6142ff565b906001600160a01b03169052565b60208b611663846001600160a01b03166000526005602052604060002090565b549260405180809781947f70a08231000000000000000000000000000000000000000000000000000000008352309083019190916001600160a01b036020820193169052565b03915afa9182156110b2578c611720938f9592610f519360009261175d575b5061171991926116ff896116f96116f2856001600160a01b0316600052600b602052604060002090565b5487613b5f565b926142ff565b526001600160a01b0316600052600e602052604060002090565b5490613b5f565b80611739575b50506001019098979493959291986112c6565b9261174d61175392610f4160019596613b7d565b90613bad565b9190508938611726565b61171992506117839060203d602011611789575b61177b8183611da4565b810190613dc5565b916116c8565b503d611771565b50509098979493959291986112cf565b8263ab143c06600052601cfd5b346104375760806003193601126104375767ffffffffffffffff60048035828111610437576117e09036906004016111ad565b602493919335828111610437576117fe9094939436906004016111ad565b919093611809610586565b946119246064359561181a876104d5565b806001600160a01b03986118518a7f0000000000000000000000000000000000000000000000000000000000000000163314613578565b60008052600460205261188e8a6118877f17ef568e3e12ab5b9c7254a8d58478811de00f9e6eb34345acd53bf8fd09d3ec611605565b1615613578565b16670de0b6b3a76400006118a3818310613578565b031660070b6118e2817fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000600f54169067ffffffffffffffff1617600f55565b7fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff600f549160401b6fffffffffffffffff000000000000000016911617600f55565b61192c614315565b9660009485945b80861061198657897f7dde447513a4ed2580f1f8cd3caea2d0c14b2f46b036d72456a33457da14ed758a8a6119678b600a55565b61197081614acc565b611981604051928392169482614354565b0390a2005b909192939495886119a061199b89858a614330565b61438a565b916119ec836119b98b6000526004602052604060002090565b906001600160a01b03167fffffffffffffffffffffffff0000000000000000000000000000000000000000825416179055565b6119f7898689614330565b3592611a04841515613578565b83611a22826001600160a01b03166000526005602052604060002090565b556040517f70a08231000000000000000000000000000000000000000000000000000000008152308882019081526020949192859284928390038401918391165afa80156110b2576001948b8f6114db94611a9d97600095611aa9575b50508391611a9791611a92841515613578565b614340565b52613b9a565b96019493929190611933565b611a97929395509081611ac792903d106117895761177b8183611da4565b93919038611a7f565b34610437576000600319360112610437576020610ac4614394565b3461043757600060031936011261043757602067ffffffffffffffff60075460901c16604051908152f35b3461043757608060031936011261043757600435611b33816104d5565b60243590611b40826104d5565b604435916064359168929eee149b4bd212689130835414611cf957308355611b8e611b88611b7b60075467ffffffffffffffff9060901c1690565b67ffffffffffffffff1690565b8661506d565b611ba2611b9b8288613b5f565b83856144db565b94858111611cbf5750947ff631545f16e5f3e54a6cf8b4e2bfe643a342d0d0bf8e224479382b8acdfd009a91611bf26104d197611be1843033896152be565b611bec8833856149bc565b85615317565b611c19611c12856001600160a01b03166000526005602052604060002090565b5483613b9a565b611c40611c39836001600160a01b03166000526005602052604060002090565b5488613b9a565b81811115611ca257611c58611c609261135792613b5f565b600a54613b5f565b604080516001600160a01b03958616815294909116602085015283015260608201849052339180608081015b0390a23890556040519081529081906020820190565b611cb261135791611cba93613b5f565b600a54613b0f565b611c60565b6040517f24557f05000000000000000000000000000000000000000000000000000000008152600481018790526024810191909152604490fd5b63ab143c066000526004601cfd5b3461043757602060031936011261043757611d20610558565b6001600160a01b03611d30614394565b163303610437576105e9906151e8565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b67ffffffffffffffff8111611d8357604052565b611d40565b6080810190811067ffffffffffffffff821117611d8357604052565b90601f601f19910116810190811067ffffffffffffffff821117611d8357604052565b81601f820112156104375780359160209167ffffffffffffffff8411611d83578360051b9060405194611dfc85840187611da4565b85528380860192820101928311610437578301905b828210611e1f575050505090565b81358152908301908301611e11565b346104375760408060031936011261043757600480359160243567ffffffffffffffff811161043757611e65903690600401611dc7565b9268929eee149b4bd212689130835414611cf957308355611e868233614ba4565b611e95610ef9600f5460070b90565b93611e9e6142ab565b90611ea76142ab565b926000805b600381106120e8575b601054611ec29203613e03565b96611ecb614315565b9781611f02611eeb89610f306805345cdf77eb68f44c54600c5490613b0f565b611efd611ef88b83613b5f565b613b7d565b613e03565b806120d1575050905b600095611f17826143fe565b91875b60038110611fa8575b50505050505050506104d19450611f3f61135782600a54613b5f565b60065490808211611f99575050611f566000600655565b7f7a5919fae19c7104c67635ca0c2ded0d01316a06da859fd961851aa12ac6c71b60405180611f8786339583614373565b0390a238905560405191829182611212565b611fa39103600655565b611f56565b611fb5611420828a6142ff565b6001600160a01b038116156120cb578d90611fdd84610f41611fd786896142ff565b51613b7d565b9a611fe884876142ff565b519b808910612097575b50836120296120048e61202f94613b0f565b9d612022856001600160a01b03166000526005602052604060002090565b5490613e03565b93614340565b5182811161205a575081612054918f9361204c8660019796614340565b5233906149bc565b01611f1a565b88517f24557f05000000000000000000000000000000000000000000000000000000008152808b0184815260208101929092529081906040010390fd5b6120296120046120c161202f949f610f4b6113188d8f886120bc610f41928f9b613b5f565b61534b565b9e93505050611ff2565b50611f23565b6113186120e29392610f4b92614dc6565b90611f0b565b6120ff611605826000526004602052604060002090565b6001600160a01b0381169081156122475761211e81611635858a6142ff565b61213b816001600160a01b03166000526005602052604060002090565b5485517f70a082310000000000000000000000000000000000000000000000000000000081523088820190815290936020918291869182908190850103915afa80156110b2578d946121979260009261222a575b505082613b9a565b916121c86121c2836121bc846001600160a01b0316600052600b602052604060002090565b54613b9a565b84613b5f565b6121d2868c6142ff565b52826121e5575b50505050600101611eac565b92610f41611ef8600196979461221861174d956121bc61221e996001600160a01b0316600052600e602052604060002090565b90613b5f565b919050883880806121d9565b6122409250803d106117895761177b8183611da4565b388061218f565b5050611eb5565b3461043757600060031936011261043757602067ffffffffffffffff60085416604051908152f35b92919267ffffffffffffffff8211611d8357604051916122a06020601f19601f8401160184611da4565b829481845281830111610437578281602093846000960137010152565b346104375760406003193601126104375760243567ffffffffffffffff811161043757366023820112156104375761233c61232c602061230a6104d1943690602481600401359101612276565b600435600052600382526040600020826040519483868095519384920161045a565b8201908152030190205460ff1690565b60405190151581529081906020820190565b34610437576040600319360112610437576020611116600435612370816104d5565b60243590614418565b346104375760006003193601126104375760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b346104375760008060031936011261240b576020906001600160a01b0380600954161591826123f3575b50506040519015158152f35b604091925080805260048452205416151538806123e7565b80fd5b346104375760206003193601126104375760043561242b816104d5565b6387a211a2600c52600052602080600c2054604051908152f35b34610437576000600319360112610437576020600c54604051908152f35b34610437576020600319360112610437576001600160a01b03600435612488816104d5565b16600052600e6020526020604060002054604051908152f35b34610437576020600319360112610437576004356124be816104d5565b6338377508600c52600052602080600c2054604051908152f35b346104375760206111166124eb36610ad5565b916144db565b346104375760008060031936011261240b576009546001600160a01b0381163303612562577fffffffffffffffffffffffff0000000000000000000000000000000000000000166009557f7991f9d379def473bbda7d0d566449ae0c4b9edb031c33f829df029783f680a48180a180f35b5080fd5b3461043757602060031936011261043757600435600052600460205260206001600160a01b0360406000205416604051908152f35b3461043757600060031936011261043757602065ffffffffffff60075416604051908152f35b346104375760008060031936011261240b57604051908060018054906125e682613441565b80865292602092600181169081156126695750600114612611575b6104d1866104c581880382611da4565b9350600184527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b838510612656575050505081016020016104c5826104d138612601565b8054868601840152938201938101612639565b8796506104d1979450602093506104c59592507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091501682840152151560051b820101929338612601565b346104375760008060031936011261240b5780805b600382106126d9575b600a555080f35b6126f0611605836000526004602052604060002090565b906001600160a01b0382169081156127c1576040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152926020928390859060249082905afa9081156110b25761279561277b6114db9360019761279c978b926127a4575b5050611719846001600160a01b0316600052600b602052604060002090565b916001600160a01b03166000526005602052604060002090565b5490613b9a565b9101906126c9565b6127ba9250803d106117895761177b8183611da4565b388061275c565b9150506126d2565b346104375760006003193601126104375760206008546001600160a01b036040519160401c168152f35b3461043757602060031936011261043757600435600052600d60205260206001600160a01b0360406000205416604051908152f35b6044359060ff8216820361043757565b6084359060ff8216820361043757565b6101206003193601126104375767ffffffffffffffff60043581811161043757612876903690600401610de7565b90602435612883816104d5565b61288b612828565b9260c435612898816104d5565b60e4359061ffff821682036104375761010435948511610437576104d1956128c76107e8963690600401610721565b95909460a435926084359260643592614646565b34610437576040600319360112610437576004356128f8816104d5565b602435906387a211a2600c52336000526020600c208054808411610ba25783900390556000526020600c20818154019055602052600c5160601c337fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef602080a360405160018152602090f35b34610437576000600319360112610437576020600f5460070b604051908152f35b34610437576020806003193601126104375760043567ffffffffffffffff8111610437576129b79036906004016111ad565b9060009260208452826020528215612a3957909160051b90604082848237828101925b8151850191868460408401948035918291018637389085305af415612a305781848267ffffffffffffffe094603f945201933d90523d88606083013e3d0101169383821015612a2957936129da565b6040850186f35b863d81803e3d90fd5b604084f35b346104375760606003193601126104375760043560243567ffffffffffffffff811161043757612a72903690600401610721565b91604435928315158403610437576001600160a01b036009541633036104375760418103610437577fd3223b577ecd2d8632a35c20b084999e9f3d352d8924beb1d32f42e0bd66e9a593612b2391836000526003602052612b1782604060002060206040518092868b8337868201908152030190209060ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0083541691151516179055565b6040519485948561472c565b0390a1005b3461043757608060031936011261043757604435606435612b48816104d5565b6001600160a01b03908160025416330361043757612b6981846004356158e1565b50612b78602435601054613bad565b60105516600052600e6020526040600020908154039055600080f35b346104375760006003193601126104375760206001600160a01b0360025416604051908152f35b346104375760c060031936011261043757600435612bd8816104d5565b60443590606435612be8816104d5565b60a43567ffffffffffffffff811161043757612c08903690600401610721565b6001600160a01b03600254163303610437576020612c2d60ff93612c4f933691612276565b608435600052600382526040600020826040519483868095519384920161045a565b820190815203019020541615612c9f57612c7b83612c9493612c7484836024356158e1565b50836149bc565b6001600160a01b0316600052600e602052604060002090565b908154039055600080f35b60046040517f2c64c1b2000000000000000000000000000000000000000000000000000000008152fd5b34610437576000600319360112610437576020611116600f5460070b612cf8612cf182614c0b565b50916143fe565b90614dc6565b346104375760006003193601126104375760206001600160a01b0360095416604051908152f35b346104375760e060031936011261043757600435612d42816104d5565b60243590612d4f826104d5565b6044359060643592612d5f612838565b92612d68613494565b90815160208093012090864211612ec857604051946001600160a01b0380911694169465383775081901600e5260009685885260c085600c209283549a7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82528782019687528b60408301977fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc689528b6060850199468b528c608087019330855260a08820602e527f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9885252528789525260a082015220604e526042602c20885260ff16845260a43560405260c435606052838060808960015afa853d5103612ebb577f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259596979801905585777f5e9f200000000000000000000000000000000000000000176040526034602c2055a380f35b63ddafbaef88526004601cfd5b631a15a3cc6000526004601cfd5b3461043757604060031936011261043757600435612ef3816104d5565b602435612eff816104d5565b602052637f5e9f20600c5260005260206034600c2054604051908152f35b6101006003193601126104375767ffffffffffffffff60043581811161043757612f4b903690600401610de7565b9060243591612f59836104d5565b612f61612828565b60a435612f6d816104d5565b60c4359061ffff821682036104375760e435948511610437576104d195612f9b6107e8963690600401610721565b9590946084359260643592614753565b34610437576000600319360112610437576020601054604051908152f35b34610437576040806003193601126104375760049060043567ffffffffffffffff811161043757612ffe903690600401611dc7565b906024359268929eee149b4bd212689130835414611cf957308355613028610ef9600f5460070b90565b9160009182918391845b6003811061314f575b5050506130b26130ca94939261306d613068846130606113576130b897600a54613b0f565b600654613b0f565b600655565b6010549003926130806000821215613578565b6007546130999060901c67ffffffffffffffff16611b7b565b670de0b6b3a76400000302670de0b6b3a7640000900490565b926143fe565b916805345cdf77eb68f44c54906155ea565b91828411613112576104d193506130e18333614b44565b7f7dde447513a4ed2580f1f8cd3caea2d0c14b2f46b036d72456a33457da14ed7560405180611c8c33948783614373565b50506040517f24557f0500000000000000000000000000000000000000000000000000000000815260048101919091526024810191909152604490fd5b613166611605826000526004602052604060002090565b936001600160a01b0385169081156132d057613195866001600160a01b03166000526005602052604060002090565b54976131a1848d614340565b5185517f70a082310000000000000000000000000000000000000000000000000000000081523088820190815291946020928391839182908190850103915afa9081156110b2576131fc926000926132b3575b50508a613b9a565b8a6000918b81613269575b5085156132585761323e8694613245946132378f95610f41611ef86114db976114db60019f9e61324f9e9b613b9a565b9103613bad565b9b84613b9a565b96309033906152be565b01915b91613032565b505050975094505060010191613252565b61329d935091610f41611ef88361221861174d959f968f6121bc906001600160a01b0316600052600e602052604060002090565b978a6132ac81610f4184613b7d565b918b613207565b6132c99250803d106117895761177b8183611da4565b38806131f4565b94505061303b565b34610437576132e6366107f8565b906001600160a01b0360029694939654163303610437578583613334836108ab86827f8a49f1dbb0b988d0421183f74b9866ce7c88256f1b88cf865bf7f3a74706fe689c612b239a8d61508a565b50604051968796876147f5565b34610437576000600319360112610437576020600f546040519060401c60070b8152f35b3461043757613373366108f7565b94919590936001600160a01b036002541633036104375785858886846133ca84846109946133f39e83837fe6db00361b6a35af0ded81ba5696c1633e945a81008cd7da44fb8a78422a7d429f8f9d6133d79e61585a565b5060405197889788614a05565b0390a16001600160a01b03166000526005602052604060002090565b54026006548180821160001461342c5761340d9103600655565b600a549081019081101561342757506105e9600019600a55565b600a55005b501561340d5761343c6000600655565b61340d565b90600182811c9216801561348a575b602083101461345b57565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b91607f1691613450565b60405190600082600054916134a883613441565b8083529260209060019081811690811561353557506001146134d5575b50506134d392500383611da4565b565b915092600080527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563936000925b82841061351d57506134d394505050810160200138806134c5565b85548885018301529485019487945092810192613502565b9050602093506134d39592507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091501682840152151560051b82010138806134c5565b1561043757565b969197949098929a999568929eee149b4bd212689b308d5414611cf957308d556001600160a01b0380600254163303610437576135bd368c8e612276565b918a600052600360205260ff6135e76020604095866000208288519483868095519384920161045a565b82019081520301902054161561369f57600052600460205280826000205416926136129085856148fd565b9b61361e8d89866149bc565b82519b8c809c6101209182918152602001528c019061363c926136c8565b961690890152606088015260808701528760a087015260c086015284820360e0860152613668926136c8565b9063ffffffff16610100830152037f6b7977bd09a2e845fb431e372aac95edfb358014e167149b4f4d09021c87a79d91a191389055565b600483517f2c64c1b2000000000000000000000000000000000000000000000000000000008152fd5b601f8260209493601f19938186528686013760008582860101520116010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8181039291600013801582851316918412161761373157565b6136e9565b908160209103126104375751611223816104d5565b6040513d6000823e3d90fd5b6040517f19b90b0d0000000000000000000000000000000000000000000000000000000081526020816004816001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165afa9081156110b2576000916137c1575090565b611223915060203d6020116137e3575b6137db8183611da4565b810190613736565b503d6137d1565b9390949691989792959868929eee149b4bd2126899308b5414611cf957308b556001600160a01b0360025416330361043757613827368389612276565b9086600052600360205260ff6138516020604094856000208287519483868095519384920161045a565b820190815203019020541615613a4957613888613873610ef9600f5460070b90565b9161388e61388084614c0b565b9381956143fe565b93613b9a565b926805345cdf77eb68f44c54906138a78486848b6155ea565b9d8e8111613a0757508d91849184613984575b50505050506138ce610a4d86601054613718565b8482111561395b578997946139559a61394d957f7af4b988c9949d39dbe6398b8332fa201574208c2656602a23f1624c428bfe9199956139438f9d9a966139398f979161393361131884610f4161392861393e9786614dc6565b94610f3c8d82613b5f565b9061594d565b615040565b615767565b5198899889613a72565b0390a1614b44565b91389055565b600483517f7c1e66d0000000000000000000000000000000000000000000000000000000008152fd5b83610f3061399f6139bd966114d66139af976139a996614dc6565b93600c5490613b0f565b90613e03565b670de0b6b3a7640000900490565b8082116139cd5782818e926138ba565b84517f24557f0500000000000000000000000000000000000000000000000000000000815260048101919091526024810191909152604490fd5b8e61140488519283927f24557f050000000000000000000000000000000000000000000000000000000084526004840160209093929193604081019481520152565b600482517f2c64c1b2000000000000000000000000000000000000000000000000000000008152fd5b9692613aa260c097936001600160a01b039263ffffffff98949c9b979c8b5260e060208c015260e08b01916136c8565b991660408801526060870152608086015260a085015216910152565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610437570180359067ffffffffffffffff82116104375760200191813603831361043757565b9190820180921161373157565b90670de0b6b3a764000091820391821161373157565b907ffffffffffffffffffffffffffffffffffffffffffffffffff21f494c589c0000820191821161373157565b9190820391821161373157565b908115600183800414171561373157565b90670de0b6b3a76400009182810292818404149015171561373157565b8181029291811591840414171561373157565b9190916000838201938412911290801582169115161761373157565b90357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18236030181121561043757016020813591019167ffffffffffffffff821161043757813603831361043757565b359065ffffffffffff8216820361043757565b35906bffffffffffffffffffffffff8216820361043757565b9061122390613c8f613c7461014085358452613c646020870187613bc9565b90918060208701528501916136c8565b613c816040860186613bc9565b9084830360408601526136c8565b9265ffffffffffff80613ca460608401613c19565b166060840152613cb660808301613c19565b1660808301526001600160a01b0360a0820135613cd2816104d5565b1660a0830152613ce460c08201613c2c565b6bffffffffffffffffffffffff80911660c0840152613d0560e08301613c2c565b1660e083015261010067ffffffffffffffff613d2282840161059d565b1690830152613d3561012080920161059d565b67ffffffffffffffff16910152565b9092613d5f611223969495939560c0845260c0840190613c45565b9460208301526040604481840137608082015260a08185039101526136c8565b9391613da490613db29460c097939a99989a875260e0602088015260e08701916136c8565b9184830360408601526136c8565b9460608201526040604460808301370152565b90816020910312610437575190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b8115613e0d570490565b613dd4565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015291906020836024816001600160a01b0385165afa9283156110b257600093613ec3575b50613ea0613e8864e8d4a51000926001600160a01b03166000526005602052604060002090565b54613e98610ef9600f5460070b90565b908585615189565b92041015613eab5790565b670d2f13f7789f0000670de0b6b3a764000091020490565b64e8d4a51000919350613e88613eea613ea09260203d6020116117895761177b8183611da4565b94925050613e61565b95919396929490967fffffffffffffffffffffffffffffffffffffffffffffffffffffffffbf6011329889548060038c556140b4575b50613f8292613f87959492613f7d926001600160a01b0390817fffffffffffffffffffffffff000000000000000000000000000000000000000093168360025416176002551690600954161760095561482b565b6151e8565b614a4a565b67ffffffffffffffff8411611d83578492600090613fae86613fa98454613441565b6140ee565b8190601f871160011461402a579580613fe192613fe89798859261401f575b50506000198260011b9260031b1c19161790565b90556141d5565b613fef5750565b6002905560016020527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602080a1565b013590503880613fcd565b600080527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5639691601f198316845b818110614099575091613fe897989184600195941061407f575b505050811b0190556141d5565b60001960f88560031b161c19910135169055388080614072565b828401358a556001909901988a985060209283019201614058565b90999260018281979694971c14303b10156140e05760ff9190911b9290921b9892939092613f82613f29565b63f92ee8a96000526004601cfd5b601f81116140fa575050565b600090600080527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563906020601f850160051c83019410614155575b601f0160051c01915b82811061414a57505050565b81815560010161413e565b9092508290614135565b90601f821161416c575050565b60019160009060016000527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6906020601f850160051c830194106141cb575b601f0160051c01915b8281106141c15750505050565b81815583016141b4565b90925082906141ab565b919067ffffffffffffffff8111611d83576001906141fc816141f78454613441565b61415f565b6000601f821160011461423057819061422c93949560009261401f5750506000198260011b9260031b1c19161790565b9055565b6001600052601f198216947fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf691805b8781106142955750838596971061427b575b505050811b019055565b60001960f88560031b161c19910135169055388080614271565b828201358455928501926020918201910161425f565b604051906060820182811067ffffffffffffffff821117611d83576040526060368337565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b9060038110156143105760051b0190565b6142d0565b6040519061432282611d88565b600382526060366020840137565b91908110156143105760051b0190565b80518210156143105760209160051b010190565b90604061122392670de0b6b3a7640000815281602082015201906111de565b6040906112239392815281602082015201906111de565b35611223816104d5565b6040517f8da5cb5b0000000000000000000000000000000000000000000000000000000081526020816004816001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165afa9081156110b2576000916137c1575090565b8015613e0d576ec097ce7bc90715b34b9f10000000000590565b906040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526020816024816001600160a01b0387165afa9081156110b2576000916144bc575b50614484836001600160a01b0316600052600b602052604060002090565b548103908111613731576144ae611223936001600160a01b03166000526005602052604060002090565b5490600f5460070b92615258565b6144d5915060203d6020116117895761177b8183611da4565b38614466565b6040517f70a0823100000000000000000000000000000000000000000000000000000000808252306004830152909493926001600160a01b039260209283886024818589165afa9788156110b257600098614625575b506040519081523060048201529383908590602490829086165afa80156110b2576145a861458e6145c39264e8d4a51000976145e597600092614608575b5050611719866001600160a01b0316600052600b602052604060002090565b926001600160a01b03166000526005602052604060002090565b54926001600160a01b03166000526005602052604060002090565b54906145e06145d7610ef9600f5460070b90565b80948a89615189565b615258565b930410156145ef57565b90670d2f13f7789f0000670de0b6b3a764000091020490565b61461e9250803d106117895761177b8183611da4565b388061456f565b8491985061463f90823d84116117895761177b8183611da4565b9790614531565b9099979496939198959268929eee149b4bd2126899308b5414611cf957308b5560ff61469d602061467c610e8282880188613abe565b8635600052600382526040600020826040519483868095519384920161045a565b820190815203019020541615612c9f576146c667ffffffffffffffff60075460901c168361506d565b92838303838111613731576146db908e613e12565b8a81106146f2575090899a9b9c6139559a92615450565b6040517f24557f050000000000000000000000000000000000000000000000000000000081526004810191909152602481018b9052604490fd5b929160409261474b9296959685526060602086015260608501916136c8565b931515910152565b989794919592989693909668929eee149b4bd2126899308b5414611cf957308b5560ff6147ab602061478a610e8282870187613abe565b8535600052600382526040600020826040519483868095519384920161045a565b820190815203019020541615612c9f576147d467ffffffffffffffff60075460901c168261506d565b9182820398828a11613731576147ed6139559a8c613e12565b9a8b92615450565b949060809497969263ffffffff9461481a92885260a0602089015260a08801916136c8565b966040860152606085015216910152565b67ffffffffffffffff811690670de0b6b3a76400008211610437577f5b7d342bae9633dbbf79ee2bcab48506e0662e0a74be62192960beab09d2fbc6916020917fffffffffffff0000000000000000ffffffffffffffffffffffffffffffffffff79ffffffffffffffff0000000000000000000000000000000000006007549260901b16911617600755604051908152a1565b600a54620151808165ffffffffffff60075460601c1642030204600654818111156148f8570390818111156148f1570390565b5050600090565b505090565b92916001600160a01b036149118386614418565b9416600052600560205261492a60406000205485613b9a565b600a54908082111561499257806149449203600a55615767565b8381116149585750610a4d90601054613718565b6040517f24557f05000000000000000000000000000000000000000000000000000000008152600481018590526024810191909152604490fd5b60046040517f7c1e66d0000000000000000000000000000000000000000000000000000000008152fd5b60109260209260145260345260446000938480936fa9059cbb00000000000000000000000082525af13d1560018351141716156149f857603452565b6390b8ec1890526004601cfd5b959094614a336001600160a01b039363ffffffff969a999560a0988a5260c060208b015260c08a01916136c8565b986040880152606087015216608085015216910152565b60207f9c1c6bae52abe079778f8408d952941f631f8b1d020e289245851e78f350c817916008547fffffffff0000000000000000000000000000000000000000ffffffffffffffff7bffffffffffffffffffffffffffffffffffffffff00000000000000008360401b169116176008556001600160a01b0360405191168152a1565b6805345cdf77eb68f44c908154670de0b6b3a764000092838201918210614b3657556387a211a2600c526000526020600c20818154019055602052600c5160601c60007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef602080a3565b63e5cfe9576000526004601cfd5b6805345cdf77eb68f44c805490838201918210614b3657556387a211a2600c526000526020600c20818154019055602052600c5160601c60007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef602080a3565b906387a211a2600c52816000526020600c2091825491828111610ba257600093816001600160a01b03940390556805345cdf77eb68f44c8181540390558352167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef602083a3565b6000908190815b60038410614c2f575b505081614c2c916010549003613e03565b91565b9092614c48611605826000526004602052604060002090565b6001600160a01b0381168015614d3c57614c75826001600160a01b03166000526005602052604060002090565b546040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152916020908190849060249082905afa80156110b2578894614ce794610f51938993614d17575b5050611719906001600160a01b0316600052600e602052604060002090565b80614cf9575b50506001019290614c12565b9361174d614d0d92610f4160019597613b7d565b9290508338614ced565b6117199293509081614d3492903d106117895761177b8183611da4565b919038614cc8565b505092614c1b565b670de0b6b3a7640000907812725dd1d243aba0e75fe645cc4873f9e65afe688c928e1f218111820215830215614d7957020490565b637c5f487d6000526004601cfd5b8181029291600082127f800000000000000000000000000000000000000000000000000000000000000082141661373157818405149015171561373157565b806fffffffffffffffffffffffffffffffff1060071b81811c67ffffffffffffffff1060061b1781811c63ffffffff1060051b1781811c61ffff1060041b1781811c60ff1060031b176000821315615032576112239282827ff8f9f9faf9fdfafbf9fdfcfdfafbfcfef9fafdfafcfcfbfefafafcfbffffffff6f8421084210842108cc6318c6db6d54be61502d9661501f961c1c601f161a1890811b609f1c7ffffffffffffffff5f6af8f7b3396644f18e157960000000000000000000000006060917fffffffffffffffffffffffffffffffffffffff465fda27eb4d63ded474e5f832816c465772b2bbbb5f824b15207a30018202841d6d0388eaa27412d5aca026815d636e018202841d6d0df99ac502031bf953eff472fdcc018202841d6d13cdffb29d51d99322bdff5f2211018202841d6d0a0f742023def783a307a986912e018202841d6d01920d8043ca89b5239253284e42018202841d6c0b7a86d7375468fac667a0a5270193827ffffffffffffffffffffffffffffffffffffffdc7b88c420e53a9890533129f6f817fffffffffffffffffffffffffffffffffffffff73c0c716a594e00d54e3c4cbc9818080806c29508e458543d8aa4df2abee780102871d6d0139601a2efabe717e604cbb48940102861d6d02247f7a7b6594320649aa03aba10102851d0102831d0102901d01020105711340daa0d5f769dba1915cef59f0815a55060290609f037d0267a36c0c95b3975ab3ee5b203a7614a3f75373f047d803ae7b6687f2b302017d57115e47018c7177eebf7cd370a3356a1b7863008a5ae8028c72b88642840160ae1d614d87565b670de0b6b3a7640000900590565b61596f565b631615e6386000526004601cfd5b8060001904600211810261505f57670de0b6b3a76400009060011b0490565b63bac65e5b6000526004601cfd5b9080600019048211810261505f57670de0b6b3a764000091020490565b93906150e6927fffffffff0000000000000000000000000000000000000000000000000000000060649360405196848895602087019a8b378501936020850152604084015260e01b166060820152036044810184520182611da4565b51902090565b9081600052600d6020526001600160a01b036040600020541661515f5761514d91600052600d6020526040600020906001600160a01b03167fffffffffffffffffffffffff0000000000000000000000000000000000000000825416179055565b600c5490810180911161373157600c55565b60046040517fed778779000000000000000000000000000000000000000000000000000000008152fd5b92909283018084116137315761519f9083613b9a565b670de0b6b3a7640000908181029080820483149015171561373157826151c491614dc6565b93806151d2575b5050505090565b6151dd930202614dc6565b9003388080806151cb565b67ffffffffffffffff16670a688906bd8b00008111610437576020817fb77b18869f1146e7805c1d2169aa277954f24055acb20c3e15ddc3de57eacb85927fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000006008541617600855604051908152a1565b9092918361526591613b9a565b91670de0b6b3a76400009283810290808204851490151715613731578161528b91614dc6565b91820391808311613731576152a6612cf8916152ac9461534b565b916143fe565b8103908111613731576112239161506d565b601c600060649281946020966040519860605260405260601b602c526f23b872dd000000000000000000000000600c525af13d15600160005114171615615309576000606052604052565b637939f4246000526004601cfd5b67ffffffffffffffff60085416918261532f57505050565b6134d39261533c9161506d565b90615345613757565b906149bc565b670de0b6b3a7640000907812725dd1d243aba0e75fe645cc4873f9e65afe688c928e1f218111820215830215614d79570290808204910615150190565b9461ffff946112239a989460ff6153b26001600160a01b03969c9a95610100808c528b0190613c45565b9b1660208901526040880152606087015260808601521660a08401521660c082015260e08185039101526136c8565b9a96918b61ffff9a966101209c989f9e9a9661541a6154289460ff986001600160a01b03976101409087528060208801528601916136c8565b9260408185039101526136c8565b9c1660608b015216608089015260a088015260c087015260e086015261010085015216910152565b9899909997969795939294956154706001600160a01b038a161515613578565b61549b7f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8710613578565b6154aa610a4d87601054613bad565b6154c2610faa610faa6002546001600160a01b031690565b906154cd8886613b5f565b91803b1561043757848c61551a8f968b958e8c996000996040519b8c9a8b998a997fd6512967000000000000000000000000000000000000000000000000000000008b5260048b01615388565b039134905af180156110b2576155d7575b50604088019661553b888a613abe565b8b6155468987613b5f565b884363ffffffff16936155589561585a565b908a6155648886613b5f565b9161556e936156f0565b61557a8230338c6152be565b615584858a615317565b6155916020890189613abe565b99909761559e908a613abe565b906040519b8c9b359a6155b19b8d6153e1565b037f39d3d3ef1ca8c28e2940bcde183fe626d94dca2df8d9ba3bdcd7a91caa31e36191a1565b806110a66155e492611d6f565b3861552b565b92909282018083116137315761560392610f4191614d44565b7ffffffffffffffffffffffffffffffffffffffffffffffffff21f494c589c00008101908113600116613731576112239161506d565b600052600d6020526040600020908154916001600160a01b038316928315610437577fffffffffffffffffffffffff0000000000000000000000000000000000000000169055600c5403600c5590565b90600090828252600d6020526001600160a01b03908160408420541661515f576040938352600d60205283832060017fffffffffffffffffffffffff0000000000000000000000000000000000000000825416179055168152600b60205220908154019055565b919091600091818352600d6020526001600160a01b03918260408520541661515f57604094615756918552600d602052858520906001600160a01b03167fffffffffffffffffffffffff0000000000000000000000000000000000000000825416179055565b168152600b60205220908154019055565b600a549061579e8261579261578760075465ffffffffffff9060601c1690565b65ffffffffffff1690565b42030262015180900490565b906006548281111561580657906157b491613b0f565b0390811161499257600780547fffffffffffffffffffffffffffff000000000000ffffffffffffffffffffffff164260601b71ffffffffffff000000000000000000000000161790556134d390600655565b50809291501161499257600780547fffffffffffffffffffffffffffff000000000000ffffffffffffffffffffffff164260601b71ffffffffffff000000000000000000000000161790556134d390600655565b94917fffffffff000000000000000000000000000000000000000000000000000000006078937fffffffffffffffffffffffffffffffffffffffff0000000000000000000000006150e6969760405198868a97602089019c8d378701956020870152604086015260601b16606084015260e01b166074820152036058810184520182611da4565b600052600d6020526040600020918254906001600160a01b038216938415610437577fffffffffffffffffffffffff0000000000000000000000000000000000000000615944931690556001600160a01b0316600052600b602052604060002090565b90815403905590565b81600019048111820261505f5702670de0b6b3a7640000808204910615150190565b7ffffffffffffffffffffffffffffffffffffffffffffffffdc0d0570925a462d7811315615b3657680755bf798b4a1bf1e5811215615b28576503782dace9d990604e1b0574029d9dc38563c32e5c2f6dc192ee70ef65f9978af36bb17217f7d1cf79abc9e3b3989179d835ebba824c98fb31b83b2ca45c0000000000000000000000006060916b8000000000000000000000008582851b0501831d94850290036e0587f503bb6ea29d25fcb740196450816c10fe68e7fd37d0007b713f7650810102841d936e05180bb14799ab47a8a8cb2a527d57837ffffffffffffffffffffffffffffffffffffd38dc772608b0ae56cce01296c0eb816db1bbb201f443cf962f1a1d3db4a5817fffffffffffffffffffffffffffffffffffffe5adedaa1cb095af9e4da10e363c816d0277594991cfc85f6e2461837cd9817fffffffffffffffffffffffffffffffffffffffdbf3ccf1604d263450f02a55048101028a1d0102881d0102861d0102841d0102821d01947ffffffffffffffffffffffffffffffffffffffe2c69812cf03b0763fd454a8f7e846d02d16720577bd19bf614176fe9ea830192010102901d01020105029060c3031c90565b63a37bfec96000526004601cfd5b5060009056fea26469706673582212205b620e5c19cd34ebff19ce0d6221c4cb20ca382d3b6b735234817ac60f7e822764736f6c6343000816003300000000000000000000000000000000e5e81e25aead7fccb4c9560c6b5b718f000000000000000000000000000000575b0d9cc6ddbd8990db4d845fe480281f
Deployed Bytecode
0x6080604052600436101561001257600080fd5b60003560e01c8063033597b21461042757806306fdde0314610422578063095ea7b31461041d57806309de4fea146104185780630bc350d714610413578063119f8e681461040e578063128581001461040957806313193e6a1461040457806316604f4f146103ff57806318160ddd146103fa5780631fd1602b146103f5578063202ad2c5146103f057806323b872dd146103eb57806324351d57146103e65780632dd31000146103e15780632f48ed57146103dc578063313ce567146103d757806332a3385e146103d257806334420dbd146103cd5780633644e515146103c857806336ae087e146103c357806337fd5135146103be57806339a391de146103b95780633b49580d146103b45780633cf183fa146103af5780634273601c146103aa57806346c3a2fd146103a5578063505b0c12146103a0578063586f98001461039b5780635c459a5b1461039657806364d1e1c01461039157806366ae79e61461038c5780636caea8a3146103875780636d0f691b146103825780636defbf801461037d57806370a08231146103785780637265563114610373578063739fc9bc1461036e5780637ecebe0014610369578063818431be1461036457806386f25e4d1461035f578063904e0a011461035a5780639584c8881461035557806395d89b4114610350578063994e1ada1461034b5780639cf80f20146103465780639d29db4514610341578063a57ecf4f1461033c578063a9059cbb14610337578063aa14786214610332578063ac9650d81461032d578063b22889e414610328578063b9ff629b14610323578063bf5086421461031e578063c86380d914610319578063c8d710d514610314578063c90da0131461030f578063d505accf1461030a578063dd62ed3e14610305578063de6bbd9d14610300578063e6b91aba146102fb578063e75552fb146102f6578063eb80cd11146102f1578063f71f4026146102ec5763f754fc35146102e757600080fd5b613365565b613341565b6132d8565b612fc9565b612fab565b612f1d565b612ed6565b612d25565b612cfe565b612cc9565b612bbb565b612b94565b612b28565b612a3e565b612985565b612964565b6128db565b612848565b6127f3565b6127c9565b6126b4565b6125c1565b61259b565b612566565b6124f1565b6124d8565b6124a1565b612463565b612445565b61240e565b6123bd565b612379565b61234e565b6122bd565b61224e565b611e2e565b611d07565b611b16565b611aeb565b611ad0565b6117ad565b611226565b61111e565b6110eb565b610df6565b610d5e565b610cee565b610cb0565b610c94565b610c57565b610c13565b610bd5565b610b01565b610aa9565b610951565b6108d1565b610845565b610763565b6106f8565b610611565b6105eb565b6105b2565b6104e6565b6104a9565b61043c565b600091031261043757565b600080fd5b34610437576000600319360112610437576020600a54604051908152f35b60005b83811061046d5750506000910152565b818101518382015260200161045d565b601f19601f604093602084526104a2815180928160208801526020888801910161045a565b0116010190565b34610437576000600319360112610437576104d16104c5613494565b6040519182918261047d565b0390f35b6001600160a01b0381160361043757565b3461043757604060031936011261043757600435610503816104d5565b60243590602052637f5e9f20600c5233600052806034600c2055600052602c5160601c337f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560206000a3602060405160018152f35b6004359067ffffffffffffffff8216820361043757565b6084359067ffffffffffffffff8216820361043757565b6044359067ffffffffffffffff8216820361043757565b359067ffffffffffffffff8216820361043757565b34610437576020600319360112610437576105cb610558565b6001600160a01b0360085460401c163303610437576105e99061482b565b005b346104375760006003193601126104375760206106066148be565b60011c604051908152f35b3461043757608060031936011261043757600435602435610631816104d5565b604435907f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821015610437576001600160a01b039081600254163303610437576104d1937fd4228165b1b0dc50bd8ac0a74d2b5766000d5ee9f7488b9e74e183deb55c8f1d60606106e2946106a960643588876148fd565b966106b5888787615689565b60405191861682526020820152866040820152a26001600160a01b0316600052600e602052604060002090565b8054820190556040519081529081906020820190565b3461043757600060031936011261043757602065ffffffffffff60075460301c16604051908152f35b9181601f840112156104375782359167ffffffffffffffff8311610437576020838186019501011161043757565b610104359063ffffffff8216820361043757565b34610437576101206003193601126104375767ffffffffffffffff60243581811161043757610796903690600401610721565b6064929192356107a5816104d5565b60e435928311610437576104d1936107c46107e8943690600401610721565b9290916107cf61074f565b9460c4359260a43592608435926044359160043561357f565b6040519081529081906020820190565b9060a060031983011261043757600435916024359067ffffffffffffffff82116104375761082891600401610721565b9091604435906064359060843563ffffffff811681036104375790565b3461043757610853366107f8565b9490926001600160a01b0360029593955416330361043757858486836108b5836108b0816108ab6108cc9e7f97cc161fb90f5cdec9c65ba7aac2279e32df11368946590b82fd6fe8e76b39e09d886108c19c8f61508a565b615639565b614b44565b604051968796876147f5565b0390a1601054613718565b601055005b346104375760006003193601126104375760206805345cdf77eb68f44c54604051908152f35b9060c060031983011261043757600435916024359067ffffffffffffffff82116104375761092791600401610721565b9091604435906064359060843561093d816104d5565b9060a43563ffffffff811681036104375790565b346104375761095f366108f7565b929495936001600160a01b039291928060025416330361043757610a0a60008061099987876109948b8f8f84908c879361585a565b6158e1565b5a946040519060208201927fa9059cbb000000000000000000000000000000000000000000000000000000008452166024820152876044820152604481526109e081611d88565b519082897f8000000000000000000000000000000000000000000000000000000000000000f11590565b610a52575b6105e9610a4d887fcab6c1a18a9c89efaab5ea5a8c665ffe2c5aac9ddd9301ccad01fd4fed7c7e3d8b8a6108c18b8b8b878c60405197889788614a05565b601055565b610a6d610a66989497969395985a92613b6c565b603f900490565b11610a7f573896939194959296610a0f565b60046040517fdd629f86000000000000000000000000000000000000000000000000000000008152fd5b34610437576000600319360112610437576020610ac4613757565b6001600160a01b0360405191168152f35b600319606091011261043757600435610aed816104d5565b90602435610afa816104d5565b9060443590565b3461043757610b0f36610ad5565b8260601b91602092338452600c90637f5e9f2081178252603482209081549160018301610bb0575b506387a211a2915017815283812092835492838211610ba2577fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef94826001600160a01b039503905560005284822081815401905584525160601c93169180a360405160018152602090f35b63f4d678b86000526004601cfd5b828611610bc757856387a211a29303905538610b37565b6313be252b6000526004601cfd5b34610437576020600319360112610437576001600160a01b03600435610bfa816104d5565b16600052600b6020526020604060002054604051908152f35b346104375760006003193601126104375760206040516001600160a01b037f00000000000000000000000000000000e5e81e25aead7fccb4c9560c6b5b718f168152f35b3461043757602060031936011261043757600435610c74816104d5565b6001600160a01b03610c84614394565b163303610437576105e990614a4a565b3461043757600060031936011261043757602060405160128152f35b34610437576020600319360112610437576001600160a01b03600435610cd5816104d5565b1660005260056020526020604060002054604051908152f35b34610437576101006003193601126104375760243567ffffffffffffffff811161043757610d20903690600401610721565b60443591610d2d836104d5565b60e4359063ffffffff82168203610437576104d1936107e89360c4359260a4359260843592606435926004356137ea565b3461043757600060031936011261043757602060a0610d7b613494565b828151910120604051907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f8252838201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6604082015246606082015230608082015220604051908152f35b90816101409103126104375790565b60c060031936011261043757600467ffffffffffffffff813581811161043757610e239036908401610de7565b9160243591366084116104375760843590610e3d826104d5565b60a43590811161043757610e549036908401610721565b68929eee149b4bd2126894919492308454146110de573084558635966020810190610e89610e828383613abe565b3691612276565b9689600052600360205260ff610eb3602060409a8b600020828d519483868095519384920161045a565b8201908152030190205416156110b757610ed76001600160a01b0385161515613578565b610ee18633614ba4565b610f57610f46610f51610eff610ef9600f5460070b90565b60070b90565b610f4b610f0b82614c0b565b949092610f418d610f3c610f3582610f306805345cdf77eb68f44c54600c5490613b0f565b613b0f565b9182613b0f565b614d44565b614dc6565b613b32565b9061506d565b90613b9a565b98610f837f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8b10613578565b610f92610a4d8b601054613bad565b610fb6610faa610faa6002546001600160a01b031690565b6001600160a01b031690565b803b156104375783600093610ffb8a998e958e519c8d97889687967f318987c40000000000000000000000000000000000000000000000000000000088528701613d44565b039134905af19081156110b2576104d199611088967f8c9503be4db35b4e3d31565a9616d1dc3f1b3024e5e9e9d65052de46a5149f1c93611099575b506110808a878b85018c61107361106b6110648686611056878d613abe565b4363ffffffff16939161508a565b9a89613abe565b939098613abe565b9290915197889788613d7f565b0390a16150ec565b389055519081529081906020820190565b806110a66110ac92611d6f565b8061042c565b38611037565b61374b565b87517f2c64c1b2000000000000000000000000000000000000000000000000000000008152fd5b8463ab143c06600052601cfd5b3461043757604060031936011261043757602061111660043561110d816104d5565b60243590613e12565b604051908152f35b346104375760e06003193601126104375767ffffffffffffffff60043581811161043757611150903690600401610721565b60243583811161043757611168903690600401610721565b93604435611175816104d5565b6064359182168203610437576105e99561118d61056f565b9360a4359561119b876104d5565b60c435976111a8896104d5565b613ef3565b9181601f840112156104375782359167ffffffffffffffff8311610437576020808501948460051b01011161043757565b90815180825260208080930193019160005b8281106111fe575050505090565b8351855293810193928101926001016111f0565b9060206112239281815201906111de565b90565b346104375760606003193601126104375767ffffffffffffffff60046024358281116104375761125990369083016111ad565b9190926044359081116104375761127390369083016111ad565b92903068929eee149b4bd2126854146117a0579293903068929eee149b4bd21268556112a0833533614ba4565b6112af610ef9600f5460070b90565b936112b86142ab565b916112c16142ab565b926000805b600382106115e5575b90610f516112e58261131d946010549003613e03565b610f4b6113188c610f418d610f3c6113106805345cdf77eb68f44c54610f30843591600c5490613b0f565b913582613b5f565b613b1c565b97611326614315565b9760009586975b60038810611408575b5050505050505050836113cf576104d1935061135c61135782600a54613b5f565b600a55565b600654908082116113c05750506113736000600655565b7f7a5919fae19c7104c67635ca0c2ded0d01316a06da859fd961851aa12ac6c71b604051806113a58533953583614373565b0390a23868929eee149b4bd212685560405191829182611212565b6113ca9103600655565b611373565b6040517f0289311f00000000000000000000000000000000000000000000000000000000815280830185815281906020010390fd5b0390fd5b909192939495969761142d610faa6114208b896142ff565b516001600160a01b031690565b156115df576114476114408a8985614330565b358d61506d565b9b8c1561153d578c61145891613b5f565b9b6114638a886142ff565b516001600160a01b03166000908152600560205260409020549085826114898d886142ff565b5161149393615258565b8061149f8c898d614330565b35116114f257916114db6114e192848f818f6114d16114208f9260019b6114c9826114d698614340565b5233936142ff565b6149bc565b613b9a565b90613b0f565b9801955b949392919096959661132d565b8b6114046115018d8a8e614330565b604080517f24557f0500000000000000000000000000000000000000000000000000000000815293840194855290356020850152919283920190565b9b509761154b818884614330565b356115b65761155b81868a614330565b3561156957600101956114e5565b6115758a91868a614330565b35906114046040519283927f24557f050000000000000000000000000000000000000000000000000000000084528301919060206040840193600081520152565b896040517fb8003bfa000000000000000000000000000000000000000000000000000000008152fd5b97611336565b90611612611605829b94959896979a9b6000526004602052604060002090565b546001600160a01b031690565b6001600160a01b038116801561179057906116a99161164382611635868a6142ff565b906001600160a01b03169052565b60208b611663846001600160a01b03166000526005602052604060002090565b549260405180809781947f70a08231000000000000000000000000000000000000000000000000000000008352309083019190916001600160a01b036020820193169052565b03915afa9182156110b2578c611720938f9592610f519360009261175d575b5061171991926116ff896116f96116f2856001600160a01b0316600052600b602052604060002090565b5487613b5f565b926142ff565b526001600160a01b0316600052600e602052604060002090565b5490613b5f565b80611739575b50506001019098979493959291986112c6565b9261174d61175392610f4160019596613b7d565b90613bad565b9190508938611726565b61171992506117839060203d602011611789575b61177b8183611da4565b810190613dc5565b916116c8565b503d611771565b50509098979493959291986112cf565b8263ab143c06600052601cfd5b346104375760806003193601126104375767ffffffffffffffff60048035828111610437576117e09036906004016111ad565b602493919335828111610437576117fe9094939436906004016111ad565b919093611809610586565b946119246064359561181a876104d5565b806001600160a01b03986118518a7f00000000000000000000000000000000e5e81e25aead7fccb4c9560c6b5b718f163314613578565b60008052600460205261188e8a6118877f17ef568e3e12ab5b9c7254a8d58478811de00f9e6eb34345acd53bf8fd09d3ec611605565b1615613578565b16670de0b6b3a76400006118a3818310613578565b031660070b6118e2817fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000600f54169067ffffffffffffffff1617600f55565b7fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff600f549160401b6fffffffffffffffff000000000000000016911617600f55565b61192c614315565b9660009485945b80861061198657897f7dde447513a4ed2580f1f8cd3caea2d0c14b2f46b036d72456a33457da14ed758a8a6119678b600a55565b61197081614acc565b611981604051928392169482614354565b0390a2005b909192939495886119a061199b89858a614330565b61438a565b916119ec836119b98b6000526004602052604060002090565b906001600160a01b03167fffffffffffffffffffffffff0000000000000000000000000000000000000000825416179055565b6119f7898689614330565b3592611a04841515613578565b83611a22826001600160a01b03166000526005602052604060002090565b556040517f70a08231000000000000000000000000000000000000000000000000000000008152308882019081526020949192859284928390038401918391165afa80156110b2576001948b8f6114db94611a9d97600095611aa9575b50508391611a9791611a92841515613578565b614340565b52613b9a565b96019493929190611933565b611a97929395509081611ac792903d106117895761177b8183611da4565b93919038611a7f565b34610437576000600319360112610437576020610ac4614394565b3461043757600060031936011261043757602067ffffffffffffffff60075460901c16604051908152f35b3461043757608060031936011261043757600435611b33816104d5565b60243590611b40826104d5565b604435916064359168929eee149b4bd212689130835414611cf957308355611b8e611b88611b7b60075467ffffffffffffffff9060901c1690565b67ffffffffffffffff1690565b8661506d565b611ba2611b9b8288613b5f565b83856144db565b94858111611cbf5750947ff631545f16e5f3e54a6cf8b4e2bfe643a342d0d0bf8e224479382b8acdfd009a91611bf26104d197611be1843033896152be565b611bec8833856149bc565b85615317565b611c19611c12856001600160a01b03166000526005602052604060002090565b5483613b9a565b611c40611c39836001600160a01b03166000526005602052604060002090565b5488613b9a565b81811115611ca257611c58611c609261135792613b5f565b600a54613b5f565b604080516001600160a01b03958616815294909116602085015283015260608201849052339180608081015b0390a23890556040519081529081906020820190565b611cb261135791611cba93613b5f565b600a54613b0f565b611c60565b6040517f24557f05000000000000000000000000000000000000000000000000000000008152600481018790526024810191909152604490fd5b63ab143c066000526004601cfd5b3461043757602060031936011261043757611d20610558565b6001600160a01b03611d30614394565b163303610437576105e9906151e8565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b67ffffffffffffffff8111611d8357604052565b611d40565b6080810190811067ffffffffffffffff821117611d8357604052565b90601f601f19910116810190811067ffffffffffffffff821117611d8357604052565b81601f820112156104375780359160209167ffffffffffffffff8411611d83578360051b9060405194611dfc85840187611da4565b85528380860192820101928311610437578301905b828210611e1f575050505090565b81358152908301908301611e11565b346104375760408060031936011261043757600480359160243567ffffffffffffffff811161043757611e65903690600401611dc7565b9268929eee149b4bd212689130835414611cf957308355611e868233614ba4565b611e95610ef9600f5460070b90565b93611e9e6142ab565b90611ea76142ab565b926000805b600381106120e8575b601054611ec29203613e03565b96611ecb614315565b9781611f02611eeb89610f306805345cdf77eb68f44c54600c5490613b0f565b611efd611ef88b83613b5f565b613b7d565b613e03565b806120d1575050905b600095611f17826143fe565b91875b60038110611fa8575b50505050505050506104d19450611f3f61135782600a54613b5f565b60065490808211611f99575050611f566000600655565b7f7a5919fae19c7104c67635ca0c2ded0d01316a06da859fd961851aa12ac6c71b60405180611f8786339583614373565b0390a238905560405191829182611212565b611fa39103600655565b611f56565b611fb5611420828a6142ff565b6001600160a01b038116156120cb578d90611fdd84610f41611fd786896142ff565b51613b7d565b9a611fe884876142ff565b519b808910612097575b50836120296120048e61202f94613b0f565b9d612022856001600160a01b03166000526005602052604060002090565b5490613e03565b93614340565b5182811161205a575081612054918f9361204c8660019796614340565b5233906149bc565b01611f1a565b88517f24557f05000000000000000000000000000000000000000000000000000000008152808b0184815260208101929092529081906040010390fd5b6120296120046120c161202f949f610f4b6113188d8f886120bc610f41928f9b613b5f565b61534b565b9e93505050611ff2565b50611f23565b6113186120e29392610f4b92614dc6565b90611f0b565b6120ff611605826000526004602052604060002090565b6001600160a01b0381169081156122475761211e81611635858a6142ff565b61213b816001600160a01b03166000526005602052604060002090565b5485517f70a082310000000000000000000000000000000000000000000000000000000081523088820190815290936020918291869182908190850103915afa80156110b2578d946121979260009261222a575b505082613b9a565b916121c86121c2836121bc846001600160a01b0316600052600b602052604060002090565b54613b9a565b84613b5f565b6121d2868c6142ff565b52826121e5575b50505050600101611eac565b92610f41611ef8600196979461221861174d956121bc61221e996001600160a01b0316600052600e602052604060002090565b90613b5f565b919050883880806121d9565b6122409250803d106117895761177b8183611da4565b388061218f565b5050611eb5565b3461043757600060031936011261043757602067ffffffffffffffff60085416604051908152f35b92919267ffffffffffffffff8211611d8357604051916122a06020601f19601f8401160184611da4565b829481845281830111610437578281602093846000960137010152565b346104375760406003193601126104375760243567ffffffffffffffff811161043757366023820112156104375761233c61232c602061230a6104d1943690602481600401359101612276565b600435600052600382526040600020826040519483868095519384920161045a565b8201908152030190205460ff1690565b60405190151581529081906020820190565b34610437576040600319360112610437576020611116600435612370816104d5565b60243590614418565b346104375760006003193601126104375760206040516001600160a01b037f000000000000000000000000000000575b0d9cc6ddbd8990db4d845fe480281f168152f35b346104375760008060031936011261240b576020906001600160a01b0380600954161591826123f3575b50506040519015158152f35b604091925080805260048452205416151538806123e7565b80fd5b346104375760206003193601126104375760043561242b816104d5565b6387a211a2600c52600052602080600c2054604051908152f35b34610437576000600319360112610437576020600c54604051908152f35b34610437576020600319360112610437576001600160a01b03600435612488816104d5565b16600052600e6020526020604060002054604051908152f35b34610437576020600319360112610437576004356124be816104d5565b6338377508600c52600052602080600c2054604051908152f35b346104375760206111166124eb36610ad5565b916144db565b346104375760008060031936011261240b576009546001600160a01b0381163303612562577fffffffffffffffffffffffff0000000000000000000000000000000000000000166009557f7991f9d379def473bbda7d0d566449ae0c4b9edb031c33f829df029783f680a48180a180f35b5080fd5b3461043757602060031936011261043757600435600052600460205260206001600160a01b0360406000205416604051908152f35b3461043757600060031936011261043757602065ffffffffffff60075416604051908152f35b346104375760008060031936011261240b57604051908060018054906125e682613441565b80865292602092600181169081156126695750600114612611575b6104d1866104c581880382611da4565b9350600184527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b838510612656575050505081016020016104c5826104d138612601565b8054868601840152938201938101612639565b8796506104d1979450602093506104c59592507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091501682840152151560051b820101929338612601565b346104375760008060031936011261240b5780805b600382106126d9575b600a555080f35b6126f0611605836000526004602052604060002090565b906001600160a01b0382169081156127c1576040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152926020928390859060249082905afa9081156110b25761279561277b6114db9360019761279c978b926127a4575b5050611719846001600160a01b0316600052600b602052604060002090565b916001600160a01b03166000526005602052604060002090565b5490613b9a565b9101906126c9565b6127ba9250803d106117895761177b8183611da4565b388061275c565b9150506126d2565b346104375760006003193601126104375760206008546001600160a01b036040519160401c168152f35b3461043757602060031936011261043757600435600052600d60205260206001600160a01b0360406000205416604051908152f35b6044359060ff8216820361043757565b6084359060ff8216820361043757565b6101206003193601126104375767ffffffffffffffff60043581811161043757612876903690600401610de7565b90602435612883816104d5565b61288b612828565b9260c435612898816104d5565b60e4359061ffff821682036104375761010435948511610437576104d1956128c76107e8963690600401610721565b95909460a435926084359260643592614646565b34610437576040600319360112610437576004356128f8816104d5565b602435906387a211a2600c52336000526020600c208054808411610ba25783900390556000526020600c20818154019055602052600c5160601c337fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef602080a360405160018152602090f35b34610437576000600319360112610437576020600f5460070b604051908152f35b34610437576020806003193601126104375760043567ffffffffffffffff8111610437576129b79036906004016111ad565b9060009260208452826020528215612a3957909160051b90604082848237828101925b8151850191868460408401948035918291018637389085305af415612a305781848267ffffffffffffffe094603f945201933d90523d88606083013e3d0101169383821015612a2957936129da565b6040850186f35b863d81803e3d90fd5b604084f35b346104375760606003193601126104375760043560243567ffffffffffffffff811161043757612a72903690600401610721565b91604435928315158403610437576001600160a01b036009541633036104375760418103610437577fd3223b577ecd2d8632a35c20b084999e9f3d352d8924beb1d32f42e0bd66e9a593612b2391836000526003602052612b1782604060002060206040518092868b8337868201908152030190209060ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0083541691151516179055565b6040519485948561472c565b0390a1005b3461043757608060031936011261043757604435606435612b48816104d5565b6001600160a01b03908160025416330361043757612b6981846004356158e1565b50612b78602435601054613bad565b60105516600052600e6020526040600020908154039055600080f35b346104375760006003193601126104375760206001600160a01b0360025416604051908152f35b346104375760c060031936011261043757600435612bd8816104d5565b60443590606435612be8816104d5565b60a43567ffffffffffffffff811161043757612c08903690600401610721565b6001600160a01b03600254163303610437576020612c2d60ff93612c4f933691612276565b608435600052600382526040600020826040519483868095519384920161045a565b820190815203019020541615612c9f57612c7b83612c9493612c7484836024356158e1565b50836149bc565b6001600160a01b0316600052600e602052604060002090565b908154039055600080f35b60046040517f2c64c1b2000000000000000000000000000000000000000000000000000000008152fd5b34610437576000600319360112610437576020611116600f5460070b612cf8612cf182614c0b565b50916143fe565b90614dc6565b346104375760006003193601126104375760206001600160a01b0360095416604051908152f35b346104375760e060031936011261043757600435612d42816104d5565b60243590612d4f826104d5565b6044359060643592612d5f612838565b92612d68613494565b90815160208093012090864211612ec857604051946001600160a01b0380911694169465383775081901600e5260009685885260c085600c209283549a7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82528782019687528b60408301977fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc689528b6060850199468b528c608087019330855260a08820602e527f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9885252528789525260a082015220604e526042602c20885260ff16845260a43560405260c435606052838060808960015afa853d5103612ebb577f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259596979801905585777f5e9f200000000000000000000000000000000000000000176040526034602c2055a380f35b63ddafbaef88526004601cfd5b631a15a3cc6000526004601cfd5b3461043757604060031936011261043757600435612ef3816104d5565b602435612eff816104d5565b602052637f5e9f20600c5260005260206034600c2054604051908152f35b6101006003193601126104375767ffffffffffffffff60043581811161043757612f4b903690600401610de7565b9060243591612f59836104d5565b612f61612828565b60a435612f6d816104d5565b60c4359061ffff821682036104375760e435948511610437576104d195612f9b6107e8963690600401610721565b9590946084359260643592614753565b34610437576000600319360112610437576020601054604051908152f35b34610437576040806003193601126104375760049060043567ffffffffffffffff811161043757612ffe903690600401611dc7565b906024359268929eee149b4bd212689130835414611cf957308355613028610ef9600f5460070b90565b9160009182918391845b6003811061314f575b5050506130b26130ca94939261306d613068846130606113576130b897600a54613b0f565b600654613b0f565b600655565b6010549003926130806000821215613578565b6007546130999060901c67ffffffffffffffff16611b7b565b670de0b6b3a76400000302670de0b6b3a7640000900490565b926143fe565b916805345cdf77eb68f44c54906155ea565b91828411613112576104d193506130e18333614b44565b7f7dde447513a4ed2580f1f8cd3caea2d0c14b2f46b036d72456a33457da14ed7560405180611c8c33948783614373565b50506040517f24557f0500000000000000000000000000000000000000000000000000000000815260048101919091526024810191909152604490fd5b613166611605826000526004602052604060002090565b936001600160a01b0385169081156132d057613195866001600160a01b03166000526005602052604060002090565b54976131a1848d614340565b5185517f70a082310000000000000000000000000000000000000000000000000000000081523088820190815291946020928391839182908190850103915afa9081156110b2576131fc926000926132b3575b50508a613b9a565b8a6000918b81613269575b5085156132585761323e8694613245946132378f95610f41611ef86114db976114db60019f9e61324f9e9b613b9a565b9103613bad565b9b84613b9a565b96309033906152be565b01915b91613032565b505050975094505060010191613252565b61329d935091610f41611ef88361221861174d959f968f6121bc906001600160a01b0316600052600e602052604060002090565b978a6132ac81610f4184613b7d565b918b613207565b6132c99250803d106117895761177b8183611da4565b38806131f4565b94505061303b565b34610437576132e6366107f8565b906001600160a01b0360029694939654163303610437578583613334836108ab86827f8a49f1dbb0b988d0421183f74b9866ce7c88256f1b88cf865bf7f3a74706fe689c612b239a8d61508a565b50604051968796876147f5565b34610437576000600319360112610437576020600f546040519060401c60070b8152f35b3461043757613373366108f7565b94919590936001600160a01b036002541633036104375785858886846133ca84846109946133f39e83837fe6db00361b6a35af0ded81ba5696c1633e945a81008cd7da44fb8a78422a7d429f8f9d6133d79e61585a565b5060405197889788614a05565b0390a16001600160a01b03166000526005602052604060002090565b54026006548180821160001461342c5761340d9103600655565b600a549081019081101561342757506105e9600019600a55565b600a55005b501561340d5761343c6000600655565b61340d565b90600182811c9216801561348a575b602083101461345b57565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b91607f1691613450565b60405190600082600054916134a883613441565b8083529260209060019081811690811561353557506001146134d5575b50506134d392500383611da4565b565b915092600080527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563936000925b82841061351d57506134d394505050810160200138806134c5565b85548885018301529485019487945092810192613502565b9050602093506134d39592507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091501682840152151560051b82010138806134c5565b1561043757565b969197949098929a999568929eee149b4bd212689b308d5414611cf957308d556001600160a01b0380600254163303610437576135bd368c8e612276565b918a600052600360205260ff6135e76020604095866000208288519483868095519384920161045a565b82019081520301902054161561369f57600052600460205280826000205416926136129085856148fd565b9b61361e8d89866149bc565b82519b8c809c6101209182918152602001528c019061363c926136c8565b961690890152606088015260808701528760a087015260c086015284820360e0860152613668926136c8565b9063ffffffff16610100830152037f6b7977bd09a2e845fb431e372aac95edfb358014e167149b4f4d09021c87a79d91a191389055565b600483517f2c64c1b2000000000000000000000000000000000000000000000000000000008152fd5b601f8260209493601f19938186528686013760008582860101520116010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8181039291600013801582851316918412161761373157565b6136e9565b908160209103126104375751611223816104d5565b6040513d6000823e3d90fd5b6040517f19b90b0d0000000000000000000000000000000000000000000000000000000081526020816004816001600160a01b037f00000000000000000000000000000000e5e81e25aead7fccb4c9560c6b5b718f165afa9081156110b2576000916137c1575090565b611223915060203d6020116137e3575b6137db8183611da4565b810190613736565b503d6137d1565b9390949691989792959868929eee149b4bd2126899308b5414611cf957308b556001600160a01b0360025416330361043757613827368389612276565b9086600052600360205260ff6138516020604094856000208287519483868095519384920161045a565b820190815203019020541615613a4957613888613873610ef9600f5460070b90565b9161388e61388084614c0b565b9381956143fe565b93613b9a565b926805345cdf77eb68f44c54906138a78486848b6155ea565b9d8e8111613a0757508d91849184613984575b50505050506138ce610a4d86601054613718565b8482111561395b578997946139559a61394d957f7af4b988c9949d39dbe6398b8332fa201574208c2656602a23f1624c428bfe9199956139438f9d9a966139398f979161393361131884610f4161392861393e9786614dc6565b94610f3c8d82613b5f565b9061594d565b615040565b615767565b5198899889613a72565b0390a1614b44565b91389055565b600483517f7c1e66d0000000000000000000000000000000000000000000000000000000008152fd5b83610f3061399f6139bd966114d66139af976139a996614dc6565b93600c5490613b0f565b90613e03565b670de0b6b3a7640000900490565b8082116139cd5782818e926138ba565b84517f24557f0500000000000000000000000000000000000000000000000000000000815260048101919091526024810191909152604490fd5b8e61140488519283927f24557f050000000000000000000000000000000000000000000000000000000084526004840160209093929193604081019481520152565b600482517f2c64c1b2000000000000000000000000000000000000000000000000000000008152fd5b9692613aa260c097936001600160a01b039263ffffffff98949c9b979c8b5260e060208c015260e08b01916136c8565b991660408801526060870152608086015260a085015216910152565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610437570180359067ffffffffffffffff82116104375760200191813603831361043757565b9190820180921161373157565b90670de0b6b3a764000091820391821161373157565b907ffffffffffffffffffffffffffffffffffffffffffffffffff21f494c589c0000820191821161373157565b9190820391821161373157565b908115600183800414171561373157565b90670de0b6b3a76400009182810292818404149015171561373157565b8181029291811591840414171561373157565b9190916000838201938412911290801582169115161761373157565b90357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18236030181121561043757016020813591019167ffffffffffffffff821161043757813603831361043757565b359065ffffffffffff8216820361043757565b35906bffffffffffffffffffffffff8216820361043757565b9061122390613c8f613c7461014085358452613c646020870187613bc9565b90918060208701528501916136c8565b613c816040860186613bc9565b9084830360408601526136c8565b9265ffffffffffff80613ca460608401613c19565b166060840152613cb660808301613c19565b1660808301526001600160a01b0360a0820135613cd2816104d5565b1660a0830152613ce460c08201613c2c565b6bffffffffffffffffffffffff80911660c0840152613d0560e08301613c2c565b1660e083015261010067ffffffffffffffff613d2282840161059d565b1690830152613d3561012080920161059d565b67ffffffffffffffff16910152565b9092613d5f611223969495939560c0845260c0840190613c45565b9460208301526040604481840137608082015260a08185039101526136c8565b9391613da490613db29460c097939a99989a875260e0602088015260e08701916136c8565b9184830360408601526136c8565b9460608201526040604460808301370152565b90816020910312610437575190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b8115613e0d570490565b613dd4565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015291906020836024816001600160a01b0385165afa9283156110b257600093613ec3575b50613ea0613e8864e8d4a51000926001600160a01b03166000526005602052604060002090565b54613e98610ef9600f5460070b90565b908585615189565b92041015613eab5790565b670d2f13f7789f0000670de0b6b3a764000091020490565b64e8d4a51000919350613e88613eea613ea09260203d6020116117895761177b8183611da4565b94925050613e61565b95919396929490967fffffffffffffffffffffffffffffffffffffffffffffffffffffffffbf6011329889548060038c556140b4575b50613f8292613f87959492613f7d926001600160a01b0390817fffffffffffffffffffffffff000000000000000000000000000000000000000093168360025416176002551690600954161760095561482b565b6151e8565b614a4a565b67ffffffffffffffff8411611d83578492600090613fae86613fa98454613441565b6140ee565b8190601f871160011461402a579580613fe192613fe89798859261401f575b50506000198260011b9260031b1c19161790565b90556141d5565b613fef5750565b6002905560016020527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602080a1565b013590503880613fcd565b600080527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5639691601f198316845b818110614099575091613fe897989184600195941061407f575b505050811b0190556141d5565b60001960f88560031b161c19910135169055388080614072565b828401358a556001909901988a985060209283019201614058565b90999260018281979694971c14303b10156140e05760ff9190911b9290921b9892939092613f82613f29565b63f92ee8a96000526004601cfd5b601f81116140fa575050565b600090600080527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563906020601f850160051c83019410614155575b601f0160051c01915b82811061414a57505050565b81815560010161413e565b9092508290614135565b90601f821161416c575050565b60019160009060016000527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6906020601f850160051c830194106141cb575b601f0160051c01915b8281106141c15750505050565b81815583016141b4565b90925082906141ab565b919067ffffffffffffffff8111611d83576001906141fc816141f78454613441565b61415f565b6000601f821160011461423057819061422c93949560009261401f5750506000198260011b9260031b1c19161790565b9055565b6001600052601f198216947fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf691805b8781106142955750838596971061427b575b505050811b019055565b60001960f88560031b161c19910135169055388080614271565b828201358455928501926020918201910161425f565b604051906060820182811067ffffffffffffffff821117611d83576040526060368337565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b9060038110156143105760051b0190565b6142d0565b6040519061432282611d88565b600382526060366020840137565b91908110156143105760051b0190565b80518210156143105760209160051b010190565b90604061122392670de0b6b3a7640000815281602082015201906111de565b6040906112239392815281602082015201906111de565b35611223816104d5565b6040517f8da5cb5b0000000000000000000000000000000000000000000000000000000081526020816004816001600160a01b037f00000000000000000000000000000000e5e81e25aead7fccb4c9560c6b5b718f165afa9081156110b2576000916137c1575090565b8015613e0d576ec097ce7bc90715b34b9f10000000000590565b906040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526020816024816001600160a01b0387165afa9081156110b2576000916144bc575b50614484836001600160a01b0316600052600b602052604060002090565b548103908111613731576144ae611223936001600160a01b03166000526005602052604060002090565b5490600f5460070b92615258565b6144d5915060203d6020116117895761177b8183611da4565b38614466565b6040517f70a0823100000000000000000000000000000000000000000000000000000000808252306004830152909493926001600160a01b039260209283886024818589165afa9788156110b257600098614625575b506040519081523060048201529383908590602490829086165afa80156110b2576145a861458e6145c39264e8d4a51000976145e597600092614608575b5050611719866001600160a01b0316600052600b602052604060002090565b926001600160a01b03166000526005602052604060002090565b54926001600160a01b03166000526005602052604060002090565b54906145e06145d7610ef9600f5460070b90565b80948a89615189565b615258565b930410156145ef57565b90670d2f13f7789f0000670de0b6b3a764000091020490565b61461e9250803d106117895761177b8183611da4565b388061456f565b8491985061463f90823d84116117895761177b8183611da4565b9790614531565b9099979496939198959268929eee149b4bd2126899308b5414611cf957308b5560ff61469d602061467c610e8282880188613abe565b8635600052600382526040600020826040519483868095519384920161045a565b820190815203019020541615612c9f576146c667ffffffffffffffff60075460901c168361506d565b92838303838111613731576146db908e613e12565b8a81106146f2575090899a9b9c6139559a92615450565b6040517f24557f050000000000000000000000000000000000000000000000000000000081526004810191909152602481018b9052604490fd5b929160409261474b9296959685526060602086015260608501916136c8565b931515910152565b989794919592989693909668929eee149b4bd2126899308b5414611cf957308b5560ff6147ab602061478a610e8282870187613abe565b8535600052600382526040600020826040519483868095519384920161045a565b820190815203019020541615612c9f576147d467ffffffffffffffff60075460901c168261506d565b9182820398828a11613731576147ed6139559a8c613e12565b9a8b92615450565b949060809497969263ffffffff9461481a92885260a0602089015260a08801916136c8565b966040860152606085015216910152565b67ffffffffffffffff811690670de0b6b3a76400008211610437577f5b7d342bae9633dbbf79ee2bcab48506e0662e0a74be62192960beab09d2fbc6916020917fffffffffffff0000000000000000ffffffffffffffffffffffffffffffffffff79ffffffffffffffff0000000000000000000000000000000000006007549260901b16911617600755604051908152a1565b600a54620151808165ffffffffffff60075460601c1642030204600654818111156148f8570390818111156148f1570390565b5050600090565b505090565b92916001600160a01b036149118386614418565b9416600052600560205261492a60406000205485613b9a565b600a54908082111561499257806149449203600a55615767565b8381116149585750610a4d90601054613718565b6040517f24557f05000000000000000000000000000000000000000000000000000000008152600481018590526024810191909152604490fd5b60046040517f7c1e66d0000000000000000000000000000000000000000000000000000000008152fd5b60109260209260145260345260446000938480936fa9059cbb00000000000000000000000082525af13d1560018351141716156149f857603452565b6390b8ec1890526004601cfd5b959094614a336001600160a01b039363ffffffff969a999560a0988a5260c060208b015260c08a01916136c8565b986040880152606087015216608085015216910152565b60207f9c1c6bae52abe079778f8408d952941f631f8b1d020e289245851e78f350c817916008547fffffffff0000000000000000000000000000000000000000ffffffffffffffff7bffffffffffffffffffffffffffffffffffffffff00000000000000008360401b169116176008556001600160a01b0360405191168152a1565b6805345cdf77eb68f44c908154670de0b6b3a764000092838201918210614b3657556387a211a2600c526000526020600c20818154019055602052600c5160601c60007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef602080a3565b63e5cfe9576000526004601cfd5b6805345cdf77eb68f44c805490838201918210614b3657556387a211a2600c526000526020600c20818154019055602052600c5160601c60007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef602080a3565b906387a211a2600c52816000526020600c2091825491828111610ba257600093816001600160a01b03940390556805345cdf77eb68f44c8181540390558352167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef602083a3565b6000908190815b60038410614c2f575b505081614c2c916010549003613e03565b91565b9092614c48611605826000526004602052604060002090565b6001600160a01b0381168015614d3c57614c75826001600160a01b03166000526005602052604060002090565b546040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152916020908190849060249082905afa80156110b2578894614ce794610f51938993614d17575b5050611719906001600160a01b0316600052600e602052604060002090565b80614cf9575b50506001019290614c12565b9361174d614d0d92610f4160019597613b7d565b9290508338614ced565b6117199293509081614d3492903d106117895761177b8183611da4565b919038614cc8565b505092614c1b565b670de0b6b3a7640000907812725dd1d243aba0e75fe645cc4873f9e65afe688c928e1f218111820215830215614d7957020490565b637c5f487d6000526004601cfd5b8181029291600082127f800000000000000000000000000000000000000000000000000000000000000082141661373157818405149015171561373157565b806fffffffffffffffffffffffffffffffff1060071b81811c67ffffffffffffffff1060061b1781811c63ffffffff1060051b1781811c61ffff1060041b1781811c60ff1060031b176000821315615032576112239282827ff8f9f9faf9fdfafbf9fdfcfdfafbfcfef9fafdfafcfcfbfefafafcfbffffffff6f8421084210842108cc6318c6db6d54be61502d9661501f961c1c601f161a1890811b609f1c7ffffffffffffffff5f6af8f7b3396644f18e157960000000000000000000000006060917fffffffffffffffffffffffffffffffffffffff465fda27eb4d63ded474e5f832816c465772b2bbbb5f824b15207a30018202841d6d0388eaa27412d5aca026815d636e018202841d6d0df99ac502031bf953eff472fdcc018202841d6d13cdffb29d51d99322bdff5f2211018202841d6d0a0f742023def783a307a986912e018202841d6d01920d8043ca89b5239253284e42018202841d6c0b7a86d7375468fac667a0a5270193827ffffffffffffffffffffffffffffffffffffffdc7b88c420e53a9890533129f6f817fffffffffffffffffffffffffffffffffffffff73c0c716a594e00d54e3c4cbc9818080806c29508e458543d8aa4df2abee780102871d6d0139601a2efabe717e604cbb48940102861d6d02247f7a7b6594320649aa03aba10102851d0102831d0102901d01020105711340daa0d5f769dba1915cef59f0815a55060290609f037d0267a36c0c95b3975ab3ee5b203a7614a3f75373f047d803ae7b6687f2b302017d57115e47018c7177eebf7cd370a3356a1b7863008a5ae8028c72b88642840160ae1d614d87565b670de0b6b3a7640000900590565b61596f565b631615e6386000526004601cfd5b8060001904600211810261505f57670de0b6b3a76400009060011b0490565b63bac65e5b6000526004601cfd5b9080600019048211810261505f57670de0b6b3a764000091020490565b93906150e6927fffffffff0000000000000000000000000000000000000000000000000000000060649360405196848895602087019a8b378501936020850152604084015260e01b166060820152036044810184520182611da4565b51902090565b9081600052600d6020526001600160a01b036040600020541661515f5761514d91600052600d6020526040600020906001600160a01b03167fffffffffffffffffffffffff0000000000000000000000000000000000000000825416179055565b600c5490810180911161373157600c55565b60046040517fed778779000000000000000000000000000000000000000000000000000000008152fd5b92909283018084116137315761519f9083613b9a565b670de0b6b3a7640000908181029080820483149015171561373157826151c491614dc6565b93806151d2575b5050505090565b6151dd930202614dc6565b9003388080806151cb565b67ffffffffffffffff16670a688906bd8b00008111610437576020817fb77b18869f1146e7805c1d2169aa277954f24055acb20c3e15ddc3de57eacb85927fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000006008541617600855604051908152a1565b9092918361526591613b9a565b91670de0b6b3a76400009283810290808204851490151715613731578161528b91614dc6565b91820391808311613731576152a6612cf8916152ac9461534b565b916143fe565b8103908111613731576112239161506d565b601c600060649281946020966040519860605260405260601b602c526f23b872dd000000000000000000000000600c525af13d15600160005114171615615309576000606052604052565b637939f4246000526004601cfd5b67ffffffffffffffff60085416918261532f57505050565b6134d39261533c9161506d565b90615345613757565b906149bc565b670de0b6b3a7640000907812725dd1d243aba0e75fe645cc4873f9e65afe688c928e1f218111820215830215614d79570290808204910615150190565b9461ffff946112239a989460ff6153b26001600160a01b03969c9a95610100808c528b0190613c45565b9b1660208901526040880152606087015260808601521660a08401521660c082015260e08185039101526136c8565b9a96918b61ffff9a966101209c989f9e9a9661541a6154289460ff986001600160a01b03976101409087528060208801528601916136c8565b9260408185039101526136c8565b9c1660608b015216608089015260a088015260c087015260e086015261010085015216910152565b9899909997969795939294956154706001600160a01b038a161515613578565b61549b7f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8710613578565b6154aa610a4d87601054613bad565b6154c2610faa610faa6002546001600160a01b031690565b906154cd8886613b5f565b91803b1561043757848c61551a8f968b958e8c996000996040519b8c9a8b998a997fd6512967000000000000000000000000000000000000000000000000000000008b5260048b01615388565b039134905af180156110b2576155d7575b50604088019661553b888a613abe565b8b6155468987613b5f565b884363ffffffff16936155589561585a565b908a6155648886613b5f565b9161556e936156f0565b61557a8230338c6152be565b615584858a615317565b6155916020890189613abe565b99909761559e908a613abe565b906040519b8c9b359a6155b19b8d6153e1565b037f39d3d3ef1ca8c28e2940bcde183fe626d94dca2df8d9ba3bdcd7a91caa31e36191a1565b806110a66155e492611d6f565b3861552b565b92909282018083116137315761560392610f4191614d44565b7ffffffffffffffffffffffffffffffffffffffffffffffffff21f494c589c00008101908113600116613731576112239161506d565b600052600d6020526040600020908154916001600160a01b038316928315610437577fffffffffffffffffffffffff0000000000000000000000000000000000000000169055600c5403600c5590565b90600090828252600d6020526001600160a01b03908160408420541661515f576040938352600d60205283832060017fffffffffffffffffffffffff0000000000000000000000000000000000000000825416179055168152600b60205220908154019055565b919091600091818352600d6020526001600160a01b03918260408520541661515f57604094615756918552600d602052858520906001600160a01b03167fffffffffffffffffffffffff0000000000000000000000000000000000000000825416179055565b168152600b60205220908154019055565b600a549061579e8261579261578760075465ffffffffffff9060601c1690565b65ffffffffffff1690565b42030262015180900490565b906006548281111561580657906157b491613b0f565b0390811161499257600780547fffffffffffffffffffffffffffff000000000000ffffffffffffffffffffffff164260601b71ffffffffffff000000000000000000000000161790556134d390600655565b50809291501161499257600780547fffffffffffffffffffffffffffff000000000000ffffffffffffffffffffffff164260601b71ffffffffffff000000000000000000000000161790556134d390600655565b94917fffffffff000000000000000000000000000000000000000000000000000000006078937fffffffffffffffffffffffffffffffffffffffff0000000000000000000000006150e6969760405198868a97602089019c8d378701956020870152604086015260601b16606084015260e01b166074820152036058810184520182611da4565b600052600d6020526040600020918254906001600160a01b038216938415610437577fffffffffffffffffffffffff0000000000000000000000000000000000000000615944931690556001600160a01b0316600052600b602052604060002090565b90815403905590565b81600019048111820261505f5702670de0b6b3a7640000808204910615150190565b7ffffffffffffffffffffffffffffffffffffffffffffffffdc0d0570925a462d7811315615b3657680755bf798b4a1bf1e5811215615b28576503782dace9d990604e1b0574029d9dc38563c32e5c2f6dc192ee70ef65f9978af36bb17217f7d1cf79abc9e3b3989179d835ebba824c98fb31b83b2ca45c0000000000000000000000006060916b8000000000000000000000008582851b0501831d94850290036e0587f503bb6ea29d25fcb740196450816c10fe68e7fd37d0007b713f7650810102841d936e05180bb14799ab47a8a8cb2a527d57837ffffffffffffffffffffffffffffffffffffd38dc772608b0ae56cce01296c0eb816db1bbb201f443cf962f1a1d3db4a5817fffffffffffffffffffffffffffffffffffffe5adedaa1cb095af9e4da10e363c816d0277594991cfc85f6e2461837cd9817fffffffffffffffffffffffffffffffffffffffdbf3ccf1604d263450f02a55048101028a1d0102881d0102861d0102841d0102821d01947ffffffffffffffffffffffffffffffffffffffe2c69812cf03b0763fd454a8f7e846d02d16720577bd19bf614176fe9ea830192010102901d01020105029060c3031c90565b63a37bfec96000526004601cfd5b5060009056fea26469706673582212205b620e5c19cd34ebff19ce0d6221c4cb20ca382d3b6b735234817ac60f7e822764736f6c63430008160033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000000000000e5e81e25aead7fccb4c9560c6b5b718f000000000000000000000000000000575b0d9cc6ddbd8990db4d845fe480281f
-----Decoded View---------------
Arg [0] : factory_ (address): 0x00000000E5E81E25aeaD7fCCb4C9560C6b5b718F
Arg [1] : mathlib_ (address): 0x000000575b0D9cc6ddbd8990db4d845fe480281f
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 00000000000000000000000000000000e5e81e25aead7fccb4c9560c6b5b718f
Arg [1] : 000000000000000000000000000000575b0d9cc6ddbd8990db4d845fe480281f
Deployed Bytecode Sourcemap
2287:73514:11:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;;;;;;:::o;:::-;;;;;;;;;-1:-1:-1;;2287:73514:11;;;;;;6378:31:12;2287:73514:11;;;;;;;;;;;;;;;-1:-1:-1;;2287:73514:11;;;;:::o;:::-;;;;;;;;;;;;;;-1:-1:-1;;2287:73514:11;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;:::o;:::-;;;;;-1:-1:-1;;2287:73514:11;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;-1:-1:-1;;;;;2287:73514:11;;;;;:::o;:::-;;;;;-1:-1:-1;;2287:73514:11;;;;;;;;;;:::i;:::-;;;7568:413:3;2287:73514:11;7568:413:3;;;;;-1:-1:-1;7568:413:3;;;;;;-1:-1:-1;7568:413:3;;;;;;;2287:73514:11;-1:-1:-1;7568:413:3;2287:73514:11;;;7997:4:3;2287:73514:11;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;:::o;:::-;;;;;;;;;;;:::o;:::-;;;;;;;;;;:::o;:::-;;;;;-1:-1:-1;;2287:73514:11;;;;;;;:::i;:::-;-1:-1:-1;;;;;18697:17:12;2287:73514:11;;;;18683:10:12;:31;2287:73514:11;;18784:3:12;;;:::i;:::-;2287:73514:11;;;;;;-1:-1:-1;;2287:73514:11;;;;;;8721:23;;:::i;:::-;8748:1;2287:73514;;;;;;;;;;;;-1:-1:-1;;2287:73514:11;;;;;;;;;;;;:::i;:::-;;;73973:29;73985:16;73973:29;;2287:73514;;;-1:-1:-1;;;;;2287:73514:11;;8467:15:12;2287:73514:11;;8453:10:12;:29;2287:73514:11;;;;34418:115:12;2287:73514:11;74482:39;2287:73514;34194:33:12;2287:73514:11;;34194:33:12;;;:::i;:::-;34377:15;;;;;;:::i;:::-;2287:73514:11;;;;;;;;2522:19:12;;2287:73514:11;2522:19:12;2287:73514:11;2522:19:12;;2287:73514:11;34418:115:12;-1:-1:-1;;;;;2287:73514:11;;;74482:30;2287:73514;;;;;;;74482:39;2287:73514;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;2287:73514:11;;;;;;;4765:35:12;2287:73514:11;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;:::o;:::-;;;;;-1:-1:-1;;2287:73514:11;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;:::i;:::-;;;;;;;;;;;52630:23;2287:73514;;;;;;:::i;:::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;52630:23;:::i;:::-;2287:73514;;;;;;;;;;;;;;;;-1:-1:-1;;2287:73514:11;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;:::i;:::-;;;;-1:-1:-1;;;;;8467:15:12;2287:73514:11;;;;;8453:10:12;:29;2287:73514:11;;31260:303:12;;;;31847:12;31260:303;31727:56;31260:303;;73428:25:11;31260:303:12;31894:145;31260:303;;31894:145;31260:303;;;:::i;:::-;31727:56;:::i;:::-;31847:12;:::i;:::-;2287:73514:11;;31894:145:12;;;;;:::i;:::-;;;;73428:25:11;2287:73514;73428:25;:::i;:::-;;2287:73514;;;;;;;-1:-1:-1;;2287:73514:11;;;;;;6408:68:3;;2287:73514:11;;;;;;;;;-1:-1:-1;;2287:73514:11;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;:::o;:::-;;;;;;;:::i;:::-;;;;;-1:-1:-1;;;;;2287:73514:11;;;;8467:15:12;2287:73514:11;;8453:10:12;:29;2287:73514:11;;28696:8:12;-1:-1:-1;26731:410:12;27302:61;26731:410;;;;;;;;;;;;:::i;:::-;27302:61;:::i;:::-;27651:9;2287:73514:11;;;27974:83:12;;;;;;;;2287:73514:11;27974:83:12;;;2287:73514:11;;;;;;;27974:83:12;;;;;:::i;:::-;28067:504;;;;;;28696:8;;2287:73514:11;28696:8:12;28692:79;;2287:73514:11;71862:25;;2287:73514;28787:166:12;2287:73514:11;;28787:166:12;2287:73514:11;;;;;;;28787:166:12;;;;;:::i;71862:25:11:-;;2287:73514;;28692:79:12;28722:26;:21;28710:9;;;;;;;;28722:21;;:::i;:::-;28746:2;3138:4:11;;;;28722:26:12;-1:-1:-1;28706:65:12;;28692:79;;;;;;;;;;28706:65;2287:73514:11;;;28757:14:12;;;;2287:73514:11;;;;;-1:-1:-1;;2287:73514:11;;;;;;;;:::i;:::-;-1:-1:-1;;;;;2287:73514:11;;;;;;;;-1:-1:-1;;2287:73514:11;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;:::o;:::-;;;;;;;:::i;:::-;10164:1922:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;2287:73514:11;10164:1922:3;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;10164:1922:3;;;;-1:-1:-1;10164:1922:3;;;;;;;;;;;;;;;;;;;;2287:73514:11;;10164:1922:3;2287:73514:11;;;;;10164:1922:3;;-1:-1:-1;10164:1922:3;2287:73514:11;10164:1922:3;;;;;;;;;;;;;;;;;;;-1:-1:-1;10164:1922:3;2287:73514:11;10164:1922:3;;2287:73514:11;;;;;-1:-1:-1;;2287:73514:11;;;;;-1:-1:-1;;;;;2287:73514:11;;;;;:::i;:::-;;-1:-1:-1;2287:73514:11;6490:50:12;2287:73514:11;;;;-1:-1:-1;2287:73514:11;;;;;;;;;;;;;-1:-1:-1;;2287:73514:11;;;;;;;;-1:-1:-1;;;;;3857:32:12;2287:73514:11;;;;;;;;;-1:-1:-1;;2287:73514:11;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;8241:14:12;;:::i;:::-;2287:73514:11;8227:10:12;:28;2287:73514:11;;18105:13:12;;;:::i;2287:73514:11:-;;;;;-1:-1:-1;;2287:73514:11;;;;;;;;5933:2:3;2287:73514:11;;;;;;;;-1:-1:-1;;2287:73514:11;;;;;-1:-1:-1;;;;;2287:73514:11;;;;;:::i;:::-;;-1:-1:-1;2287:73514:11;4534:42:12;2287:73514:11;;;;-1:-1:-1;2287:73514:11;;;;;;;;;;;;;-1:-1:-1;;2287:73514:11;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;;;;;67407:28;2287:73514;;;;;;;;;;;;;;;67407:28;:::i;2287:73514::-;;;;;-1:-1:-1;;2287:73514:11;;;;;;16961:346:3;2287:73514:11;;:::i;:::-;;;;;;16884:24:3;16961:346;;;;;;;;;;;;;;;;;;;;;;;;;;;2287:73514:11;;;;;;;;;;;;;;;:::o;:::-;;-1:-1:-1;;2287:73514:11;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;:::i;:::-;1575:245:8;;;;;;;;;;;;;;2287:73514:11;;58573:24;;;;;2287:73514;58573:24;;;;:::i;:::-;2287:73514;;;:::i;:::-;;;-1:-1:-1;2287:73514:11;8713:16:12;58573:24:11;2287:73514;;;58573:24;2287:73514;;;-1:-1:-1;2287:73514:11;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;8712:35:12;8708:67;;58817:35:11;-1:-1:-1;;;;;2287:73514:11;;58825:26;;58817:35;:::i;:::-;59089:11;59077:10;;59089:11;:::i;:::-;59722:336;59811:208;59727:331;59112:33;2287:73514;59133:12;2287:73514;;;;;;;;;;59112:33;59803:241;59365:29;;;:::i;:::-;6408:68:3;;;59657:46:11;6408:68:3;59682:16:11;59571:50;6408:68:3;59571:36:11;6408:68:3;;59587:20:11;2287:73514;59571:36;;:::i;:::-;:50;:::i;:::-;59682:16;;;:::i;:::-;59657:46;:::i;:::-;59811:208;:::i;:::-;59803:241;:::i;:::-;59727:331;;:::i;:::-;59722:336;;:::i;:::-;60222:29;60214:38;60234:16;60222:29;;60214:38;:::i;:::-;60296:25;;2287:73514;60296:25;2287:73514;60296:25;:::i;:::-;60393:64;:40;2287:73514;60417:15;2287:73514;-1:-1:-1;;;;;2287:73514:11;;;;-1:-1:-1;;;;;2287:73514:11;;;60393:64;:205;;;;;2287:73514;-1:-1:-1;2287:73514:11;60393:205;2287:73514;;;;;;60393:205;;;;;;;2287:73514;60393:205;;;;;:::i;:::-;;60465:9;;60393:205;;;;;;;;2287:73514;60393:205;61896:11;60393:205;61465:207;60393:205;;;2287:73514;61042:26;61465:207;61042:26;;;;;;61576;61538:24;61003:368;61042:26;;;;;;:::i;:::-;61298:12;2287:73514;;;61298:12;61003:368;:::i;:::-;61538:24;;;:::i;:::-;61576:26;;;;:::i;:::-;2287:73514;;;;61465:207;;;;;:::i;:::-;;;;61896:11;:::i;:::-;1883:75:8;;;2287:73514:11;;;;;;;;;;;;60393:205;;;;;;:::i;:::-;;;:::i;:::-;;;;;;:::i;8708:67:12:-;2287:73514:11;;8756:19:12;;;;1575:245:8;;;-1:-1:-1;1575:245:8;;;2287:73514:11;;;;;-1:-1:-1;;2287:73514:11;;;;;;;;;;;;:::i;:::-;;;;;:::i;:::-;;;;;;;;;;;;-1:-1:-1;;2287:73514:11;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;;9628:715:12;2287:73514:11;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;9628:715:12;:::i;2287:73514:11:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;-1:-1:-1;2287:73514:11;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::o;:::-;;;;;-1:-1:-1;;2287:73514:11;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;:::i;:::-;1575:245:8;;;;;;;;;;;;;;32880:11:11;2287:73514;;32868:10;32880:11;:::i;:::-;33064:33;2287:73514;33085:12;2287:73514;;;;;33064:33;3471:1:12;;;:::i;:::-;;;;:::i;:::-;33319:13:11;-1:-1:-1;33859:34:11;34148:14;3471:1:12;34148:14:11;;;;34136:1605;2287:73514;37233:332;36261:51;2287:73514;37228:337;2287:73514;36295:12;2287:73514;3471:1:12;;36261:51:11;:::i;:::-;37309:241;37341:208;6408:68:3;36827:46:11;6408:68:3;36852:16:11;36597:50;6408:68:3;;36597:36:11;2287:73514;;;36613:20;2287:73514;36597:36;;:::i;:50::-;2287:73514;;36852:16;;:::i;37341:208::-;37309:241;:::i;37228:337::-;37681:25;;;:::i;:::-;37753:10;-1:-1:-1;37716:22:11;;37748:1852;37765:15;3471:1:12;37765:15:11;;;;37748:1852;39721:6;;;;;;;;;39717:48;;2287:73514;;;39848:34;;2287:73514;39848:34;2287:73514;39848:34;:::i;:::-;;2287:73514;;39848:34;39896:17;2287:73514;;39896:35;;;;;39947:21;;;-1:-1:-1;39896:17:11;2287:73514;;39947:21;40197:47;2287:73514;;32868:10;40197:47;32868:10;;2287:73514;;40197:47;;:::i;:::-;;;;1883:75:8;1575:245;1883:75;2287:73514:11;;;;;;;:::i;39892:264::-;40096:35;3471:1:12;;39896:17:11;2287:73514;;40096:35;39892:264;;39717:48;2287:73514;;39736:29;;;;;;2287:73514;;;;;;;39736:29;;;;;;;37753:10;37911:16;;;;;;;;:30;:16;;;;;:::i;:::-;3471:1:12;-1:-1:-1;;;;;2287:73514:11;;3471:1:12;37911:30:11;;37907:41;;38032:46;38060:17;;;;;:::i;:::-;3471:1:12;38032:46:11;;:::i;:::-;38096:8;;;38092:503;;38608:8;;;;:::i;:::-;38766:16;;;;;:::i;:::-;3471:1:12;-1:-1:-1;;;;;2287:73514:11;;;;;34356:7;2287:73514;;;;;;38976:20;;;;;;;:::i;:::-;3471:1:12;38950:73:11;;;:::i;:::-;39095:10;;;;;;:::i;:::-;3471:1:12;39095:24:11;39091:80;;39234:25;39503;39485:43;39234:25;;;;;39360:16;;39234:25;;3471:1:12;39234:25:11;;;39390:11;39234:25;;:::i;:::-;3471:1:12;32868:10:11;39360:16;;:::i;:::-;39390:11;:::i;:::-;39503:25;:::i;:::-;39485:43;;:::i;:::-;3471:1:12;;37753:10:11;;;;;;;;;;;;39091:80;39160:10;39128:43;39160:10;;;;;:::i;:::-;2287:73514;;;39128:43;;;;;;2287:73514;;;3471:1:12;;;;;2287:73514:11;;;;;3471:1:12;;;38092:503:11;38250:17;;;;;;;;:::i;:::-;3471:1:12;38246:57:11;;38424:10;;;;;:::i;:::-;3471:1:12;38420:61:11;;3471:1:12;;38572:8:11;;;38420:61;38470:10;;;;;;:::i;:::-;3471:1:12;2287:73514:11;38448:33;2287:73514;;38448:33;;;;;;;;3471:1:12;;;;;;2287:73514:11;-1:-1:-1;2287:73514:11;;3471:1:12;2287:73514:11;3471:1:12;38246:57:11;2287:73514;;;38281:22;;;;37907:41;37943:5;;;34141;34203:17;;;;;;;;;;;;2287:73514;;;;;;;;;;34203:17;2287:73514;-1:-1:-1;;;;;2287:73514:11;;;34203:17;-1:-1:-1;;;;;2287:73514:11;;34246:19;;34242:30;;34294:23;34493:37;34294:23;;;;;;;:::i;:::-;3471:1:12;-1:-1:-1;;;;;2287:73514:11;3471:1:12;;;34294:23:11;2287:73514;34356:14;;;-1:-1:-1;;;;;2287:73514:11;;;34356:7;2287:73514;;;;;;;34356:14;2287:73514;;;;34493:37;;;;;2287:73514;34493:37;;1575:245:8;34493:37:11;;;2287:73514;;;-1:-1:-1;;;;;2287:73514:11;;;;;;;;34493:37;;;;;;;;;;;34934:53;34493:37;;;;34944:42;34493:37;-1:-1:-1;34493:37:11;;;34141:5;34764:22;34949:37;34764:22;;34737:49;34764:22;34759:27;34764:22;;-1:-1:-1;;;;;2287:73514:11;;;34764:15;2287:73514;;;;;;;34764:22;2287:73514;34759:27;;:::i;:::-;34737:49;;:::i;:::-;3471:1:12;-1:-1:-1;;;;;2287:73514:11;;;74482:30;2287:73514;;;;;;;34949:37;2287:73514;34944:42;;:::i;34934:53::-;35182:23;35178:461;;34141:5;3471:1:12;;;;34141:5:11;;;;;;;;;;;35178:461;35300:42;35239:231;35586:30;35300:42;;3471:1:12;35300:42:11;;;:::i;35239:231::-;35586:30;;:::i;:::-;35178:461;;;;;;;34493:37;34949;34493;;;;2287:73514;34493:37;2287:73514;34493:37;;;;;;;;:::i;:::-;;;;;:::i;:::-;;;;;;;;;34242:30;34267:5;;;;;;;;;;;;;1575:245:8;;;-1:-1:-1;1575:245:8;;;2287:73514:11;;;;;-1:-1:-1;;2287:73514:11;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;:::i;:::-;;6393:65;2287:73514;;;;;;:::i;:::-;;-1:-1:-1;;;;;4769:7:11;4747:30;4769:7;;2287:73514;4755:10;:21;4747:30;:::i;:::-;4874:1;2287:73514;;;;;4851:40;4859:17;;2287:73514;4859:17;2287:73514;4859:17;2287:73514;4859:31;4851:40;:::i;:::-;2287:73514;2458:4:4;5017:36:11;5025:27;;;5017:36;:::i;:::-;3471:1:12;2287:73514:11;;;6322:57;;2287:73514;6322:57;2287:73514;;;;;;6322:57;2287:73514;;6322:57;2287:73514;6322:57;2287:73514;;;;;;;;;6322:57;2287:73514;;6393:65;6556:25;;:::i;:::-;6675:10;-1:-1:-1;6591:27:11;;6670:1233;6687:16;;;;;;8131:34;8280:61;8131:34;;;;39848;2287:73514;;8131:34;8244:19;;;:::i;:::-;8280:61;2287:73514;;;;;;8280:61;;;:::i;:::-;;;;2287:73514;6675:10;6744;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;6768:18;:33;:18;;;2287:73514;;;;;;;;;;6768:18;2287:73514;-1:-1:-1;;;;;2287:73514:11;;;;;;;;;6768:33;6833:11;;;;;:::i;:::-;3471:1:12;6866:11:11;6858:20;6866:11;;;6858:20;:::i;:::-;6934:21;;;-1:-1:-1;;;;;2287:73514:11;;;34356:7;2287:73514;;;;;;;6934:21;2287:73514;;;;7605:44;;7643:4;7605:44;;;2287:73514;;;;;;;;;;;7605:44;;;;;;2287:73514;;;7605:44;;;;;;3471:1:12;7605:44:11;;;7809:22;7605:44;7790:41;7605:44;-1:-1:-1;7605:44:11;;;6675:10;7671:18;;;;7740:35;7671:18;7663:27;7671:18;;;7663:27;:::i;:::-;7740:35;:::i;:::-;3471:1:12;7809:22:11;:::i;7790:41::-;3471:1:12;;6675:10:11;;;;;;;7605:44;7740:35;7605:44;;;;;;;;;;-1:-1:-1;7605:44:11;;;;;;:::i;:::-;;;;;;;2287:73514;;;;;-1:-1:-1;;2287:73514:11;;;;;;;;:::i;:::-;;;;;-1:-1:-1;;2287:73514:11;;;;;;;5056:23:12;2287:73514:11;;;;;;;;;;;;;;;-1:-1:-1;;2287:73514:11;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;1575:245:8;;;;;;;;;;;;40887:43:11;;2287:73514;40920:9;2287:73514;;;;;;;;;;;;;40887:43;;;:::i;:::-;40986:47;41020:12;;;;:::i;:::-;40986:47;;;:::i;:::-;41116:12;;;;41112:56;;1575:245:8;;42150:54:11;1575:245:8;41628:3:11;2287:73514;1575:245:8;41469:6:11;1575:245:8;;41442:10:11;41469:6;;:::i;:::-;41536:3;41442:10;;41536:3;;:::i;:::-;41628;;:::i;:::-;41768:27;41777:18;;-1:-1:-1;;;;;2287:73514:11;;;34356:7;2287:73514;;;;;;;41777:18;2287:73514;41768:27;;:::i;:::-;41827:22;41833:16;;-1:-1:-1;;;;;2287:73514:11;;;34356:7;2287:73514;;;;;;;41833:16;2287:73514;41827:22;;:::i;:::-;41953:28;;;;;;42017;41997:48;42017:28;41997:48;42017:28;;:::i;:::-;41997:48;2287:73514;41997:48;:::i;:::-;2287:73514;;;-1:-1:-1;;;;;2287:73514:11;;;;;;;;;;;;;;;;;;;;;;41442:10;;2287:73514;;;;42150:54;;;;1883:75:8;;;2287:73514:11;;;;;;;;;;;;;41949:186;42096:28;42076:48;42096:28;42076:48;42096:28;;:::i;:::-;42076:48;2287:73514;42076:48;:::i;:::-;41949:186;;41112:56;2287:73514;;41137:31;;;2287:73514;41137:31;;2287:73514;;;3471:1:12;;;2287:73514:11;;;;3471:1:12;;39736:29:11;1575:245:8;;-1:-1:-1;1575:245:8;2287:73514:11;1575:245:8;;2287:73514:11;;;;;-1:-1:-1;;2287:73514:11;;;;;;;:::i;:::-;-1:-1:-1;;;;;8241:14:12;;:::i;:::-;2287:73514:11;8227:10:12;:28;2287:73514:11;;18414:3:12;;;:::i;2287:73514:11:-;;;;;;;;;;;;;;;;;;:::o;:::-;;:::i;:::-;;;;;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;2287:73514:11;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;-1:-1:-1;;2287:73514:11;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;1575:245:8;;;;;;;;;;;;23224:11:11;23212:10;;23224:11;:::i;:::-;23407:33;2287:73514;23428:12;2287:73514;;;;;23407:33;3471:1:12;;;:::i;:::-;;;;:::i;:::-;24134:10:11;-1:-1:-1;24003:34:11;24171:15;3471:1:12;24171:15:11;;;;24158:1347;26079:12;2287:73514;26045:52;;3471:1:12;26045:52:11;:::i;:::-;26282:25;;;:::i;:::-;6408:68:3;;26928:49:11;26841:50;6408:68:3;26841:36:11;6408:68:3;;26857:20:11;2287:73514;26841:36;;:::i;:50::-;26929:42;26930:16;;;;:::i;:::-;26929:42;:::i;:::-;26928:49;:::i;:::-;27212:16;;;:358;;;;-1:-1:-1;27651:20:11;;;;:::i;:::-;27686:10;;27698:15;3471:1:12;27698:15:11;;;;27681:3486;2287:73514;;;;;;;;;;;31241:34;;2287:73514;31241:34;2287:73514;31241:34;:::i;:::-;31289:17;2287:73514;;31289:35;;;;;31340:21;;;-1:-1:-1;39896:17:11;2287:73514;;31340:21;31585:47;2287:73514;;23212:10;31585:47;23212:10;;31585:47;;;:::i;:::-;;;;1883:75:8;;;2287:73514:11;;;;;;;:::i;31285:259::-;31484:35;3471:1:12;;39896:17:11;2287:73514;;31484:35;31285:259;;27686:10;27746:16;;;;;:::i;:::-;-1:-1:-1;;;;;2287:73514:11;;27780:19;27776:30;;28120:26;;28040:234;28120:26;:50;:26;;;;:::i;:::-;3471:1:12;28120:50:11;:::i;28040:234::-;28679:26;;;;;:::i;:::-;3471:1:12;28873:33:11;;;;28869:1456;;27686:10;30424:37;;30567;30424;;30730:10;30424:37;;:::i;:::-;30590:14;;;-1:-1:-1;;;;;2287:73514:11;;;34356:7;2287:73514;;;;;;;30590:14;2287:73514;30567:37;;:::i;:::-;30730:10;;:::i;:::-;3471:1:12;30774:33:11;;;30770:98;;30922:33;;31075:19;30922:33;;;;;3471:1:12;30922:33:11;;;:::i;:::-;3471:1:12;23212:10:11;31075:19;;:::i;:::-;3471:1:12;27686:10:11;;30770:98;2287:73514;;30816:52;;;;;;2287:73514;;;3471:1:12;;;2287:73514:11;;;;;;;3471:1:12;;39736:29:11;;;28869:1456;30567:37;30424;29716:594;30730:10;30101:33;;29803:489;29835:456;30101:33;;;;29966:245;30101:33;;;;:::i;:::-;29966:245;:::i;29716:594::-;28869:1456;;;;;;;27776:30;27801:5;;;27212:358;27361:194;27249:321;27361:194;;27329:227;27361:194;;:::i;27249:321::-;27212:358;;;24163:6;24223:18;;;2287:73514;;;;;;;;;;24223:18;-1:-1:-1;;;;;2287:73514:11;;24263:19;;;24259:30;;24307:24;;;;;;:::i;:::-;24366:14;;-1:-1:-1;;;;;2287:73514:11;;;34356:7;2287:73514;;;;;;;24366:14;2287:73514;;;;24520:37;;1575:245:8;24520:37:11;;;2287:73514;;;;;;;;;;;;;;;;;24520:37;;;;;;;;;;24511:46;24520:37;-1:-1:-1;24520:37:11;;;24163:6;24511:46;;;;:::i;:::-;24739:22;24718:52;24739:31;:22;;;-1:-1:-1;;;;;2287:73514:11;;;34764:15;2287:73514;;;;;;;24739:22;2287:73514;24739:31;:::i;:::-;24718:52;;:::i;:::-;24689:81;;;;:::i;:::-;3471:1:12;24931:23:11;24927:491;;24163:6;3471:1:12;;;;;;24163:6:11;;24927:491;25070:37;25048:93;25049:67;3471:1:12;25070:37:11;;;:46;24991:270;25070:37;;25369:30;25070:37;-1:-1:-1;;;;;2287:73514:11;;;74482:30;2287:73514;;;;;;;25070:46;25049:67;;:::i;25369:30::-;24927:491;;;;;;;;;24520:37;;;;;;-1:-1:-1;24520:37:11;;;;;;:::i;:::-;;;;;24259:30;24284:5;;;;2287:73514;;;;;-1:-1:-1;;2287:73514:11;;;;;;;5264:33:12;2287:73514:11;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;2287:73514:11;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;-1:-1:-1;2287:73514:11;;;;;;:::o;:::-;;;;;-1:-1:-1;;2287:73514:11;;;;;;;;;;;;;;;;;;;;4103:66:12;2287:73514:11;;;;;;;;;;;;;;;:::i;:::-;;;-1:-1:-1;2287:73514:11;4103:66:12;2287:73514:11;;;-1:-1:-1;2287:73514:11;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;4103:66:12;2287:73514:11;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;2287:73514:11;;;;;;;;;;;;:::i;:::-;;;;;:::i;:::-;;;;;-1:-1:-1;;2287:73514:11;;;;;;;;-1:-1:-1;;;;;7088:32:12;2287:73514:11;;;;;;;;;;-1:-1:-1;;2287:73514:11;;;;;;;-1:-1:-1;;;;;2287:73514:11;12754:12:12;2287:73514:11;;12754:26:12;:61;;;;2287:73514:11;;;;;;;;;;;12754:61:12;2287:73514:11;;;;;;;;;;;;;12784:31:12;;12754:61;;;;2287:73514:11;;;;;;;;-1:-1:-1;;2287:73514:11;;;;;;;;;;:::i;:::-;6680:148:3;;;-1:-1:-1;6680:148:3;2287:73514:11;6680:148:3;;;;2287:73514:11;;;;;;;;;;;-1:-1:-1;;2287:73514:11;;;;;;6602:35:12;2287:73514:11;;;;;;;;;;;;-1:-1:-1;;2287:73514:11;;;;;-1:-1:-1;;;;;2287:73514:11;;;;;:::i;:::-;;-1:-1:-1;2287:73514:11;2510:65;2287:73514;;;;-1:-1:-1;2287:73514:11;;;;;;;;;;;;;-1:-1:-1;;2287:73514:11;;;;;;;;;;:::i;:::-;12929:205:3;;;-1:-1:-1;12929:205:3;2287:73514:11;12929:205:3;;;;2287:73514:11;;;;;;;;;;;;;;;:::i;:::-;;;:::i;:::-;;;;;;-1:-1:-1;;2287:73514:11;;;;;11631:12:12;2287:73514:11;-1:-1:-1;;;;;2287:73514:11;;11617:10:12;:26;2287:73514:11;;;;11631:12:12;2287:73514:11;11712:13:12;;;;2287:73514:11;;;;;;;;;;;-1:-1:-1;;2287:73514:11;;;;;;;-1:-1:-1;2287:73514:11;;;;;-1:-1:-1;;;;;2287:73514:11;-1:-1:-1;2287:73514:11;;;;;;;;;;;;;;-1:-1:-1;;2287:73514:11;;;;;;;4727:31:12;2287:73514:11;;;;;;;;;;;;;;-1:-1:-1;;2287:73514:11;;;;;;;;;3713:7:12;;2287:73514:11;;;;;:::i;:::-;;;;;;;3713:7:12;2287:73514:11;;;3713:7:12;;;;2287:73514:11;;;;;;;;;;;;;;:::i;:::-;;;3713:7:12;2287:73514:11;;;;;;;;;-1:-1:-1;;;;2287:73514:11;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;2287:73514:11;;;;;8944:23;;8994:15;3471:1:12;8994:15:11;;;;8977:314;39848:34;2287:73514;-1:-1:-1;2287:73514:11;;8982:10;9042:18;;;2287:73514;;;;;;;;;;9042:18;2287:73514;-1:-1:-1;;;;;2287:73514:11;;9078:19;;;9074:30;;2287:73514;;;9139:37;;9170:4;2287:73514;9139:37;;2287:73514;;9139:37;;;;2287:73514;;;;;;9139:37;;;;;;;9205:14;9139:62;9138:81;9139:37;3471:1:12;9139:37:11;9119:100;9139:37;;;;;8982:10;9179:22;;;;-1:-1:-1;;;;;2287:73514:11;;;34764:15;2287:73514;;;;;;;9139:62;9205:14;-1:-1:-1;;;;;2287:73514:11;;;34356:7;2287:73514;;;;;;;9205:14;2287:73514;9138:81;;:::i;9119:100::-;3471:1:12;;8982:10:11;;;9139:37;;;;;;-1:-1:-1;9139:37:11;;;;;;:::i;:::-;;;;;9074:30;9099:5;;;;;2287:73514;;;;;-1:-1:-1;;2287:73514:11;;;;;;5407:32:12;2287:73514:11;-1:-1:-1;;;;;2287:73514:11;;;;;;;;;;;;;;-1:-1:-1;;2287:73514:11;;;;;;;-1:-1:-1;2287:73514:11;6736:48:12;2287:73514:11;;;-1:-1:-1;;;;;2287:73514:11;-1:-1:-1;2287:73514:11;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;:::o;:::-;;-1:-1:-1;;2287:73514:11;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;49144:9;2287:73514;;;;;;:::i;:::-;;;;;;;;;;;;49144:9;;:::i;2287:73514::-;;;;;-1:-1:-1;;2287:73514:11;;;;;;;;;;:::i;:::-;;;8378:1143:3;;;;;-1:-1:-1;8378:1143:3;2287:73514:11;8378:1143:3;;;;;;;;;;;;;;-1:-1:-1;8378:1143:3;2287:73514:11;8378:1143:3;;;;;;;;2287:73514:11;8378:1143:3;;;;;;;2287:73514:11;8378:1143:3;;2287:73514:11;;10164:1922:3;2287:73514:11;;;;;;;;;;-1:-1:-1;;2287:73514:11;;;;;;3283:25;2287:73514;;;;;;;;;;;;;;;-1:-1:-1;;2287:73514:11;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;1903:2157:7;2287:73514:11;1903:2157:7;;;2287:73514:11;1903:2157:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2287:73514:11;;;;;-1:-1:-1;;2287:73514:11;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;-1:-1:-1;;;;;10975:12:12;2287:73514:11;;10961:10:12;:26;2287:73514:11;;11040:2:12;11022:20;;2287:73514:11;;11160:40:12;2287:73514:11;11160:40:12;2287:73514:11;;-1:-1:-1;2287:73514:11;11100:16:12;2287:73514:11;;11100:44:12;2287:73514:11;;-1:-1:-1;2287:73514:11;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;11100:44:12;2287:73514:11;;11160:40:12;;;;;:::i;:::-;;;;2287:73514:11;;;;;;-1:-1:-1;;2287:73514:11;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;2287:73514:11;;8467:15:12;2287:73514:11;;8453:10:12;:29;2287:73514:11;;36211:58:12;2287:73514:11;;;;36211:58:12;:::i;:::-;;75457:25:11;2287:73514;;75457:25;2287:73514;75457:25;:::i;:::-;;2287:73514;;-1:-1:-1;2287:73514:11;75723:30;2287:73514;;;-1:-1:-1;2287:73514:11;;;;3471:1:12;2287:73514:11;;-1:-1:-1;2287:73514:11;;;;;;;-1:-1:-1;;2287:73514:11;;;;;;-1:-1:-1;;;;;3895:30:12;2287:73514:11;;;;;;;;;;;;;-1:-1:-1;;2287:73514:11;;;;;;;;;;:::i;:::-;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;8467:15:12;2287:73514:11;;8453:10:12;:29;2287:73514:11;;;;;;;;;;;:::i;:::-;;;-1:-1:-1;2287:73514:11;8713:16:12;2287:73514:11;;;-1:-1:-1;2287:73514:11;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;8712:35:12;8708:67;;35506:12;2287:73514:11;74951:43;2287:73514;35314:58:12;2287:73514:11;;;;35314:58:12;:::i;:::-;;35506:12;;:::i;:::-;-1:-1:-1;;;;;2287:73514:11;;;74482:30;2287:73514;;;;;;;74951:43;2287:73514;;;3471:1:12;2287:73514:11;;-1:-1:-1;2287:73514:11;;8708:67:12;2287:73514:11;;;8756:19:12;;;;2287:73514:11;;;;;-1:-1:-1;;2287:73514:11;;;;;;57051:195;56892:12;2287:73514;;;57212:20;56943:29;;;:::i;:::-;57212:20;;;:::i;:::-;57051:195;;:::i;2287:73514::-;;;;;-1:-1:-1;;2287:73514:11;;;;;;-1:-1:-1;;;;;5714:27:12;2287:73514:11;;;;;;;;;;;;;-1:-1:-1;;2287:73514:11;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;:::i;:::-;;;;:::i;:::-;;;;;;;;13704:24:3;13781:2752;;;;;;2287:73514:11;13781:2752:3;;-1:-1:-1;;;;;13781:2752:3;;;;;;;;;-1:-1:-1;13781:2752:3;;;;2287:73514:11;13781:2752:3;;;;;;;;;;;;;;;;;2287:73514:11;13781:2752:3;;;;;;;2287:73514:11;13781:2752:3;;;;;;;2287:73514:11;13781:2752:3;;;;;;2287:73514:11;13781:2752:3;;;;;;;;;;;;;2287:73514:11;13781:2752:3;;;;;;;;;;;;;;;2287:73514:11;;;13781:2752:3;2287:73514:11;;;13781:2752:3;;;2287:73514:11;13781:2752:3;13669:22;13781:2752;;;;;;;;;;;;;;;;;;;2287:73514:11;13781:2752:3;;;;;;2287:73514:11;;13781:2752:3;;;;2287:73514:11;13781:2752:3;;;;-1:-1:-1;13781:2752:3;2287:73514:11;13781:2752:3;;2287:73514:11;;;;;-1:-1:-1;;2287:73514:11;;;;;;;;;;:::i;:::-;;;;;;:::i;:::-;;7114:184:3;;;;-1:-1:-1;7114:184:3;2287:73514:11;7114:184:3;;;;2287:73514:11;;;;;;;;-1:-1:-1;;2287:73514:11;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;:::i;:::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;46806:9;2287:73514;;;;;;:::i;:::-;;;;;;;;;46806:9;;:::i;2287:73514::-;;;;;-1:-1:-1;;2287:73514:11;;;;;;3538:26;2287:73514;;;;;;;;;;;;;-1:-1:-1;;2287:73514:11;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;1575:245:8;;;;;;;;;;;;14324:33:11;2287:73514;14345:12;2287:73514;;;;;14324:33;14647:11;-1:-1:-1;15731:34:11;;15779:27;;15825:10;;15837:15;3471:1:12;15837:15:11;;;;15820:3453;2287:73514;;;21590:75;21873:98;2287:73514;;;19616:36;;2287:73514;19354:35;;21728:20;2287:73514;19354:35;2287:73514;19354:35;:::i;:::-;19616:36;2287:73514;19616:36;:::i;:::-;39896:17;2287:73514;;19616:36;20245:12;2287:73514;3471:1:12;;20965:9:11;20957:18;-1:-1:-1;20965:9:11;;;20957:18;:::i;:::-;21632:9;2287:73514;21608:33;;2287:73514;;;;;;21608:33;2458:4:4;3471:1:12;3185:5:11;2458:4:4;3138::11;;;;21590:75;21728:20;;:::i;:::-;6408:68:3;;;21873:98:11;;:::i;:::-;22080:20;;;;22076:72;;2287:73514;19045:10;;22241:11;19045:10;;22241:11;:::i;:::-;22303:51;2287:73514;;19045:10;22303:51;19045:10;22303:51;;;;:::i;22076:72::-;-1:-1:-1;;2287:73514:11;;22109:39;;;2287:73514;22109:39;;2287:73514;;;;3471:1:12;;;2287:73514:11;;;;3471:1:12;;39736:29:11;15825:10;15889:18;;;2287:73514;;;;;;;;;;15889:18;2287:73514;-1:-1:-1;;;;;2287:73514:11;;15929:19;;;15925:30;;15990:14;;-1:-1:-1;;;;;2287:73514:11;;;34356:7;2287:73514;;;;;;;15990:14;2287:73514;16044:16;;;;;:::i;:::-;3471:1:12;2287:73514:11;;;16217:37;;1575:245:8;16217:37:11;;;2287:73514;;;3471:1:12;;2287:73514:11;;;;;;;;;;;;16217:37;;;;;;;;;16208:46;16217:37;-1:-1:-1;16217:37:11;;;15825:10;16208:46;;;;:::i;:::-;16578:14;-1:-1:-1;16618:23:11;;;16614:864;;15825:10;17855:16;;;17851:175;;18598:239;18681:20;;18890:39;18681:20;18606:231;18681:20;;18659:67;18660:41;18909:20;18681;;3471:1:12;18681:20:11;;19112:11;18681:20;;;:::i;18606:231::-;3471:1:12;;18598:239:11;:::i;:::-;18909:20;;;:::i;18890:39::-;1575:245:8;;19045:10:11;;19112:11;;:::i;:::-;3471:1:12;15825:10:11;;;;;17851:175;3471:1:12;;;;;;;;;;17995:8:11;;;16614:864;17161:30;16846:37;;;16824:93;16825:67;16846:37;:46;16763:282;16846:37;;;;;;-1:-1:-1;;;;;2287:73514:11;;;74482:30;2287:73514;;;;;;;17161:30;17285:42;;17224:231;17285:42;;;;:::i;17224:231::-;16614:864;;;;16217:37;;;;;;-1:-1:-1;16217:37:11;;;;;;:::i;:::-;;;;;15925:30;15950:5;;;;;2287:73514;;;;;;;:::i;:::-;;-1:-1:-1;;;;;8467:15:12;2287:73514:11;;;;;;8453:10:12;:29;2287:73514:11;;29974:303:12;;30288:56;29974:303;;;;30390:145;29974:303;30390:145;29974:303;;;:::i;30288:56::-;;2287:73514:11;;30390:145:12;;;;;:::i;2287:73514:11:-;;;;;-1:-1:-1;;2287:73514:11;;;;;;3314:33;2287:73514;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;-1:-1:-1;;;;;8467:15:12;2287:73514:11;;8453:10:12;:29;2287:73514:11;;24587:410:12;;;;;25008:61;24587:410;;;69404:20:11;24587:410:12;;;25120:166;24587:410;;;25120:166;24587:410;;:::i;25008:61::-;;2287:73514:11;;25120:166:12;;;;;:::i;:::-;;;;-1:-1:-1;;;;;2287:73514:11;;;34356:7;2287:73514;;;;;;;69404:20;2287:73514;3185:5;69452:17;2287:73514;69573:28;;;;69569:430;69573:28;;;69621:48;3471:1:12;;39896:17:11;2287:73514;;69621:48;70295:16;2287:73514;;;;;70561:13;;;;;70594:36;;-1:-1:-1;;70295:16:11;2287:73514;;70557:153;39848:34;2287:73514;;69569:430;69756:7;69752:247;69569:430;69752:247;69963:21;-1:-1:-1;39896:17:11;2287:73514;;69963:21;69569:430;;2287:73514;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:::o;:::-;;;;;;;;;;;;;;;;;-1:-1:-1;2287:73514:11;;-1:-1:-1;;;2287:73514:11;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;2287:73514:11;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;1490:474:8:-;;;;;;;;;;;1575:245;;;;;;;;;;;-1:-1:-1;;;;;2287:73514:11;8467:15:12;2287:73514:11;;8453:10:12;:29;2287:73514:11;;;;;;;:::i;:::-;;;;;8713:16:12;2287:73514:11;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;8712:35:12;8708:67;;2287:73514:11;;52760:14;2287:73514;;;;;;;;52816:79;;;;;;:::i;:::-;52995:15;;;;;;:::i;:::-;2287:73514;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;53027:237;;;;1883:75:8;;;;1490:474::o;8708:67:12:-;8756:19;2287:73514:11;;8756:19:12;;;;2287:73514:11;;;;;;-1:-1:-1;;2287:73514:11;;;;;;;;-1:-1:-1;2287:73514:11;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;-1:-1:-1;2287:73514:11;;;;;;;;;;;;;:::o;:::-;;:::i;:::-;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;7792:154:12;2287:73514:11;;;7884:55:12;;;7903:7;7884:55;7903:7;-1:-1:-1;;;;;7903:7:12;2287:73514:11;7884:55:12;;;;;;;;;;;7877:62;7792:154;:::o;7884:55::-;;;;;;;;;;;;;;;:::i;:::-;;;;;:::i;:::-;;;;;1490:474:8;;;;;;;;;;;1575:245;;;;;;;;;;;-1:-1:-1;;;;;8467:15:12;2287:73514:11;;8453:10:12;:29;2287:73514:11;;;;;;;:::i;:::-;;;;;8713:16:12;2287:73514:11;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;8712:35:12;8708:67;;63182:20:11;62861:33;2287:73514;62882:12;2287:73514;;;;;62861:33;63114:29;63245:20;63114:29;;;:::i;:::-;63182:20;;;;:::i;:::-;63245;;:::i;:::-;6408:68:3;;;63390:86:11;;;;;;;:::i;:::-;63561:28;;;;63557:88;;63736:22;;;;;;63732:841;;1490:474:8;2287:73514:11;;;;;64619:25;;2287:73514;64619:25;2287:73514;64619:25;:::i;:::-;64984:26;;;;64980:61;;65133:225;;;67760:20;65133:225;67587:102;65133:225;67587:102;65133:225;;65892:44;65133:225;;;;65081:712;65133:225;;;65377:402;65409:369;65133:225;65513:206;65133:225;65892:44;65133:225;;;:::i;:::-;65625:25;;;;;:::i;65377:402::-;65081:712;;:::i;:::-;65892:44;:::i;:::-;;:::i;:::-;2287:73514;67587:102;;;;;:::i;:::-;;;;67760:20;:::i;:::-;1883:75:8;;;;1490:474::o;64980:61:11:-;65019:22;2287:73514;;65019:22;;;;63732:841;63801:273;64372:36;64345:22;64343:105;63801:273;;64344:79;63801:273;64372:50;63801:273;;:::i;64345:22::-;2287:73514;64388:20;2287:73514;64372:36;;:::i;:50::-;64344:79;;:::i;:::-;2458:4:4;3138::11;;;;64343:105;64466:34;;;64462:100;;63732:841;;;;;;64462:100;2287:73514;;64509:53;;;;;;2287:73514;;;;3471:1:12;;;2287:73514:11;;;;3471:1:12;;39736:29:11;63557:88;2287:73514;63598:47;2287:73514;;63598:47;;;;;;;;;3471:1:12;;;;;;;;;2287:73514:11;;;3471:1:12;2287:73514:11;3471:1:12;8708:67;8756:19;2287:73514:11;;8756:19:12;;;;2287:73514:11;;;;;;;-1:-1:-1;;;;;2287:73514:11;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;:::o;2458:4:4:-;;;;;;;;;;;:::o;:::-;;;;;;;;;;:::o;:::-;;;;;;;;;;:::o;:::-;;;;28742:1:12;2458:4:4;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;2287:73514:11;;;;2458:4:4;;;;:::o;:::-;;;;;;;;;;:::o;:::-;;;;;;;2287:73514:11;;;;2458:4:4;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;;:::i;:::-;2287:73514:11;;2458:4:4;;;;;;:::i;:::-;2287:73514:11;2458:4:4;;;2287:73514:11;2458:4:4;;;;;:::i;:::-;2287:73514:11;2458:4:4;;;2287:73514:11;-1:-1:-1;;;;;2458:4:4;;;2287:73514:11;;;;:::i;:::-;;2458:4:4;;;2287:73514:11;2458:4:4;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;;;;;;;2287:73514:11;;2458:4:4;;;2287:73514:11;:::i;:::-;;2458:4:4;;;2287:73514:11;;2458:4:4;;;;2287:73514:11;:::i;:::-;;;2458:4:4;;2287:73514:11;;2458:4:4;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;2287:73514:11;2458:4:4;2287:73514:11;2458:4:4;;;;;;;2287:73514:11;2458:4:4;;;;;;;;:::i;:::-;;;;;;;;;;;;;;2287:73514:11;;2458:4:4;;;;;;;;;;:::i;:::-;;;;;;;;;;:::i;:::-;;;;;2287:73514:11;2458:4:4;2287:73514:11;2458:4:4;;;;;2287:73514:11;2458:4:4:o;2287:73514:11:-;;;;;;;;;;;:::o;3138:4::-;;;;;;;;;;;;;;;;;:::o;:::-;;:::i;9801:1163::-;2287:73514;;;10019:41;;10054:4;10019:41;;;2287:73514;;;10019:41;2287:73514;;;-1:-1:-1;;;;;2287:73514:11;;10019:41;;;;;;;-1:-1:-1;10019:41:11;;;9801:1163;10082:18;10363:47;10082:18;3138:4;10082:18;-1:-1:-1;;;;;2287:73514:11;;;34356:7;2287:73514;;;;;;;10082:18;2287:73514;10363:47;2287:73514;10397:12;2287:73514;;;;;10363:47;;;;;:::i;:::-;3138:4;;10838:28;;10834:86;;9801:1163;:::o;10834:86::-;3185:5;2458:4:4;3185:5:11;;3138:4;10868:52;:::o;10019:41::-;3138:4;10019:41;;;10082:18;10019:41;10363:47;10019:41;;;;;;;;;;;:::i;:::-;;;;;;;3081:1113:5;;;;;;;;;2001:66;3207:622;;;;;;;;;3081:1113;2287:73514:11;10185:13:12;2287:73514:11;10230:16:12;2287:73514:11;;;10148:8:12;2287:73514:11;-1:-1:-1;;;;;2287:73514:11;;;;;;10056:32:12;2287:73514:11;;;10056:32:12;2287:73514:11;;;10098:26:12;2287:73514:11;;;10098:26:12;2287:73514:11;10148:8:12;:::i;:::-;10185:13;:::i;:::-;10230:16;:::i;:::-;2287:73514:11;;;;;-1:-1:-1;;;2287:73514:11;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;2287:73514:11;;;;;;;;;;;;;;;;:::i;:::-;3892:296:5;;3081:1113;:::o;3892:296::-;10056:32:12;3892:296:5;;10319:17:12;3892:296:5;;;;;;3081:1113::o;2287:73514:11:-;;;;-1:-1:-1;2287:73514:11;;;;;10296:13:12;2287:73514:11;;;;;-1:-1:-1;;2287:73514:11;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;2287:73514:11;;3207:622:5;2287:73514:11;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;2287:73514:11;;;;;;;;3207:622:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;10185:13:12;3207:622:5;;;;-1:-1:-1;3207:622:5;;;;2287:73514:11;;;;;;;;:::o;:::-;10296:13:12;2287:73514:11;10296:13:12;2287:73514:11;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;-1:-1:-1;2287:73514:11;;;;;;;;;;;;;:::o;:::-;10319:17:12;-1:-1:-1;;2287:73514:11;10319:17:12;-1:-1:-1;2287:73514:11;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;-1:-1:-1;2287:73514:11;;;;;;;;;;;;10319:17:12;2287:73514:11;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;2287:73514:11;;;;;;;;;;;;;;;:::o;:::-;10319:17:12;2287:73514:11;;-1:-1:-1;;2287:73514:11;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;-1:-1:-1;;2287:73514:11;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3471:1:12;2287:73514:11;;;3471:1:12;2287:73514:11;;;;;;;;;;;;;3471:1:12;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;:::i;:::-;2287:73514:11;;;;;;:::i;:::-;;3471:1:12;;2287:73514:11;3471:1:12;2287:73514:11;3471:1:12;;;:::o;:::-;;;;;;;;;;;;:::o;:::-;2287:73514:11;;3471:1:12;;;;;;;;;;;;:::o;:::-;;;;;2458:4:4;2287:73514:11;;3471:1:12;;;;;;;;:::i;:::-;;;;;;2287:73514:11;;3471:1:12;;;;;;;;:::i;2287:73514:11:-;;;;;:::i;7577:111:12:-;2287:73514:11;;;7657:24:12;;;7665:7;7657:24;7665:7;-1:-1:-1;;;;;7665:7:12;2287:73514:11;7657:24:12;;;;;;;;;;;7650:31;7577:111;:::o;84:4:28:-;;;;;;;;:::o;11290:703:11:-;;2287:73514;;;11522:39;;11555:4;11522:39;;;2287:73514;11522:39;2287:73514;;;-1:-1:-1;;;;;2287:73514:11;;11522:39;;;;;;;-1:-1:-1;11522:39:11;;;11290:703;11564:24;;;-1:-1:-1;;;;;2287:73514:11;;;34764:15;2287:73514;;;;;;;11564:24;2287:73514;2458:4:4;;;;;;;11610:16:11;11943:43;11610:16;-1:-1:-1;;;;;2287:73514:11;;;34356:7;2287:73514;;;;;;;11610:16;2287:73514;;11973:12;2287:73514;;;11943:43;;:::i;11522:39::-;;;;;;;;;;;;;;:::i;:::-;;;;12536:903;2287:73514;;;12709:41;;;12744:4;12709:41;;;2287:73514;;;;12536:903;-1:-1:-1;;;;;2287:73514:11;12709:41;;;2287:73514;;;;;;12709:41;;;;;;;-1:-1:-1;12709:41:11;;;12536:903;-1:-1:-1;2287:73514:11;;12772:39;;;12744:4;12709:41;12772:39;;2287:73514;;;;;;;;;;;;12772:39;;;;;;12862:18;12772:66;12904:16;12772:39;3138:4;12772:39;12983:91;12772:39;-1:-1:-1;12772:39:11;;;12536:903;12814:24;;;;-1:-1:-1;;;;;2287:73514:11;;;34764:15;2287:73514;;;;;;;12772:66;12862:18;-1:-1:-1;;;;;2287:73514:11;;;34356:7;2287:73514;;;;;;;12862:18;2287:73514;12904:16;-1:-1:-1;;;;;2287:73514:11;;;34356:7;2287:73514;;;;;;;12904:16;2287:73514;;13004:48;12930:33;2287:73514;12951:12;2287:73514;;;;;12930:33;13004:48;;;;;:::i;:::-;12983:91;:::i;:::-;3138:4;;13335:28;;13331:91;;12536:903::o;13331:91::-;3185:5;;2458:4:4;3185:5:11;;3138:4;13365:57;:::o;12772:39::-;;;;;;-1:-1:-1;12772:39:11;;;;;;:::i;:::-;;;;;12709:41;;;;;;;;;;;;;;;;;:::i;:::-;;;;;1490:474:8;;;;;;;;;;;1575:245;;;;;;;;;;;2287:73514:11;;49083:24;2287:73514;49083:24;;;;;;:::i;2287:73514::-;;;;;8713:16:12;2287:73514:11;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;8712:35:12;8708:67;;49215:43:11;2287:73514;49248:9;2287:73514;;;;49215:43;;:::i;:::-;2458:4:4;;;;;;;;;49312:38:11;;;;:::i;:::-;49365:8;;;49361:48;;49773:9;;;;;;;;;;:::i;49361:48::-;2287:73514;;49382:27;;;;;;2287:73514;;;;3471:1:12;;;2287:73514:11;;;3471:1:12;;39736:29:11;2287:73514;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;:::o;1490:474:8:-;;;;;;;;;;;;1575:245;;;;;;;;;;;2287:73514:11;;46745:24;2287:73514;46745:24;;;;;;:::i;2287:73514::-;;;;;8713:16:12;2287:73514:11;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;8712:35:12;8708:67;;46877:43:11;2287:73514;46910:9;2287:73514;;;;46877:43;;:::i;:::-;2458:4:4;;;;;;;;;;46974:38:11;47307:9;46974:38;;;:::i;:::-;47307:9;;;;:::i;2287:73514::-;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::o;17361:187:12:-;2287:73514:11;;;17422:28:12;2458:4:4;17422:28:12;;2287:73514:11;;17525:16:12;2287:73514:11;;;;;17495:15:12;2287:73514:11;;;;;;;;17495:15:12;2287:73514:11;;;;;;17525:16:12;17361:187::o;12970:1638::-;13068:16;2287:73514:11;2900:6:12;2287:73514:11;;13400:26:12;2287:73514:11;;;;13382:15:12;3471:1;3185:5:11;3138:4;13871:17:12;2287:73514:11;14099:26:12;;;;14095:42;;3471:1;14310:32;;;;;14306:46;;3471:1;12970:1638;:::o;14306:46::-;14344:8;;-1:-1:-1;14344:8:12;:::o;14095:42::-;14127:10;;;:::o;50352:1017:11:-;;;-1:-1:-1;;;;;50651:28:11;;;;:::i;:::-;2287:73514;;-1:-1:-1;2287:73514:11;50799:7;2287:73514;;50781:34;2287:73514;-1:-1:-1;2287:73514:11;;50781:34;;:::i;:::-;50829:16;2287:73514;50829:38;;;;;50825:73;;3471:1:12;51100:18:11;3471:1:12;;50829:16:11;2287:73514;51100:18;:::i;:::-;51201:24;;;51197:80;;2287:73514;51337:25;2287:73514;51337:25;2287:73514;51337:25;:::i;51197:80::-;2287:73514;;51234:43;;;;;;2287:73514;;;3471:1:12;;;2287:73514:11;;;;3471:1:12;;39736:29:11;50825:73;50876:22;2287:73514;;50876:22;;;;11375:939:9;11502:806;11375:939;11502:806;11375:939;11502:806;;;;;;;;;;;;;;;;;;;;;;;;;;;;11375:939::o;11502:806::-;;;;;;;2287:73514:11;;;;;-1:-1:-1;;;;;2287:73514:11;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;:::o;17066:161:12:-;2287:73514:11;17186:34:12;17066:161;17138:33;2287:73514:11;;;;;;;;;;17138:33:12;2287:73514:11;-1:-1:-1;;;;;2287:73514:11;;;;;;17186:34:12;17066:161::o;17717:1172:3:-;17884:946;;;;2458:4:4;17884:946:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;17717:1172::o;17884:946::-;;;;;;;17717:1172;17884:946;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;17717:1172::o;19295:1119::-;;19466:887;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;19466:887:3;;;;;;;;;;;;;;;;;;19295:1119::o;54321:1955:11:-;2287:73514;;;;;54753:15;3471:1:12;54753:15:11;;;;54744:941;2287:73514;;;56149:52;2287:73514;56183:12;2287:73514;3471:1:12;;56149:52:11;:::i;:::-;54321:1955;:::o;54749:2::-;54801:18;;;;;2287:73514;;;;;;;;;;54801:18;-1:-1:-1;;;;;2287:73514:11;;54837:19;;54833:30;;54894:14;;-1:-1:-1;;;;;2287:73514:11;;;34356:7;2287:73514;;;;;;;54894:14;2287:73514;;;;54962:37;;54993:4;54801:14;54962:37;;2287:73514;;54962:37;;;;2287:73514;;;;;;54962:37;;;;;;;;54952:88;54962:37;:77;:37;;;;;54749:2;55002:37;;;;-1:-1:-1;;;;;2287:73514:11;;;74482:30;2287:73514;;;;;;;54952:88;55211:23;55207:407;;54749:2;3471:1:12;;;;54749:2:11;;;;55207:407;55312:42;55259:210;55569:30;55312:42;;3471:1:12;55312:42:11;;;:::i;55569:30::-;55207:407;;;;;;;54962:37;55002;54962;;;;;;;;;-1:-1:-1;54962:37:11;;;;;;:::i;:::-;;;;;;54833:30;54858:5;;;;;5293:468:4;5418:337;;;;;;;;;;;;;;;5293:468;:::o;5418:337::-;;;;;;;2287:73514:11;;;;;;;;;;;;;;;;;;;;;;;;;:::o;7938:186:4:-;11948:3810;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;11948:3810:4;;;;;8081:36;11948:3810;;;;;8088:28;11948:3810;8089:12;11948:3810;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8089:12;:::i;:::-;2458:4;84::28;;;;8088:28:4;8081:36;:::i;11948:3810::-;;-1:-1:-1;11948:3810:4;;;;2809:424;2934:293;-1:-1:-1;;2934:293:4;8467:15:12;2934:293:4;;;;;;;;;;2809:424;:::o;2934:293::-;;;;;;;2809:424;;2934:293;-1:-1:-1;;2934:293:4;;;;;;;;;;;2809:424;:::o;33263:586:12:-;;;2287:73514:11;33263:586:12;2287:73514:11;;33263:586:12;2287:73514:11;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;33460:382:12;;33263:586;:::o;21083:460::-;;2287:73514:11;-1:-1:-1;2287:73514:11;21235:13:12;2287:73514:11;;-1:-1:-1;;;;;2287:73514:11;-1:-1:-1;2287:73514:11;;;21231:80:12;;21321:47;2287:73514:11;-1:-1:-1;2287:73514:11;21235:13:12;2287:73514:11;;;-1:-1:-1;2287:73514:11;;-1:-1:-1;;;;;2287:73514:11;;;;;;;;;21321:47:12;21501:35;2287:73514:11;;;;;;;;;21501:35:12;2287:73514:11;21083:460:12:o;21231:80::-;21290:21;2287:73514:11;;21290:21:12;;;;911:1089:14;;;;2287:73514:11;;;;;;;1203:15:14;;;;:::i;:::-;2458:4:4;;;;;;;;;;;;;;;;;1158:180:14;;;;:::i;:::-;1543:6;;1539:372;;911:1089;1929:20;;;;911:1089;:::o;1539:372::-;1693:193;3185:5:11;;;1693:193:14;:::i;:::-;3471:1:12;;1539:372:14;;;;;;17686:221:12;2287:73514:11;;415:5:10;17752:31:12;;2287:73514:11;;;415:5:10;17879:21:12;415:5:10;2287:73514:11;17839:25:12;415:5:10;2287:73514:11;;17839:25:12;415:5:10;2287:73514:11;;;;;17879:21:12;17686:221::o;2657:952:14:-;;;;;3052:5;2657:952;3052:5;:::i;:::-;2458:4:4;;;;;;;;;;;;;;;;;;3003:182:14;;;;:::i;:::-;2458:4:4;;;;;;;;;3401:54:14;3539:20;3401:54;3348:230;3401:54;;:::i;:::-;3539:20;;:::i;3348:230::-;2458:4:4;;;;;;;3213:389:14;;;:::i;8181:1139:9:-;8326:988;;;8181:1139;;;8326:988;8181:1139;8326:988;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8181:1139::o;8326:988::-;;;;;;;18973:468:12;2287:73514:11;19091:19:12;2287:73514:11;;19197:23:12;;19193:242;;18973:468;;;:::o;19193:242::-;19404:19;19266:60;;;;:::i;:::-;19376:26;;;:::i;:::-;19404:19;;:::i;6959:512:4:-;7086:379;;;;;;;;;;;;;;;;;;;;;;;6959:512;:::o;2287:73514:11:-;;;;;;;;;;-1:-1:-1;;;;;2287:73514:11;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;2287:73514:11;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;42283:3105::-;;;;;;;;;;;;;42788:35;-1:-1:-1;;;;;2287:73514:11;;42796:26;;42788:35;:::i;:::-;42967:38;42987:16;42975:29;;42967:38;:::i;:::-;43046:25;;2287:73514;43046:25;2287:73514;43046:25;:::i;:::-;43159:60;:40;2287:73514;43183:15;2287:73514;-1:-1:-1;;;;;2287:73514:11;;;43159:60;43342:12;;;;;:::i;:::-;43159:287;;;;;;2287:73514;;43159:287;2287:73514;;;;;;;42820:1;2287:73514;;;43159:287;;;;;;;2287:73514;43159:287;;;;;;:::i;:::-;;43227:9;;43159:287;;;;;;;;;42283:3105;43882:26;2287:73514;43882:26;;;;;;;:::i;:::-;44050:12;;;;;:::i;:::-;44219;;2287:73514;;43847:445;;;;:::i;:::-;44526:12;;;;;;:::i;:::-;;;;;:::i;:::-;44850:6;44823:10;44843:4;44823:10;44850:6;;:::i;:::-;44927:3;;;;:::i;:::-;45150:24;;;;;;:::i;:::-;45188:26;;;;;;;:::i;:::-;2287:73514;;;;;;;45081:300;;;;;:::i;:::-;;;;;42283:3105::o;43159:287::-;;;;;;:::i;:::-;;;;6274:791:14;;;;2287:73514:11;;;;;;;6607:366:14;6711:203;;;;:::i;6607:366::-;2287:73514:11;;;;;;;;;;6454:575:14;;;:::i;22755:768:12:-;-1:-1:-1;2287:73514:11;22918:13:12;2287:73514:11;;;-1:-1:-1;2287:73514:11;;;;;-1:-1:-1;;;;;2287:73514:11;;23022:26:12;;;2287:73514:11;;;;;;23440:36:12;2287:73514:11;3471:1:12;23440:36;2287:73514:11;22755:768:12;:::o;20073:431::-;;-1:-1:-1;2287:73514:11;;;;20239:13:12;2287:73514:11;;-1:-1:-1;;;;;2287:73514:11;;;;;;;20235:77:12;;2287:73514:11;;;;20239:13:12;2287:73514:11;;;;;;;;;;;;;;;;20451:15:12;2287:73514:11;;;;;;;;;20073:431:12:o;:::-;;;;-1:-1:-1;2287:73514:11;;;;20239:13:12;2287:73514:11;;-1:-1:-1;;;;;2287:73514:11;;;;;;;20235:77:12;;2287:73514:11;;20322:43:12;2287:73514:11;;;20239:13:12;2287:73514:11;;;;;;-1:-1:-1;;;;;2287:73514:11;;;;;;;;;20322:43:12;2287:73514:11;;;20451:15:12;2287:73514:11;;;;;;;;;20073:431:12:o;14889:2052::-;14966:16;2287:73514:11;;15702:34:12;2287:73514:11;15280:44:12;2287:73514:11;15298:26:12;2287:73514:11;;;;;;;;;;;;;15280:44:12;:15;3471:1;3185:5:11;2900:6:12;3138:4:11;;;;15702:34:12;2287:73514:11;15770:17:12;2287:73514:11;15897:26:12;;;;15893:378;;16428:10;;;;:::i;:::-;3471:1;16721:17;;;16717:52;;15298:26;2287:73514:11;;;;15280:15:12;2287:73514:11;;;;;;;16903:31:12;;39896:17:11;2287:73514;;15893:378:12;16028:11;;;;;;16024:46;;15298:26;2287:73514:11;;;;15280:15:12;2287:73514:11;;;;;;;16215:25:12;;39896:17:11;2287:73514;;32307:696:12;;;2287:73514:11;;32307:696:12;2287:73514:11;;32307:696:12;;2287:73514:11;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;21755:788:12:-;-1:-1:-1;2287:73514:11;21939:13:12;2287:73514:11;;;-1:-1:-1;2287:73514:11;;;;;-1:-1:-1;;;;;2287:73514:11;;22039:26:12;;;2287:73514:11;;;22444:28:12;2287:73514:11;;;;-1:-1:-1;;;;;2287:73514:11;;;34764:15;2287:73514;;;;;;;22444:28:12;2287:73514:11;;;3471:1:12;2287:73514:11;;21755:788:12;:::o;4437:468:4:-;4564:335;-1:-1:-1;;4564:335:4;;;;;;;;;;;;;;;;;4437:468;:::o;8260:3442::-;8498:21;8493:26;;;8489:40;;8591:405;;;;;;9274:7;2287:73514:11;;;;11601:49:4;9569:29;2287:73514:11;10154:40:4;2287:73514:11;;9601:7:4;2287:73514:11;;;;;;;;;;;3471:1:12;;10092:35:4;2287:73514:11;9892:31:4;2287:73514:11;;;;;3471:1:12;10671:35:4;3471:1:12;;;10530:34:4;3471:1:12;;;10393:32:4;3471:1:12;;;;2287:73514:11;;;;;;;3471:1:12;2287:73514:11;;;;;;;3471:1:12;2287:73514:11;;;;;3471:1:12;2287:73514:11;9959:32:4;2287:73514:11;;;;3471:1:12;2287:73514:11;;;;;;10768:329:4;3185:5:11;3471:1:12;11663:3:4;3471:1:12;2287:73514:11;8260:3442:4;:::o;8591:405::-;;2287:73514:11;8591:405:4;;;;8489:40;8521:8;2287:73514:11;8521:8:4;:::o
Swarm Source
ipfs://5b620e5c19cd34ebff19ce0d6221c4cb20ca382d3b6b735234817ac60f7e8227
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.