Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00
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:
Index
Compiler Version
v0.8.23+commit.f704f362
Optimization Enabled:
Yes with 1000 runs
Other Settings:
shanghai EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.23;
import {IIndex} from "./interfaces/IIndex.sol";
import {IPhutureOnDepositCallback} from "./interfaces/IPhutureOnDepositCallback.sol";
import {IERC20, IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {IERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol";
import {Currency, CurrencyLib} from "./libraries/CurrencyLib.sol";
import {CurrencyRegistryLib} from "./libraries/CurrencyRegistryLib.sol";
import {FeeMathLib} from "./libraries/FeeMathLib.sol";
import {IndexLib} from "./libraries/IndexLib.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {FixedPointMathLib} from "solmate/utils/FixedPointMathLib.sol";
import {SafeCastLib} from "solmate/utils/SafeCastLib.sol";
import {Vault} from "./Vault.sol";
/// @title Index
/// @notice Core contract for the protocol, manages deposits and redemptions
contract Index is Vault, IIndex, IERC20Metadata, IERC20Permit {
using FixedPointMathLib for uint256;
using CurrencyLib for Currency;
/// @dev Internal constant flag indicating index rebalancing is in progress
uint8 internal constant INDEX_REBALANCING_FLAG = 0x10;
/// @dev Maximum deposit fee in basis points
uint16 private immutable maxDepositFeeBPs;
/// @dev Maximum redemption fee in basis points
uint16 private immutable maxRedemptionFeeBPs;
/// @dev Maximum AUM dilution per second
uint256 private immutable maxAUMDilutionPerSecond;
/// @notice Reserve currency of the index
Currency public reserve;
/// @inheritdoc IERC20Metadata
uint8 public immutable override decimals = 18;
/// @inheritdoc IERC20Metadata
string public override name;
/// @inheritdoc IERC20Metadata
string public override symbol;
/// @notice Mapping of account addresses to their balances
mapping(address => uint256) public balanceOf;
/// @notice Mapping of account addresses to their allowances for spenders
mapping(address => mapping(address => uint256)) public allowance;
/// @notice Mapping of account addresses to their nonces for EIP-712 signature
mapping(address => uint256) public nonces;
/// @dev Current state of the index
IndexState internal state;
/// @dev Hash of the shared configuration
bytes32 internal sharedConfigHash;
/// @dev Hash of the deposit configuration
bytes32 internal depositConfigHash;
/// @dev Hash of the redemption configuration
bytes32 internal redemptionConfigHash;
/// @dev Address of the fee pool contract
address internal feePool;
/// @notice Event emitted when the configuration is updated
///
/// @param encodedConfig The encoded configuration data
event ConfigUpdated(bytes encodedConfig);
/// @notice Event emitted when a deposit is made
///
/// @param sender The address that initiated the deposit
/// @param owner The address that receives the Index tokens
/// @param reserve The amount of reserve currency deposited
/// @param shares The number of Index tokens minted
event Deposit(address indexed sender, address indexed owner, uint256 reserve, uint256 shares);
/// @notice Event emitted when a withdrawal is made
///
/// @param sender The address that initiated the withdrawal
/// @param receiver The address that receives the withdrawn assets
/// @param owner The address that owns the index tokens being redeemed
/// @param shares The number of index tokens redeemed
/// @param k The k-value of the index at the time of withdrawal
/// @param reserve The amount of reserve currency withdrawn
event Withdraw(
address indexed sender,
address indexed receiver,
address indexed owner,
uint256 shares,
uint256 k,
uint256 reserve
);
/// @custom:oz-upgrades-unsafe-allow constructor
constructor(uint16 _maxDepositFeeInBPs, uint16 _maxRedemptionFeeInBPs, uint256 _maxAUMDilutionPerSecond) {
maxDepositFeeBPs = _maxDepositFeeInBPs;
maxRedemptionFeeBPs = _maxRedemptionFeeInBPs;
maxAUMDilutionPerSecond = _maxAUMDilutionPerSecond;
_disableInitializers();
}
function initialize(string memory _name, string memory _symbol, Currency _reserve, address _governance)
external
initializer
{
__Vault_init(_governance);
reserve = _reserve;
name = _name;
symbol = _symbol;
state.lastAUMAccrualTimestamp = uint32(block.timestamp);
CurrencyRegistryLib.registerCurrency(registry, _reserve);
}
/// @notice Starts the index rebalancing process
function startIndexRebalancing() external onlyOwner {
rebalancingFlags |= INDEX_REBALANCING_FLAG;
}
function mint(Currency[] calldata currencies, uint256[] calldata amounts, address recipient, uint128 shares)
external
onlyOwner
{
state.totalSupply += shares;
balanceOf[recipient] += shares;
emit Transfer(address(0), recipient, shares);
CurrencyWithdrawal memory withdrawal;
_startRebalancingPhase(withdrawal);
for (uint256 i; i < currencies.length; ++i) {
Currency currency = currencies[i];
uint256 delta = amounts[i];
SafeERC20.safeTransferFrom(IERC20(Currency.unwrap(currency)), recipient, address(this), delta);
unaccountedBalanceOf[currency] += delta;
emit Donate(currency, delta);
}
}
/// @notice Deposits funds into the index and mints index tokens
///
/// @param params The deposit parameters
/// @param cbTarget The target contract for the callback
/// @param cbData The data to pass to the callback
///
/// @return shares The number of index tokens minted
function deposit(DepositParams calldata params, address cbTarget, bytes calldata cbData)
external
payable
nonReentrant
returns (uint256 shares)
{
if (params.recipient == address(0)) revert ZeroAddressTransfer();
_checkStateAndConfig(depositConfigHash, keccak256(abi.encode(params.config)));
if (msg.sender != params.config.shared.forwarder) revert InvalidSender();
uint256 lastReserve = reserve.balanceOfSelf();
if (cbData.length > 0) IPhutureOnDepositCallback(cbTarget).phutureOnDepositCallbackV1(reserve, cbData);
uint256 deposited = reserve.balanceOfSelf() - lastReserve;
if (reserve.isNative()) deposited += msg.value;
if (deposited == 0) revert ZeroDeposit();
IndexState memory _state = state;
shares = IndexLib.deposit(
params,
_state,
IndexLib.Info(
kBalanceWads[params.config.shared.latestSnapshot][address(this)],
maxAUMDilutionPerSecond,
maxDepositFeeBPs
),
SafeCastLib.safeCastTo96(deposited)
);
state = _state;
balanceOf[params.recipient] += shares;
emit Deposit(msg.sender, params.recipient, deposited, shares);
emit Transfer(address(0), params.recipient, shares);
}
/// @notice Redeems index tokens and withdraws the underlying assets
///
/// @param params The redemption parameters
/// @param forwardedSender The address of the sender forwarded by the forwarder contract
/// @param recipient The address that receives the withdrawn assets
///
/// @return result The redemption information
function redeem(RedemptionParams calldata params, address forwardedSender, address recipient)
external
nonReentrant
returns (RedemptionInfo memory result)
{
_checkStateAndConfig(redemptionConfigHash, keccak256(abi.encode(params.config)));
if (msg.sender != params.config.shared.forwarder) revert InvalidSender();
if (forwardedSender != params.owner) {
_spendAllowance(params.shares, params.owner, forwardedSender);
}
IndexState memory _state = state;
result = IndexLib.redeem(
forwardedSender,
params,
_state,
IndexLib.Info(
kBalanceWads[params.config.shared.latestSnapshot][address(this)],
maxAUMDilutionPerSecond,
maxRedemptionFeeBPs
)
);
state = _state;
result.accountBalanceSharesBeforeRedeem = balanceOf[params.owner];
balanceOf[params.owner] = result.accountBalanceSharesBeforeRedeem - params.shares;
// withdrawal logic
_burnSnapshot(params.config.shared.latestSnapshot, address(this), result.accountKRedeemed);
for (uint256 i; i < params.config.currencies.length; ++i) {
Currency currency = params.config.currencies[i];
uint256 value = params.config.balances[i];
uint256 assets = result.accountKRedeemed.mulWadDown(value);
if (i == 0) assets += result.accountReserveRedeemed;
if (assets != 0) currency.transfer(recipient, assets);
}
emit Withdraw(
forwardedSender,
recipient,
params.owner,
params.shares,
result.accountKRedeemed,
result.accountReserveRedeemed
);
emit Transfer(params.owner, address(0), params.shares);
}
/// @notice Accrues the accumulated fees to the specified recipient
///
/// @param recipient The address that receives the accrued fees
function accrueFee(address recipient) external {
if (msg.sender != feePool) revert InvalidSender();
uint96 _fees = state.fees;
balanceOf[recipient] += _fees;
state.fees = 0;
emit IndexLib.FeeSettled(_fees);
emit Transfer(address(this), recipient, _fees);
}
/// @inheritdoc IERC20
function transfer(address to, uint256 amount) external override returns (bool) {
_transfer(msg.sender, to, amount);
return true;
}
/// @inheritdoc IERC20
function approve(address spender, uint256 amount) external override returns (bool) {
allowance[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
/// @inheritdoc IERC20
function transferFrom(address from, address to, uint256 amount) external override returns (bool) {
_spendAllowance(amount, from, msg.sender);
_transfer(from, to, amount);
return true;
}
/// @inheritdoc IERC20Permit
function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
external
{
if (deadline < block.timestamp) revert PermitDeadlineExpired();
// Unchecked because the only math done is incrementing
// the owner's nonce which cannot realistically overflow.
unchecked {
address recoveredAddress = ecrecover(
keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR(),
keccak256(
abi.encode(
keccak256(
"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
),
owner,
spender,
value,
nonces[owner]++,
deadline
)
)
)
),
v,
r,
s
);
if (recoveredAddress == address(0) || recoveredAddress != owner) revert InvalidSigner();
allowance[recoveredAddress][spender] = value;
}
emit Approval(owner, spender, value);
}
/// @notice Sets the address of the fee pool contract
///
/// @param _feePool The address of the fee pool contract
function setFeePool(address _feePool) external onlyOwner {
feePool = _feePool;
}
/// @notice Retrieves the current reserve balance of the index
///
/// @return The reserve balance
function reserveBalance() external view returns (uint96) {
return state.reserve;
}
/// @notice Retrieves the value k for current snapshot
/// @return The k value
function kSelf() external view returns (uint256) {
return kBalanceWads[anatomySnapshot][address(this)];
}
/// @inheritdoc IERC20
function totalSupply() external view override returns (uint256) {
return state.totalSupply;
}
/// @notice Retrieves the current accumulated fees of the index
///
/// @return The accumulated fees
function fees() external view override returns (uint256) {
return state.fees;
}
/// @notice Sets the configuration for the index
///
/// @dev sanitization is done externally. Ensure that assets include reserve,
/// to simplify before-after currency balance caching in redemptions
///
/// @param _prevConfig The previous configuration
/// @param _depositConfig The new deposit configuration
/// @param _redemptionConfig The new redemption configuration
function setConfig(
Config calldata _prevConfig,
DepositConfig calldata _depositConfig,
RedemptionConfig calldata _redemptionConfig
) public virtual onlyOwner {
if (rebalancingFlags == 0) revert Rebalancing();
bytes memory encodedConfig = abi.encode(_depositConfig.shared);
if (keccak256(encodedConfig) != keccak256(abi.encode(_redemptionConfig.shared))) {
revert IndexConfigMismatch();
}
// non-initial config setup index
if (sharedConfigHash == hex"") {
if (_redemptionConfig.currencies.length != 1) revert IndexInitialConfig();
} else {
if (sharedConfigHash != keccak256(abi.encode(_prevConfig))) revert IndexConfigMismatch();
uint96 AUMFee;
IndexState memory _state = state;
(_state.totalSupply, AUMFee) = IndexLib.accrueAUMFee(_prevConfig, _state, maxAUMDilutionPerSecond);
if (AUMFee != 0) {
_state.fees += AUMFee;
state = _state;
emit IndexLib.FeeAccrued(0, 0, AUMFee);
emit Transfer(address(0), address(this), AUMFee);
}
}
if (
_depositConfig.fee.BPs > maxDepositFeeBPs || _redemptionConfig.fee.BPs > maxRedemptionFeeBPs
|| _depositConfig.shared.AUMDilutionPerSecond < FeeMathLib.RATE_SCALE_BASE
|| _depositConfig.shared.AUMDilutionPerSecond > maxAUMDilutionPerSecond
) revert IndexLib.FeeExceedsMaxFee();
sharedConfigHash = keccak256(encodedConfig);
depositConfigHash = keccak256(abi.encode(_depositConfig));
redemptionConfigHash = keccak256(abi.encode(_redemptionConfig));
rebalancingFlags &= ~INDEX_REBALANCING_FLAG;
emit ConfigUpdated(encodedConfig);
}
/// @notice Retrieves the domain separator for EIP-712 signatures
///
/// @return The domain separator
function DOMAIN_SEPARATOR() public view returns (bytes32) {
return keccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes(name)),
keccak256("1"),
block.chainid,
address(this)
)
);
}
/// @dev Transfers tokens from one address to another
///
/// @param from The address to transfer tokens from
/// @param to The address to transfer tokens to
/// @param amount The amount of tokens to transfer
function _transfer(address from, address to, uint256 amount) internal {
if (to == address(0)) revert ZeroAddressTransfer();
balanceOf[from] -= amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(from, to, amount);
}
/// @dev Spends the allowance of the spender on behalf of the owner
///
/// @param amount The amount of tokens to spend
/// @param from The address of the token owner
/// @param to The address of the spender
function _spendAllowance(uint256 amount, address from, address to) internal {
// Saves gas for limited approvals.
uint256 allowed = allowance[from][to];
if (allowed != type(uint256).max) {
allowance[from][to] = allowed - amount;
}
}
/// @dev Starts the rebalancing phase and processes withdrawals
///
/// @param withdrawal The currency withdrawals to process
function _startRebalancingPhase(CurrencyWithdrawal memory withdrawal) internal override {
if (rebalancingFlags & INDEX_REBALANCING_FLAG == 0) revert Rebalancing();
uint96 reserveAmount = state.reserve;
unaccountedBalanceOf[reserve] += reserveAmount;
state.reserve = 0;
emit Donate(reserve, reserveAmount);
super._startRebalancingPhase(withdrawal);
}
/// @dev Checks the state and configuration hashes
///
/// @param storedHash The stored configuration hash
/// @param newConfigHash The new configuration hash
function _checkStateAndConfig(bytes32 storedHash, bytes32 newConfigHash) private view {
if (rebalancingFlags != 0) revert Rebalancing();
if (storedHash != newConfigHash) revert IndexConfigHash();
}
}// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.23;
import {IVault} from "./IVault.sol";
import {Currency} from "../libraries/CurrencyLib.sol";
interface IIndex is IVault {
struct IndexState {
uint128 totalSupply;
uint96 fees;
uint32 lastAUMAccrualTimestamp;
uint96 reserve;
}
struct Config {
uint256 latestSnapshot; // needed to get the latest k value
uint256 AUMDilutionPerSecond;
bool useCustomAUMFee;
address staticPriceOracle;
address metadata;
address forwarder;
}
struct FeeConfig {
uint16 BPs;
bool useCustomCallback;
}
struct DepositConfig {
Config shared;
FeeConfig fee;
}
struct RedemptionConfig {
Config shared;
FeeConfig fee;
Currency[] currencies; // Reserve currency + Vault's currencies
uint256[] balances;
}
struct DepositParams {
DepositConfig config;
address recipient;
bytes payload;
}
struct RedemptionParams {
RedemptionConfig config;
address owner;
uint128 shares;
bytes payload;
}
struct RedemptionInfo {
uint256 reserveValuation;
uint256 totalValuation;
uint256 totalReserveShares;
uint128 totalSupplyAfterAUMAccrual;
uint256 totalKBeforeRedeem;
uint256 accountBalanceSharesBeforeRedeem;
uint96 accountReserveRedeemed;
uint256 accountReserveSharesRedeemed;
uint256 accountKRedeemed;
uint256 reservePriceInQ128;
}
error IndexConfigHash();
error IndexConfigMismatch();
error IndexInitialConfig();
error PermitDeadlineExpired();
error InvalidSigner();
error ZeroAddressTransfer();
error InvalidSender();
error ZeroDeposit();
function deposit(DepositParams calldata params, address cbTarget, bytes calldata cbData)
external
payable
returns (uint256 shares);
function redeem(RedemptionParams calldata params, address forwardedSender, address recipient)
external
returns (RedemptionInfo memory redeemed);
function startIndexRebalancing() external;
function mint(Currency[] calldata currencies, uint256[] calldata amounts, address recipient, uint128 shares)
external;
function setConfig(
Config calldata _prevConfig,
DepositConfig calldata _depositConfig,
RedemptionConfig calldata _redemptionConfig
) external;
function setFeePool(address feePool) external;
function accrueFee(address recipient) external;
function reserve() external view returns (Currency);
function reserveBalance() external view returns (uint96);
function kSelf() external view returns (uint256);
function fees() external view returns (uint256);
}// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.23;
import {Currency} from "../libraries/CurrencyLib.sol";
interface IPhutureOnDepositCallback {
function phutureOnDepositCallbackV1(Currency reserve, bytes calldata) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*
* _Available since v4.1._
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;
import {IERC20, SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
type Currency is address;
using {eq as ==, neq as !=} for Currency global;
function eq(Currency currency, Currency other) pure returns (bool) {
return Currency.unwrap(currency) == Currency.unwrap(other);
}
function neq(Currency currency, Currency other) pure returns (bool) {
return !eq(currency, other);
}
/// @title CurrencyLibrary
/// @dev This library allows for transferring and holding native tokens and ERC20 tokens
/// @author Modified from Uniswap (https://github.com/Uniswap/v4-core/blob/main/src/types/Currency.sol)
library CurrencyLib {
using SafeERC20 for IERC20;
using CurrencyLib for Currency;
/// @dev Currency wrapper for native currency
Currency public constant NATIVE = Currency.wrap(address(0));
/// @notice Thrown when a native transfer fails
error NativeTransferFailed();
/// @notice Thrown when an ERC20 transfer fails
error ERC20TransferFailed();
/// @notice Thrown when deposit amount exceeds current balance
error AmountExceedsBalance();
/// @notice Transfers currency
///
/// @param currency Currency to transfer
/// @param to Address of recipient
/// @param amount Currency amount ot transfer
function transfer(Currency currency, address to, uint256 amount) internal {
if (amount == 0) return;
// implementation from
// https://github.com/transmissions11/solmate/blob/e8f96f25d48fe702117ce76c79228ca4f20206cb/src/utils/SafeTransferLib.sol
bool success;
if (currency.isNative()) {
assembly {
// Transfer the ETH and store if it succeeded or not.
success := call(gas(), to, amount, 0, 0, 0, 0)
}
if (!success) revert NativeTransferFailed();
} else {
assembly {
// We'll write our calldata to this slot below, but restore it later.
let freeMemoryPointer := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.
mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.
success :=
and(
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data.
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
// We use 68 because that's the total length of our calldata (4 + 32 * 2)
// Counterintuitively, this call() must be positioned after the or() in the
// surrounding and() because and() evaluates its arguments from right to left.
call(gas(), currency, 0, freeMemoryPointer, 68, 0, 32)
)
}
if (!success) revert ERC20TransferFailed();
}
}
/// @notice Approves currency
///
/// @param currency Currency to approve
/// @param spender Address of spender
/// @param amount Currency amount to approve
function approve(Currency currency, address spender, uint256 amount) internal {
if (isNative(currency)) return;
IERC20(Currency.unwrap(currency)).forceApprove(spender, amount);
}
/// @notice Returns the balance of a given currency for a specific account
///
/// @param currency The currency to check
/// @param account The address of the account
///
/// @return The balance of the specified currency for the given account
function balanceOf(Currency currency, address account) internal view returns (uint256) {
return currency.isNative() ? account.balance : IERC20(Currency.unwrap(currency)).balanceOf(account);
}
/// @notice Returns the balance of a given currency for this contract
///
/// @param currency The currency to check
///
/// @return The balance of the specified currency for this contract
function balanceOfSelf(Currency currency) internal view returns (uint256) {
return currency.isNative() ? address(this).balance : IERC20(Currency.unwrap(currency)).balanceOf(address(this));
}
/// @notice Checks if the specified currency is the native currency
///
/// @param currency The currency to check
///
/// @return `true` if the specified currency is the native currency, `false` otherwise
function isNative(Currency currency) internal pure returns (bool) {
return currency == NATIVE;
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.23;
import {Currency} from "./CurrencyLib.sol";
/// @title CurrencyRegistryLib
/// @notice A library for managing a registry of currencies
library CurrencyRegistryLib {
/// @dev Represents a currency registry
struct Registry {
// Array of registered assets
Currency[] currencies;
// Hash of registry state
bytes32 currenciesHash;
// Registered flag for given currency
mapping(Currency => bool) registered;
}
/// @notice Thrown when trying to register an already registered currency.
/// @param currency The currency that is already registered
error Registered(Currency currency);
/// @notice Registers a new currency in the registry
///
/// @param self The registry where the currency will be registered
/// @param currency The currency to register
///
/// @return newHash The new hash of the updated registry
function registerCurrency(Registry storage self, Currency currency) internal returns (bytes32 newHash) {
if (self.registered[currency]) revert Registered(currency);
self.currencies.push(currency);
newHash = keccak256(abi.encode(self.currenciesHash, currency));
self.currenciesHash = newHash;
self.registered[currency] = true;
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.23;
import {FixedPointMathLib} from "solmate/utils/FixedPointMathLib.sol";
import {SafeCastLib} from "solmate/utils/SafeCastLib.sol";
/// @title FeeMathLib
/// @notice Library for fee calculations.
library FeeMathLib {
using FixedPointMathLib for *;
using SafeCastLib for uint256;
uint16 internal constant MAX_BPS = 10_000;
uint256 internal constant RATE_SCALE_BASE = 1e27;
/// @notice Accrues the total supply AUM fee based on the AUM dilution per second.
///
/// @dev The AUM dilution per second is calculated using the formula:
/// AUMDilutionPerSecond = ((1 + k) ** (1 / 31_556_952)) * 1e27
/// where:
/// - 31_556_952 represents the average number of seconds in a Gregorian year (365.2425 days)
/// - k is the AUM fee expressed as a percentage (e.g., 100% = 1)
///
/// This formula calculates the dilution factor per second based on the annual AUM fee percentage.
/// The dilution factor is then scaled by 1e27 to maintain precision.
///
/// The AUM fee is accrued by multiplying the total supply by the dilution factor raised to the power
/// of the time passed since the last accrual. The result is then divided by the rate scale base (1e27)
/// to obtain the actual AUM fee amount.
///
/// @param AUMDilutionPerSecond The AUM dilution per second.
/// @param totalSupply The current total supply.
/// @param lastAUMAccrualTimestamp The timestamp of the last AUM accrual.
/// @param currentTimestamp The current timestamp.
///
/// @return newTotalSupply The updated total supply after accruing the AUM fee.
/// @return newLastAUMAccrualTimestamp The updated timestamp of the last AUM accrual.
/// @return AUMFee The accrued AUM fee.
function accrueTotalSupplyAUMFee(
uint256 AUMDilutionPerSecond,
uint128 totalSupply,
uint32 lastAUMAccrualTimestamp,
uint256 currentTimestamp
) internal pure returns (uint128 newTotalSupply, uint32 newLastAUMAccrualTimestamp, uint96 AUMFee) {
newTotalSupply = totalSupply;
newLastAUMAccrualTimestamp = uint32(currentTimestamp);
if (AUMDilutionPerSecond > RATE_SCALE_BASE) {
uint256 timePassed;
unchecked {
timePassed = newLastAUMAccrualTimestamp - lastAUMAccrualTimestamp;
}
if (timePassed != 0) {
uint256 numerator = AUMDilutionPerSecond.rpow(timePassed, RATE_SCALE_BASE) - RATE_SCALE_BASE;
AUMFee = totalSupply.mulDivDown(numerator, RATE_SCALE_BASE).safeCastTo96();
newTotalSupply += AUMFee;
}
}
}
/// @notice Calculates the net shares and fee based on the gross shares and fee basis points.
///
/// @param grossShares The gross number of shares.
/// @param feeBPs The fee in basis points (BPs).
///
/// @return netShares The net number of shares after deducting the fee.
/// @return fee The calculated fee.
function accrueFee(uint128 grossShares, uint16 feeBPs) internal pure returns (uint128 netShares, uint96 fee) {
unchecked {
fee = uint256(grossShares).mulDivDown(feeBPs, MAX_BPS).safeCastTo96();
netShares = grossShares - fee;
}
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.23;
import {IIndex} from "../interfaces/IIndex.sol";
import {IIndexMetadata} from "../interfaces/IIndexMetadata.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IStaticPriceOracle} from "../price-oracles/interfaces/IStaticPriceOracle.sol";
import {PriceLib} from "../price-oracles/libraries/PriceLib.sol";
import {FeeMathLib} from "./FeeMathLib.sol";
import {IndexConversionLib} from "./IndexConversionLib.sol";
import {FixedPointMathLib} from "solmate/utils/FixedPointMathLib.sol";
/// @title IndexLib
/// @notice A library for managing index operations
library IndexLib {
using FixedPointMathLib for uint256;
using PriceLib for *;
/// @notice Represents the information required for index operations
struct Info {
uint256 kSelf;
uint256 maxAUMDilutionPerSecond;
uint16 maxFeeBPs;
}
/// @notice Event emitted when fees are accrued
/// @param depositFee The base deposit fee accrued
/// @param redemptionFee The base redemption fee accrued
/// @param AUMFee The AUM fee accrued
event FeeAccrued(uint96 depositFee, uint96 redemptionFee, uint96 AUMFee);
/// @notice Event emitted when fees are settled
/// @param fee The fee settled
event FeeSettled(uint96 fee);
/// @notice Thrown when the number of shares is zero
error ZeroShares();
/// @notice Thrown when the fee exceeds the maximum fee
error FeeExceedsMaxFee();
/// @notice Performs a deposit into the index
///
/// @param params The deposit parameters
/// @param state The current index state
/// @param info The index information
/// @param deposited The amount of assets deposited
///
/// @return netShares The net amount of shares minted after fees
function deposit(
IIndex.DepositParams calldata params,
IIndex.IndexState memory state,
Info memory info,
uint96 deposited
) internal returns (uint256 netShares) {
// accrue AUM fee
(uint128 totalSupplyAfterAUMAccrual, uint96 AUMFee) =
accrueAUMFee(params.config.shared, state, info.maxAUMDilutionPerSecond);
uint128 grossShares;
{
(uint256 _totalAssets,, uint256 reservePrice) =
totalAssets(params.config.shared, params.payload, state.reserve, info.kSelf);
grossShares = IndexConversionLib.convertToShares(
deposited.convertToBaseDown(reservePrice), totalSupplyAfterAUMAccrual, _totalAssets
);
}
uint96 depositFee;
(netShares, depositFee) =
_getFee(true, msg.sender, info.maxFeeBPs, grossShares, params.config.fee, params.config.shared, state);
uint96 totalFees = depositFee + AUMFee;
emit IERC20.Transfer(address(0), address(this), totalFees);
state.fees += totalFees;
emit FeeAccrued(depositFee, 0, AUMFee);
if (netShares == 0) revert ZeroShares();
state.reserve += deposited;
state.totalSupply = totalSupplyAfterAUMAccrual + grossShares;
}
/// @notice Performs a redemption from the index
///
/// @param sender The address initiating the redemption
/// @param params The redemption parameters
/// @param state The current index state
/// @param info The index information
///
/// @return result The information about the redemption operation result
function redeem(
address sender,
IIndex.RedemptionParams calldata params,
IIndex.IndexState memory state,
Info memory info
) internal returns (IIndex.RedemptionInfo memory result) {
if (params.shares == 0) revert ZeroShares();
result.totalKBeforeRedeem = info.kSelf;
uint96 AUMFee;
(result.totalSupplyAfterAUMAccrual, AUMFee) =
accrueAUMFee(params.config.shared, state, info.maxAUMDilutionPerSecond);
(uint128 netShares, uint96 redemptionFee) =
_getFee(false, sender, info.maxFeeBPs, params.shares, params.config.fee, params.config.shared, state);
uint96 totalFees = redemptionFee + AUMFee;
emit IERC20.Transfer(address(0), address(this), totalFees);
state.fees += totalFees;
emit FeeAccrued(0, redemptionFee, AUMFee);
(result.totalValuation, result.reserveValuation, result.reservePriceInQ128) =
totalAssets(params.config.shared, params.payload, state.reserve, info.kSelf);
(result.accountReserveRedeemed, result.accountReserveSharesRedeemed, result.totalReserveShares) =
_calculateReserveRedeemed(
netShares, result.totalSupplyAfterAUMAccrual, state.reserve, result.reserveValuation, result.totalValuation
);
result.accountKRedeemed = _calculateKRedeemed(
info.kSelf, result.accountReserveSharesRedeemed, netShares, result.totalSupplyAfterAUMAccrual
);
state.totalSupply = result.totalSupplyAfterAUMAccrual - netShares;
state.reserve -= result.accountReserveRedeemed;
}
/// @notice Calculates the total assets and reserve valuation of the index
///
/// @param config The index configuration
/// @param payload The payload data for the static price oracle
/// @param reserveBalance The balance of the reserve asset
/// @param kSelf The current value of kSelf
///
/// @return _totalAssets The total assets of the index
/// @return reserveValuation The valuation of the reserve asset
/// @return reservePrice The price of the reserve asset
function totalAssets(IIndex.Config calldata config, bytes calldata payload, uint256 reserveBalance, uint256 kSelf)
internal
returns (uint256 _totalAssets, uint256 reserveValuation, uint256 reservePrice)
{
(reservePrice, _totalAssets) = IStaticPriceOracle(config.staticPriceOracle).valuation(payload);
reserveValuation = reserveBalance.convertToBaseDown(reservePrice);
_totalAssets = _totalAssets.mulWadDown(kSelf) + reserveValuation;
}
/// @notice Accrues the AUM fee for the index
///
/// @param config The index configuration
/// @param state The current index state
/// @param maxAUMDilutionPerSecond The maximum allowed AUM dilution per second
///
/// @return totalSupplyAfterAUMAccrual The total supply after AUM fee accrual
/// @return AUMFee The accrued AUM fee
function accrueAUMFee(
IIndex.Config calldata config,
IIndex.IndexState memory state,
uint256 maxAUMDilutionPerSecond
) internal view returns (uint128 totalSupplyAfterAUMAccrual, uint96 AUMFee) {
uint256 AUMDilutionPerSecond;
if (config.useCustomAUMFee) {
AUMDilutionPerSecond = IIndexMetadata(config.metadata).AUMDilutionPerSecond(config, state);
if (AUMDilutionPerSecond > maxAUMDilutionPerSecond) revert FeeExceedsMaxFee();
} else {
// AUMDilutionPerSecond cannot exceed max, config setter shouldn't allow that
AUMDilutionPerSecond = config.AUMDilutionPerSecond;
}
uint32 AUMAccrualTimestamp;
(totalSupplyAfterAUMAccrual, AUMAccrualTimestamp, AUMFee) = FeeMathLib.accrueTotalSupplyAUMFee(
AUMDilutionPerSecond, state.totalSupply, state.lastAUMAccrualTimestamp, block.timestamp
);
state.lastAUMAccrualTimestamp = AUMAccrualTimestamp;
}
/// @dev Calculates the deposit or redemption fee
///
/// @param isDeposit Whether the operation is a deposit (true) or redemption (false)
/// @param sender The address initiating the operation
/// @param maxFeeBPs The maximum allowed fee in basis points
/// @param shares The number of shares being deposited or redeemed
/// @param fee The fee configuration
/// @param config The index configuration
/// @param state The current index state
///
/// @return netShares The net number of shares after deducting the fee
/// @return fees The calculated fee
function _getFee(
bool isDeposit,
address sender,
uint16 maxFeeBPs,
uint128 shares,
IIndex.FeeConfig calldata fee,
IIndex.Config calldata config,
IIndex.IndexState memory state
) private view returns (uint128 netShares, uint96 fees) {
uint16 feeBPs = fee.BPs;
if (fee.useCustomCallback) {
feeBPs = isDeposit
? IIndexMetadata(config.metadata).depositFeeInBPs(config, state, shares, sender)
: IIndexMetadata(config.metadata).redemptionFeeInBPs(config, state, shares, sender);
if (feeBPs > maxFeeBPs) revert FeeExceedsMaxFee();
}
return FeeMathLib.accrueFee(shares, feeBPs);
}
/// @dev Calculates the amount of reserve assets to be redeemed
///
/// @param netRedeemedShares The net number of shares being redeemed
/// @param totalSupplyAfterAUMAccrual The total supply after AUM fee accrual
/// @param reserveBalance The balance of the reserve asset
/// @param reserveValuation The valuation of the reserve asset
/// @param totalValuation The total valuation of the index
///
/// @return reserveRedeemed The amount of reserve assets to be redeemed
/// @return reserveSharesRedeemed The number of reserve shares redeemed
function _calculateReserveRedeemed(
uint256 netRedeemedShares,
uint256 totalSupplyAfterAUMAccrual,
uint96 reserveBalance,
uint256 reserveValuation,
uint256 totalValuation
) private pure returns (uint96 reserveRedeemed, uint256 reserveSharesRedeemed, uint256 totalReserveShares) {
if (totalValuation != 0) {
totalReserveShares = reserveValuation.mulDivUp(totalSupplyAfterAUMAccrual, totalValuation);
}
reserveSharesRedeemed = netRedeemedShares < totalReserveShares ? netRedeemedShares : totalReserveShares;
if (totalReserveShares != 0) {
// safe cast, reserve shares * (2^96-1) / total reserve shares <= (2^96-1)
reserveRedeemed = uint96(reserveSharesRedeemed.mulDivDown(reserveBalance, totalReserveShares));
}
}
/// @dev Calculates the value of redeemed k
///
/// @param totalFixedAnatomyShares The total number of fixed anatomy shares
/// @param reserveSharesRedeemed The number of reserve shares redeemed
/// @param netRedeemedShares The net number of shares being redeemed
/// @param totalSupplyAfterAUMAccrual The total supply after AUM fee accrual
///
/// @return kRedeemed The calculated value of k to be redeemed
function _calculateKRedeemed(
uint256 totalFixedAnatomyShares,
uint256 reserveSharesRedeemed,
uint256 netRedeemedShares,
uint256 totalSupplyAfterAUMAccrual
) private pure returns (uint256 kRedeemed) {
unchecked {
// cannot overflow, burned reserve shares are always less than or equal to total supply
uint256 totalSupplyAfterReserveRedemption = totalSupplyAfterAUMAccrual - reserveSharesRedeemed;
// cannot overflow, burned reserve shares are always less than or equal to net redeemed shares
if (totalSupplyAfterReserveRedemption == 0) return 0;
uint256 sharesAfterReserveRedemption = netRedeemedShares - reserveSharesRedeemed;
return sharesAfterReserveRedemption.mulDivDown(totalFixedAnatomyShares, totalSupplyAfterReserveRedemption);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(IERC20 token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
* Revert on invalid signature.
*/
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return
success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
/// @notice Arithmetic library with operations for fixed-point numbers.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol)
/// @author Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol)
library FixedPointMathLib {
/*//////////////////////////////////////////////////////////////
SIMPLIFIED FIXED POINT OPERATIONS
//////////////////////////////////////////////////////////////*/
uint256 internal constant MAX_UINT256 = 2**256 - 1;
uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s.
function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down.
}
function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up.
}
function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down.
}
function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up.
}
/*//////////////////////////////////////////////////////////////
LOW LEVEL FIXED POINT OPERATIONS
//////////////////////////////////////////////////////////////*/
function mulDivDown(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))
if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {
revert(0, 0)
}
// Divide x * y by the denominator.
z := div(mul(x, y), denominator)
}
}
function mulDivUp(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))
if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {
revert(0, 0)
}
// If x * y modulo the denominator is strictly greater than 0,
// 1 is added to round up the division of x * y by the denominator.
z := add(gt(mod(mul(x, y), denominator), 0), div(mul(x, y), denominator))
}
}
function rpow(
uint256 x,
uint256 n,
uint256 scalar
) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
switch x
case 0 {
switch n
case 0 {
// 0 ** 0 = 1
z := scalar
}
default {
// 0 ** n = 0
z := 0
}
}
default {
switch mod(n, 2)
case 0 {
// If n is even, store scalar in z for now.
z := scalar
}
default {
// If n is odd, store x in z for now.
z := x
}
// Shifting right by 1 is like dividing by 2.
let half := shr(1, scalar)
for {
// Shift n right by 1 before looping to halve it.
n := shr(1, n)
} n {
// Shift n right by 1 each iteration to halve it.
n := shr(1, n)
} {
// Revert immediately if x ** 2 would overflow.
// Equivalent to iszero(eq(div(xx, x), x)) here.
if shr(128, x) {
revert(0, 0)
}
// Store x squared.
let xx := mul(x, x)
// Round to the nearest number.
let xxRound := add(xx, half)
// Revert if xx + half overflowed.
if lt(xxRound, xx) {
revert(0, 0)
}
// Set x to scaled xxRound.
x := div(xxRound, scalar)
// If n is even:
if mod(n, 2) {
// Compute z * x.
let zx := mul(z, x)
// If z * x overflowed:
if iszero(eq(div(zx, x), z)) {
// Revert if x is non-zero.
if iszero(iszero(x)) {
revert(0, 0)
}
}
// Round to the nearest number.
let zxRound := add(zx, half)
// Revert if zx + half overflowed.
if lt(zxRound, zx) {
revert(0, 0)
}
// Return properly scaled zxRound.
z := div(zxRound, scalar)
}
}
}
}
}
/*//////////////////////////////////////////////////////////////
GENERAL NUMBER UTILITIES
//////////////////////////////////////////////////////////////*/
function sqrt(uint256 x) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
let y := x // We start y at x, which will help us make our initial estimate.
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.
// We check y >= 2^(k + 8) but shift right by k bits
// each branch to ensure that if x >= 256, then y >= 256.
if iszero(lt(y, 0x10000000000000000000000000000000000)) {
y := shr(128, y)
z := shl(64, z)
}
if iszero(lt(y, 0x1000000000000000000)) {
y := shr(64, y)
z := shl(32, z)
}
if iszero(lt(y, 0x10000000000)) {
y := shr(32, y)
z := shl(16, z)
}
if iszero(lt(y, 0x1000000)) {
y := shr(16, y)
z := shl(8, 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(y, 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
// Since the ceil is rare, we save gas on the assignment and repeat division in the rare case.
// If you don't care whether the floor or ceil square root is returned, you can remove this statement.
z := sub(z, lt(div(x, z), z))
}
}
function unsafeMod(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Mod x by y. Note this will return
// 0 instead of reverting if y is zero.
z := mod(x, y)
}
}
function unsafeDiv(uint256 x, uint256 y) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
// Divide x by y. Note this will return
// 0 instead of reverting if y is zero.
r := div(x, y)
}
}
function unsafeDivUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Add 1 to x * y if x % y > 0. Note this will
// return 0 instead of reverting if y is zero.
z := add(gt(mod(x, y), 0), div(x, y))
}
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
/// @notice Safe unsigned integer casting library that reverts on overflow.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeCastLib.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/SafeCast.sol)
library SafeCastLib {
function safeCastTo248(uint256 x) internal pure returns (uint248 y) {
require(x < 1 << 248);
y = uint248(x);
}
function safeCastTo240(uint256 x) internal pure returns (uint240 y) {
require(x < 1 << 240);
y = uint240(x);
}
function safeCastTo232(uint256 x) internal pure returns (uint232 y) {
require(x < 1 << 232);
y = uint232(x);
}
function safeCastTo224(uint256 x) internal pure returns (uint224 y) {
require(x < 1 << 224);
y = uint224(x);
}
function safeCastTo216(uint256 x) internal pure returns (uint216 y) {
require(x < 1 << 216);
y = uint216(x);
}
function safeCastTo208(uint256 x) internal pure returns (uint208 y) {
require(x < 1 << 208);
y = uint208(x);
}
function safeCastTo200(uint256 x) internal pure returns (uint200 y) {
require(x < 1 << 200);
y = uint200(x);
}
function safeCastTo192(uint256 x) internal pure returns (uint192 y) {
require(x < 1 << 192);
y = uint192(x);
}
function safeCastTo184(uint256 x) internal pure returns (uint184 y) {
require(x < 1 << 184);
y = uint184(x);
}
function safeCastTo176(uint256 x) internal pure returns (uint176 y) {
require(x < 1 << 176);
y = uint176(x);
}
function safeCastTo168(uint256 x) internal pure returns (uint168 y) {
require(x < 1 << 168);
y = uint168(x);
}
function safeCastTo160(uint256 x) internal pure returns (uint160 y) {
require(x < 1 << 160);
y = uint160(x);
}
function safeCastTo152(uint256 x) internal pure returns (uint152 y) {
require(x < 1 << 152);
y = uint152(x);
}
function safeCastTo144(uint256 x) internal pure returns (uint144 y) {
require(x < 1 << 144);
y = uint144(x);
}
function safeCastTo136(uint256 x) internal pure returns (uint136 y) {
require(x < 1 << 136);
y = uint136(x);
}
function safeCastTo128(uint256 x) internal pure returns (uint128 y) {
require(x < 1 << 128);
y = uint128(x);
}
function safeCastTo120(uint256 x) internal pure returns (uint120 y) {
require(x < 1 << 120);
y = uint120(x);
}
function safeCastTo112(uint256 x) internal pure returns (uint112 y) {
require(x < 1 << 112);
y = uint112(x);
}
function safeCastTo104(uint256 x) internal pure returns (uint104 y) {
require(x < 1 << 104);
y = uint104(x);
}
function safeCastTo96(uint256 x) internal pure returns (uint96 y) {
require(x < 1 << 96);
y = uint96(x);
}
function safeCastTo88(uint256 x) internal pure returns (uint88 y) {
require(x < 1 << 88);
y = uint88(x);
}
function safeCastTo80(uint256 x) internal pure returns (uint80 y) {
require(x < 1 << 80);
y = uint80(x);
}
function safeCastTo72(uint256 x) internal pure returns (uint72 y) {
require(x < 1 << 72);
y = uint72(x);
}
function safeCastTo64(uint256 x) internal pure returns (uint64 y) {
require(x < 1 << 64);
y = uint64(x);
}
function safeCastTo56(uint256 x) internal pure returns (uint56 y) {
require(x < 1 << 56);
y = uint56(x);
}
function safeCastTo48(uint256 x) internal pure returns (uint48 y) {
require(x < 1 << 48);
y = uint48(x);
}
function safeCastTo40(uint256 x) internal pure returns (uint40 y) {
require(x < 1 << 40);
y = uint40(x);
}
function safeCastTo32(uint256 x) internal pure returns (uint32 y) {
require(x < 1 << 32);
y = uint32(x);
}
function safeCastTo24(uint256 x) internal pure returns (uint24 y) {
require(x < 1 << 24);
y = uint24(x);
}
function safeCastTo16(uint256 x) internal pure returns (uint16 y) {
require(x < 1 << 16);
y = uint16(x);
}
function safeCastTo8(uint256 x) internal pure returns (uint8 y) {
require(x < 1 << 8);
y = uint8(x);
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.23;
import {IPhutureOnConsumeCallback} from "./interfaces/IPhutureOnConsumeCallback.sol";
import {IPhutureOnDonationCallback} from "./interfaces/IPhutureOnDonationCallback.sol";
import {IVault} from "./interfaces/IVault.sol";
import {AnatomyValidationLib} from "./libraries/AnatomyValidationLib.sol";
import {BitSet} from "./libraries/BitSet.sol";
import {Currency, CurrencyLib} from "./libraries/CurrencyLib.sol";
import {CurrencyRegistryLib} from "./libraries/CurrencyRegistryLib.sol";
import {FixedPointMathLib} from "solmate/utils/FixedPointMathLib.sol";
import {Extsload} from "./Extsload.sol";
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
abstract contract Vault is IVault, UUPSUpgradeable, OwnableUpgradeable, ReentrancyGuardUpgradeable, Extsload {
using BitSet for uint256[];
using CurrencyLib for *;
using FixedPointMathLib for uint256;
using CurrencyRegistryLib for CurrencyRegistryLib.Registry;
uint8 internal constant VAULT_REBALANCING_FLAG = 0x01;
uint8 internal rebalancingFlags;
address internal rebalancer;
address internal configBuilder;
uint256 internal anatomySnapshot;
CurrencyRegistryLib.Registry internal registry;
// packed currency balances for snapshot
mapping(uint256 => Currency[]) internal currenciesOf;
mapping(uint256 => uint256[]) internal balancesOf;
mapping(uint256 => bytes32) internal currencyHashOf;
// bit set, stores if currency balance exists for snapshot
mapping(uint256 => uint256[]) internal currencySetOf;
mapping(Currency => uint256) internal unaccountedBalanceOf;
// k balance for snapshot
mapping(uint256 => mapping(address => uint256)) public kBalanceWads;
event SetConfigBuilder(address configBuilder);
event SetRebalancer(address rebalancer);
event SnapshotTransfer(uint256 snapshot, uint256 amount, address indexed from, address indexed to);
event StartRebalancing(uint256 snapshot, uint256 kBalance, CurrencyWithdrawal withdrawals);
event FinishRebalancing(uint256 snapshot, Currency[] currencies, uint256[] balances);
event Donate(Currency currency, uint256 amount);
event Consume(Currency currency, uint256 amount);
error Forbidden();
error HashMismatch();
error Rebalancing();
error InvalidWithdrawal();
modifier only(address addr) {
_checkSender(addr);
_;
}
receive() external payable {}
function setConfigBuilder(address _configBuilder) external onlyOwner {
configBuilder = _configBuilder;
emit SetConfigBuilder(_configBuilder);
}
function setRebalancer(address _rebalancer) external onlyOwner {
rebalancer = _rebalancer;
emit SetRebalancer(_rebalancer);
}
function startRebalancingPhase(CurrencyWithdrawal calldata withdrawals) external only(configBuilder) {
_startRebalancingPhase(withdrawals);
}
function finishRebalancingPhase(EndRebalancingParams calldata params)
external
only(configBuilder)
returns (RebalancingResult memory)
{
uint8 _rebalancingFlags = rebalancingFlags;
if (_rebalancingFlags == 0) revert Rebalancing();
uint256 snapshot = anatomySnapshot;
// check if anatomy and withdrawal hashes match the stored version
// hash allows us to recover anatomy and withdrawals from memory
if (currencyHashOf[snapshot] != keccak256(abi.encode(params.withdrawals, params.lastKBalance))) {
revert HashMismatch();
}
uint256 lastSnapshot;
unchecked {
// cannot overflow, snapshot > 0
lastSnapshot = snapshot - 1;
}
if (currencyHashOf[lastSnapshot] != keccak256(abi.encode(params.anatomyCurrencies, params.anatomyBalances))) {
revert HashMismatch();
}
AnatomyValidationLib.validate(
unaccountedBalanceOf, currencySetOf[lastSnapshot], registry.currenciesHash, params
);
currenciesOf[snapshot] = params.newAnatomy.currencies;
balancesOf[snapshot] = params.newAnatomy.balances;
currencySetOf[snapshot] = params.newAnatomy.currencyIndexSet;
currencyHashOf[snapshot] = keccak256(abi.encode(params.newAnatomy.currencies, params.newAnatomy.balances));
// issue the new sub index k shares
kBalanceWads[snapshot][address(this)] = FixedPointMathLib.WAD;
emit SnapshotTransfer(snapshot, FixedPointMathLib.WAD, address(0), address(this));
// end vault rebalancing phase
rebalancingFlags = _rebalancingFlags & ~VAULT_REBALANCING_FLAG;
emit FinishRebalancing(snapshot, params.newAnatomy.currencies, params.newAnatomy.balances);
return RebalancingResult(
snapshot, params.newAnatomy.currencyIndexSet, params.newAnatomy.currencies, params.newAnatomy.balances
);
}
function donate(Currency currency, bytes memory data) external nonReentrant only(rebalancer) {
uint256 balanceBefore = currency.balanceOfSelf();
IPhutureOnDonationCallback(msg.sender).phutureOnDonationCallbackV1(data);
uint256 delta = currency.balanceOfSelf() - balanceBefore;
unaccountedBalanceOf[currency] += delta;
emit Donate(currency, delta);
}
function consume(Currency currency, uint256 amount, address target, bytes calldata data)
external
only(rebalancer)
{
if (rebalancingFlags == 0) revert Rebalancing();
unaccountedBalanceOf[currency] -= amount;
currency.transfer(target, amount);
IPhutureOnConsumeCallback(target).phutureOnConsumeCallbackV1(data);
emit Consume(currency, amount);
}
function registerCurrencies(Currency[] calldata currencies) external onlyOwner returns (bytes32 currenciesHash) {
for (uint256 i; i < currencies.length; ++i) {
currenciesHash = registry.registerCurrency(currencies[i]);
}
}
function withdraw(uint256 snapshot, uint256 kAmount, address recipient) external {
_burnSnapshot(snapshot, msg.sender, kAmount);
Currency[] memory currencies = currenciesOf[snapshot];
uint256[] memory balances = balancesOf[snapshot];
uint256 length = currencies.length;
for (uint256 i; i < length; ++i) {
uint256 assets = kAmount.mulWadDown(balances[i]);
if (assets != 0) currencies[i].transfer(recipient, assets);
}
}
function __Vault_init(address _owner) internal onlyInitializing {
__UUPSUpgradeable_init();
__Ownable_init();
__ReentrancyGuard_init();
currencyHashOf[0] = keccak256(abi.encode(new Currency[](0), new uint256[](0)));
_transferOwnership(_owner);
}
function _startRebalancingPhase(CurrencyWithdrawal memory withdrawals) internal virtual {
if (rebalancingFlags & VAULT_REBALANCING_FLAG != 0) revert Rebalancing();
uint256 snapshot = anatomySnapshot;
Currency[] memory currencies = registry.currencies;
uint256[] memory currencySet = currencySetOf[snapshot];
uint256 withdrawalIndex;
for (uint256 i; i < currencies.length; ++i) {
if (withdrawals.currencyIndexSet.contains(i)) {
if (!currencySet.contains(i)) revert InvalidWithdrawal();
unaccountedBalanceOf[currencies[i]] += withdrawals.amounts[withdrawalIndex];
unchecked {
++withdrawalIndex;
}
}
}
// enter rebalancing phase
uint256 kBalance = kBalanceWads[snapshot][address(this)];
_burnSnapshot(snapshot, address(this), kBalance);
currencyHashOf[++snapshot] = keccak256(abi.encode(withdrawals, kBalance));
rebalancingFlags |= VAULT_REBALANCING_FLAG;
anatomySnapshot = snapshot;
emit StartRebalancing(snapshot, kBalance, withdrawals);
}
function _burnSnapshot(uint256 snapshot, address from, uint256 kAmountWads) internal {
if (kAmountWads == 0) return;
kBalanceWads[snapshot][from] -= kAmountWads;
emit SnapshotTransfer(snapshot, kAmountWads, from, address(0));
}
function _transferSnapshot(uint256 snapshot, uint256 kAmountWads, address from, address recipient) internal {
kBalanceWads[snapshot][from] -= kAmountWads;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
kBalanceWads[snapshot][recipient] += kAmountWads;
}
emit SnapshotTransfer(snapshot, kAmountWads, from, recipient);
}
function _checkSender(address addr) internal view {
if (msg.sender != addr) revert Forbidden();
}
/// @inheritdoc UUPSUpgradeable
function _authorizeUpgrade(address _newImpl) internal view override onlyOwner {}
}// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.23;
import {Currency} from "../libraries/CurrencyLib.sol";
interface IVault {
struct CurrencyWithdrawal {
uint256[] currencyIndexSet;
uint256[] amounts;
}
struct SnapshotAnatomy {
Currency[] currencies;
uint256[] balances;
uint256[] currencyIndexSet;
}
struct EndRebalancingParams {
Currency[] anatomyCurrencies;
uint256[] anatomyBalances;
SnapshotAnatomy newAnatomy;
CurrencyWithdrawal withdrawals;
uint256 lastKBalance;
Currency[] currencies;
}
struct RebalancingResult {
uint256 snapshot;
uint256[] currencyIdSet;
Currency[] currencies;
uint256[] balances;
}
function setRebalancer(address rebalancer) external;
function setConfigBuilder(address configBuilder) external;
function startRebalancingPhase(CurrencyWithdrawal calldata withdrawals) external;
function finishRebalancingPhase(EndRebalancingParams calldata params) external returns (RebalancingResult memory);
function withdraw(uint256 snapshot, uint256 kAmount, address recipient) external;
function registerCurrencies(Currency[] calldata currencies) external returns (bytes32 currenciesHash);
function donate(Currency currency, bytes memory data) external;
function consume(Currency currency, uint256 amount, address target, bytes calldata data) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.23;
import {IFeeQuoter} from "./IFeeQuoter.sol";
interface IIndexMetadata is IFeeQuoter {}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.23;
interface IStaticPriceOracle {
error SequencerDown();
error GracePeriodNotOver();
function valuation(bytes calldata) external returns (uint256 _reservePrice, uint256 _valuation);
function pricesAndBalances(bytes calldata)
external
returns (uint256[] memory _prices, uint256[] memory _balances);
function checkSequencer() external view;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.23;
import {FixedPointMathLib} from "solmate/utils/FixedPointMathLib.sol";
/// @title PriceLib
/// @notice A library for handling fixed-point arithmetic for prices
library PriceLib {
using FixedPointMathLib for uint256;
/// @dev 2**128
uint256 internal constant Q128 = 0x100000000000000000000000000000000;
uint16 internal constant PRICE_ORACLE_DECIMALS = 18;
uint256 internal constant DECIMALS_MULTIPLIER = 10 ** PRICE_ORACLE_DECIMALS;
/// @notice Converts (down) an amount in base units to an amount in asset units based on a fixed-price value
/// @param base The amount to convert in base units
/// @param price The fixed-price value represented as a uint256
/// @return The equivalent amount in asset units
function convertToAssetsDown(uint256 base, uint256 price) internal pure returns (uint256) {
return base.mulDivDown(price, Q128);
}
/// @notice Converts (up) an amount in base units to an amount in asset units based on a fixed-price value
/// @param base The amount to convert in base units
/// @param price The fixed-price value represented as a uint256
/// @return The equivalent amount in asset units
function convertToAssetsUp(uint256 base, uint256 price) internal pure returns (uint256) {
return base.mulDivUp(price, Q128);
}
/// @notice Converts (down) an amount in asset units to an amount in base units based on a fixed-price value
/// @param assets The amount to convert in asset units
/// @param price The fixed-price value represented as a uint256
/// @return The equivalent amount in base units
function convertToBaseDown(uint256 assets, uint256 price) internal pure returns (uint256) {
return assets.mulDivDown(Q128, price);
}
/// @notice Converts (up) an amount in asset units to an amount in base units based on a fixed-price value
/// @param assets The amount to convert in asset units
/// @param price The fixed-price value represented as a uint256
/// @return The equivalent amount in base units
function convertToBaseUp(uint256 assets, uint256 price) internal pure returns (uint256) {
return assets.mulDivUp(Q128, price);
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.23;
import {FixedPointMathLib} from "solmate/utils/FixedPointMathLib.sol";
import {SafeCastLib} from "solmate/utils/SafeCastLib.sol";
/// @title IndexConversionLib
/// @notice A library for converting assets and shares
library IndexConversionLib {
using SafeCastLib for uint256;
using FixedPointMathLib for *;
/// @dev The initial price is set to 100 USD, which is represented by the PRICE_SCALING_FACTOR constant.
/// The scaling factor is determined by the following calculation:
/// 10^(indexDecimals - initialPriceScalingFactor) / 10^(PRICE_ORACLE_DECIMALS)
/// = 10^(16) / 10^(18)
/// = 1e-2
///
/// This scaling factor is used to convert the asset amount to shares when the initial supply is zero.
/// It ensures that the initial price of the index is properly scaled based on the desired initial value (100 USD).
uint128 private constant PRICE_SCALING_FACTOR = 1e2;
/// @notice Converts asset amount to shares based on the supply and valuation
///
/// @param assets The amount of assets (in base) to be converted
/// @param supply The total supply of shares
/// @param valuation The total valuation of assets
///
/// @return The number of shares corresponding to the given asset amount
function convertToShares(uint256 assets, uint128 supply, uint256 valuation) internal pure returns (uint128) {
return (supply == 0 ? assets / PRICE_SCALING_FACTOR : assets.mulDivDown(supply, valuation)).safeCastTo128();
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.23;
interface IPhutureOnConsumeCallback {
function phutureOnConsumeCallbackV1(bytes calldata data) external;
}// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.23;
interface IPhutureOnDonationCallback {
function phutureOnDonationCallbackV1(bytes calldata data) external;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.23;
import {IVault} from "../interfaces/IVault.sol";
import {BitSet} from "./BitSet.sol";
import {Currency, CurrencyLib} from "./CurrencyLib.sol";
import {FixedPointMathLib} from "solmate/utils/FixedPointMathLib.sol";
/// @title AnatomyValidationLib
/// @notice A library for validating the anatomy of a vault
library AnatomyValidationLib {
using CurrencyLib for *;
using FixedPointMathLib for uint256;
using BitSet for uint256[];
/// @dev Struct to hold the indexes of anatomy, new anatomy and withdrawal
struct Indexes {
uint256 anatomy;
uint256 newAnatomy;
uint256 withdrawal;
}
/// @notice Thrown when the currencies hash doesn't match the expected value
error CurrenciesHashMismatch();
/// @notice Thrown when the new anatomy contains an excess currency index
/// @param currencyIndex The excess currency index
error ExcessNewAnatomyCurrencyIndex(uint256 currencyIndex);
/// @notice Thrown when a currency index is not found in the new anatomy
/// @param currencyIndex The missing currency index
error NewAnatomyCurrencyIndexNotFound(uint256 currencyIndex);
/// @notice Thrown when the new anatomy currency count doesn't match the expected value
/// @param expectedCount The expected count of new anatomy currencies
error NewAnatomyCurrencyCountMismatch(uint256 expectedCount);
/// @notice Thrown when the new anatomy currency index set size doesn't match the expected value
/// @param expectedCount The expected size of the new anatomy currency index set
error NewAnatomyCurrencyIndexSetSizeMismatch(uint256 expectedCount);
/// @notice Thrown when a new anatomy currency doesn't match the expected value
/// @param expectedCurrency The expected currency value
/// @param expectedBalance The expected balance value
error NewAnatomyCurrencyMismatch(Currency expectedCurrency, uint256 expectedBalance);
/// @notice Validates the anatomy of a vault
///
/// @param unaccountedBalanceOf The mapping of unaccounted currency balances
/// @param anatomyCurrencyIndexSet The index set of anatomy currencies
/// @param currenciesHash The expected hash of currencies
/// @param params The end rebalancing parameters
function validate(
mapping(Currency => uint256) storage unaccountedBalanceOf,
uint256[] memory anatomyCurrencyIndexSet,
bytes32 currenciesHash,
IVault.EndRebalancingParams calldata params
) internal {
Indexes memory indexes;
bytes32 _currenciesHash;
for (uint256 i; i < params.currencies.length; ++i) {
Currency currency = params.currencies[i];
_currenciesHash = keccak256(abi.encode(_currenciesHash, currency));
uint256 balance = unaccountedBalanceOf[currency];
if (balance != 0) delete unaccountedBalanceOf[currency];
// If the currency is in the anatomy index set
if (anatomyCurrencyIndexSet.contains(i)) {
// Add new anatomy balance to the balance
balance += params.lastKBalance.mulWadDown(params.anatomyBalances[indexes.anatomy]);
// If the currency is in the withdrawals index set
if (params.withdrawals.currencyIndexSet.contains(i)) {
// Subtract the withdrawal amount from the balance
balance -= params.withdrawals.amounts[indexes.withdrawal];
unchecked {
++indexes.withdrawal;
}
}
unchecked {
++indexes.anatomy;
}
}
if (balance == 0) {
// new anatomy shouldn't contain any currencies without balances
if (params.newAnatomy.currencyIndexSet.contains(i)) revert ExcessNewAnatomyCurrencyIndex(i);
} else {
// new anatomy must contain all non-zero currency balances
if (!params.newAnatomy.currencyIndexSet.contains(i)) revert NewAnatomyCurrencyIndexNotFound(i);
if (
params.newAnatomy.currencies[indexes.newAnatomy] != currency
|| params.newAnatomy.balances[indexes.newAnatomy] != balance
) {
// new anatomy currency must match the expected packed currency
revert NewAnatomyCurrencyMismatch(currency, balance);
}
unchecked {
// cannot overflow, new anatomy index < (old anatomy + updates)
++indexes.newAnatomy;
}
}
}
// currencies hash must match the expected value
// this is checked to verify that the currencies list
// is in correct order, contains no duplicates and is complete
if (_currenciesHash != currenciesHash) revert CurrenciesHashMismatch();
// accumulated newAnatomy index must match the length of new anatomy currencies
if (indexes.newAnatomy != params.newAnatomy.currencies.length) {
revert NewAnatomyCurrencyCountMismatch(indexes.newAnatomy);
}
// new anatomy currency index set size must match the length of new anatomy currencies
if (indexes.newAnatomy != params.newAnatomy.currencyIndexSet.size()) {
revert NewAnatomyCurrencyIndexSetSizeMismatch(indexes.newAnatomy);
}
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.23;
/// @title BitSet
/// @notice A library for managing bitsets
library BitSet {
uint256 private constant WORD_SHIFT = 8;
/// @notice Checks if the next bit is set in the given word starting from the given bit position
///
/// @param word The word to check
/// @param bit The bit position
///
/// @return r True if the next bit is set, false otherwise
function hasNext(uint256 word, uint256 bit) internal pure returns (bool r) {
assembly ("memory-safe") {
r := and(shr(bit, word), 1)
}
}
/// @notice Finds the position of the next set bit in the given word starting from the given bit position
///
/// @dev This function uses a lookup table approach to find the position of the next set bit.
/// It first shifts the word right by the given bit position and then checks the lower 3 bits
/// of the resulting word to determine the position of the next set bit.
/// If no set bit is found, it returns 256 to indicate that there are no more set bits.
///
/// @param word The word to search
/// @param b The starting bit position
///
/// @return nb The position of the next set bit
function find(uint256 word, uint256 b) internal pure returns (uint256 nb) {
assembly ("memory-safe") {
let w := shr(b, word)
switch w
case 0 {
// no more bits
nb := 256
}
default {
// 0b000 = 0
// 0b001 = 1
// 0b010 = 2
// 0b011 = 3
// 0b100 = 4
// 0b101 = 5
// 0b110 = 6
// 0b111 = 7
switch and(w, 7)
case 0 { nb := add(lsb(w), b) }
case 2 { nb := add(b, 1) }
case 4 { nb := add(b, 2) }
case 6 { nb := add(b, 1) }
default { nb := b }
}
function lsb(x) -> r {
if iszero(x) { revert(0, 0) }
r := 255
switch gt(and(x, 0xffffffffffffffffffffffffffffffff), 0)
case 1 { r := sub(r, 128) }
case 0 { x := shr(128, x) }
switch gt(and(x, 0xffffffffffffffff), 0)
case 1 { r := sub(r, 64) }
case 0 { x := shr(64, x) }
switch gt(and(x, 0xffffffff), 0)
case 1 { r := sub(r, 32) }
case 0 { x := shr(32, x) }
switch gt(and(x, 0xffff), 0)
case 1 { r := sub(r, 16) }
case 0 { x := shr(16, x) }
switch gt(and(x, 0xff), 0)
case 1 { r := sub(r, 8) }
case 0 { x := shr(8, x) }
switch gt(and(x, 0xf), 0)
case 1 { r := sub(r, 4) }
case 0 { x := shr(4, x) }
switch gt(and(x, 0x3), 0)
case 1 { r := sub(r, 2) }
case 0 { x := shr(2, x) }
switch gt(and(x, 0x1), 0)
case 1 { r := sub(r, 1) }
}
}
}
/// @notice Computes the value at the given word index and bit position
///
/// @param wordIndex The index of the word
/// @param bit The bit position within the word
///
/// @return r The computed value
function valueAt(uint256 wordIndex, uint256 bit) internal pure returns (uint256 r) {
assembly ("memory-safe") {
r := or(shl(8, wordIndex), bit)
}
}
/// @notice Creates a new bitset with the given maximum size
///
/// @param maxSize The maximum size of the bitset
///
/// @return bitset The created bitset
function create(uint256 maxSize) internal pure returns (uint256[] memory bitset) {
bitset = new uint256[](_capacity(maxSize));
}
/// @notice Checks if the given value is contained in the bitset
///
/// @param bitset The bitset to check
/// @param value The value to search for
///
/// @return _contains True if the value is contained in the bitset, false otherwise
function contains(uint256[] memory bitset, uint256 value) internal pure returns (bool _contains) {
(uint256 wordIndex, uint8 bit) = _bitOffset(value);
if (wordIndex < bitset.length) {
_contains = (bitset[wordIndex] & (1 << bit)) != 0;
}
}
/// @notice Checks if the given value is contained in the bitset
///
/// @param bitset The bitset to check
/// @param value The value to search for
///
/// @return _contains True if the value is contained in the bitset, false otherwise
function contains(uint256 bitset, uint256 value) internal pure returns (bool _contains) {
(uint256 wordIndex, uint8 bit) = _bitOffset(value);
if (wordIndex == 0) {
_contains = (bitset & (1 << bit)) != 0;
}
}
/// @notice Adds the given value to the bitset
///
/// @param bitset The bitset to modify
/// @param value The value to add
///
/// @return The modified bitset
function add(uint256[] memory bitset, uint256 value) internal pure returns (uint256[] memory) {
(uint256 wordIndex, uint8 bit) = _bitOffset(value);
bitset[wordIndex] |= (1 << bit);
return bitset;
}
/// @notice Adds all elements from bitset b to bitset a
///
/// @param a The destination bitset
/// @param b The source bitset
///
/// @return c The resulting bitset
function addAll(uint256[] memory a, uint256[] memory b) internal pure returns (uint256[] memory c) {
(uint256 min, uint256 max) = a.length < b.length ? (a.length, b.length) : (b.length, a.length);
c = new uint256[](max);
uint256 i;
for (; i < min; ++i) {
c[i] = a[i] | b[i];
}
// copy leftover elements from a
for (; i < a.length; ++i) {
c[i] = a[i];
}
// copy leftover elements from b
for (; i < b.length; ++i) {
c[i] = b[i];
}
}
/// @notice Removes the given value from the bitset
///
/// @param bitset The bitset to modify
/// @param value The value to remove
///
/// @return The modified bitset
function remove(uint256[] memory bitset, uint256 value) internal pure returns (uint256[] memory) {
(uint256 wordIndex, uint8 bit) = _bitOffset(value);
bitset[wordIndex] &= ~(1 << bit);
return bitset;
}
/// @notice Computes the size (number of set bits) of the bitset
///
/// @param bitset The bitset to compute the size of
///
/// @return count The number of set bits in the bitset
function size(uint256[] memory bitset) internal pure returns (uint256 count) {
for (uint256 i; i < bitset.length; ++i) {
count += _countSetBits(bitset[i]);
}
}
/// @notice Computes the size (number of set bits) of the bitset
///
/// @param bitset The bitset to compute the size of
///
/// @return count The number of set bits in the bitset
function size(uint256 bitset) internal pure returns (uint256) {
return _countSetBits(bitset);
}
/// @dev Computes the word index and bit position for the given value
///
/// @param value The value to compute the offsets for
///
/// @return wordIndex The index of the word containing the value
/// @return bit The bit position within the word
function _bitOffset(uint256 value) private pure returns (uint256 wordIndex, uint8 bit) {
assembly ("memory-safe") {
wordIndex := shr(8, value)
// mask bits that don't fit the first wordIndex's bits
// n % 2^i = n & (2^i - 1)
bit := and(value, 255)
}
}
/// @dev Computes the number of words required to store the given maximum size
///
/// @param maxSize The maximum size of the bitset
///
/// @return words The number of words required
function _capacity(uint256 maxSize) private pure returns (uint256 words) {
// round up
words = (maxSize + type(uint8).max) >> WORD_SHIFT;
}
/// @dev Counts the number of set bits in the given word using Brian Kernighan's algorithm
///
/// @param x The word to count the set bits of
///
/// @return count The number of set bits in the word
function _countSetBits(uint256 x) private pure returns (uint256 count) {
// Brian Kernighan's Algorithm
// This algorithm counts the number of set bits in a word by repeatedly
// clearing the least significant set bit until the word becomes zero.
while (x != 0) {
unchecked {
// cannot overflow, x > 0
x = x & (x - 1);
++count;
}
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;
/// @title Extsload
/// @author Modified from RageTrade (https://github.com/RageTrade/core/blob/main/contracts/utils/Extsload.sol)
abstract contract Extsload {
/// @notice Externally loads the value stored at the specified slot
///
/// @param slot The slot to load the value from
///
/// @return value The value stored at the specified slot
function extsload(bytes32 slot) external view returns (bytes32 value) {
assembly ("memory-safe") {
value := sload(slot)
}
}
/// @notice Externally loads the values stored at the specified slots
///
/// @param slots An array of slots to load the values from
///
/// @return An array of values stored at the specified slots
function extsload(bytes32[] memory slots) external view returns (bytes32[] memory) {
assembly ("memory-safe") {
let end := add(32, add(slots, mul(mload(slots), 32)))
for { let ptr := add(slots, 32) } lt(ptr, end) { ptr := add(ptr, 32) } { mstore(ptr, sload(mload(ptr))) }
}
return slots;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
function __Ownable_init() internal onlyInitializing {
__Ownable_init_unchained();
}
function __Ownable_init_unchained() internal onlyInitializing {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (proxy/utils/UUPSUpgradeable.sol)
pragma solidity ^0.8.0;
import "../../interfaces/draft-IERC1822Upgradeable.sol";
import "../ERC1967/ERC1967UpgradeUpgradeable.sol";
import "./Initializable.sol";
/**
* @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
* {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
*
* A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
* reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
* `UUPSUpgradeable` with a custom implementation of upgrades.
*
* The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
*
* _Available since v4.1._
*/
abstract contract UUPSUpgradeable is Initializable, IERC1822ProxiableUpgradeable, ERC1967UpgradeUpgradeable {
function __UUPSUpgradeable_init() internal onlyInitializing {
}
function __UUPSUpgradeable_init_unchained() internal onlyInitializing {
}
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment
address private immutable __self = address(this);
/**
* @dev Check that the execution is being performed through a delegatecall call and that the execution context is
* a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case
* for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
* function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
* fail.
*/
modifier onlyProxy() {
require(address(this) != __self, "Function must be called through delegatecall");
require(_getImplementation() == __self, "Function must be called through active proxy");
_;
}
/**
* @dev Check that the execution is not being performed through a delegate call. This allows a function to be
* callable on the implementing contract but not through proxies.
*/
modifier notDelegated() {
require(address(this) == __self, "UUPSUpgradeable: must not be called through delegatecall");
_;
}
/**
* @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the
* implementation. It is used to validate the implementation's compatibility when performing an upgrade.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
*/
function proxiableUUID() external view virtual override notDelegated returns (bytes32) {
return _IMPLEMENTATION_SLOT;
}
/**
* @dev Upgrade the implementation of the proxy to `newImplementation`.
*
* Calls {_authorizeUpgrade}.
*
* Emits an {Upgraded} event.
*/
function upgradeTo(address newImplementation) external virtual onlyProxy {
_authorizeUpgrade(newImplementation);
_upgradeToAndCallUUPS(newImplementation, new bytes(0), false);
}
/**
* @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
* encoded in `data`.
*
* Calls {_authorizeUpgrade}.
*
* Emits an {Upgraded} event.
*/
function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual onlyProxy {
_authorizeUpgrade(newImplementation);
_upgradeToAndCallUUPS(newImplementation, data, true);
}
/**
* @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
* {upgradeTo} and {upgradeToAndCall}.
*
* Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
*
* ```solidity
* function _authorizeUpgrade(address) internal override onlyOwner {}
* ```
*/
function _authorizeUpgrade(address newImplementation) internal virtual;
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuardUpgradeable is Initializable {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
function __ReentrancyGuard_init() internal onlyInitializing {
__ReentrancyGuard_init_unchained();
}
function __ReentrancyGuard_init_unchained() internal onlyInitializing {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be _NOT_ENTERED
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.23;
import {IIndex} from "./IIndex.sol";
interface IFeeQuoter {
function depositFeeInBPs(
IIndex.Config calldata config,
IIndex.IndexState calldata state,
uint128 depositedShares,
address sender
) external view returns (uint16 feeInBPs);
function redemptionFeeInBPs(
IIndex.Config calldata config,
IIndex.IndexState calldata state,
uint128 redeemedShares,
address sender
) external view returns (uint16 feeInBPs);
function AUMDilutionPerSecond(IIndex.Config calldata config, IIndex.IndexState calldata state)
external
view
returns (uint256 dilutionPerSecond);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.1) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "../../utils/AddressUpgradeable.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
* constructor.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initialized = 1;
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: setting the version to 255 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint8 version) {
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_initialized = version;
_initializing = true;
_;
_initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. 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 executed.
*/
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized < type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint8) {
return _initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _initializing;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)
pragma solidity ^0.8.0;
/**
* @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
* proxy whose upgrades are fully controlled by the current implementation.
*/
interface IERC1822ProxiableUpgradeable {
/**
* @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
* address.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy.
*/
function proxiableUUID() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol)
pragma solidity ^0.8.2;
import "../beacon/IBeaconUpgradeable.sol";
import "../../interfaces/draft-IERC1822Upgradeable.sol";
import "../../utils/AddressUpgradeable.sol";
import "../../utils/StorageSlotUpgradeable.sol";
import "../utils/Initializable.sol";
/**
* @dev This abstract contract provides getters and event emitting update functions for
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
*
* _Available since v4.1._
*
* @custom:oz-upgrades-unsafe-allow delegatecall
*/
abstract contract ERC1967UpgradeUpgradeable is Initializable {
function __ERC1967Upgrade_init() internal onlyInitializing {
}
function __ERC1967Upgrade_init_unchained() internal onlyInitializing {
}
// This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
/**
* @dev Storage slot with the address of the current implementation.
* This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/**
* @dev Emitted when the implementation is upgraded.
*/
event Upgraded(address indexed implementation);
/**
* @dev Returns the current implementation address.
*/
function _getImplementation() internal view returns (address) {
return StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 implementation slot.
*/
function _setImplementation(address newImplementation) private {
require(AddressUpgradeable.isContract(newImplementation), "ERC1967: new implementation is not a contract");
StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
}
/**
* @dev Perform implementation upgrade
*
* Emits an {Upgraded} event.
*/
function _upgradeTo(address newImplementation) internal {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
}
/**
* @dev Perform implementation upgrade with additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCall(
address newImplementation,
bytes memory data,
bool forceCall
) internal {
_upgradeTo(newImplementation);
if (data.length > 0 || forceCall) {
_functionDelegateCall(newImplementation, data);
}
}
/**
* @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCallUUPS(
address newImplementation,
bytes memory data,
bool forceCall
) internal {
// Upgrades from old implementations will perform a rollback test. This test requires the new
// implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
// this special case will break upgrade paths from old UUPS implementation to new ones.
if (StorageSlotUpgradeable.getBooleanSlot(_ROLLBACK_SLOT).value) {
_setImplementation(newImplementation);
} else {
try IERC1822ProxiableUpgradeable(newImplementation).proxiableUUID() returns (bytes32 slot) {
require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID");
} catch {
revert("ERC1967Upgrade: new implementation is not UUPS");
}
_upgradeToAndCall(newImplementation, data, forceCall);
}
}
/**
* @dev Storage slot with the admin of the contract.
* This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
/**
* @dev Emitted when the admin account has changed.
*/
event AdminChanged(address previousAdmin, address newAdmin);
/**
* @dev Returns the current admin.
*/
function _getAdmin() internal view returns (address) {
return StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 admin slot.
*/
function _setAdmin(address newAdmin) private {
require(newAdmin != address(0), "ERC1967: new admin is the zero address");
StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
}
/**
* @dev Changes the admin of the proxy.
*
* Emits an {AdminChanged} event.
*/
function _changeAdmin(address newAdmin) internal {
emit AdminChanged(_getAdmin(), newAdmin);
_setAdmin(newAdmin);
}
/**
* @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
* This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
*/
bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
/**
* @dev Emitted when the beacon is upgraded.
*/
event BeaconUpgraded(address indexed beacon);
/**
* @dev Returns the current beacon.
*/
function _getBeacon() internal view returns (address) {
return StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value;
}
/**
* @dev Stores a new beacon in the EIP1967 beacon slot.
*/
function _setBeacon(address newBeacon) private {
require(AddressUpgradeable.isContract(newBeacon), "ERC1967: new beacon is not a contract");
require(
AddressUpgradeable.isContract(IBeaconUpgradeable(newBeacon).implementation()),
"ERC1967: beacon implementation is not a contract"
);
StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value = newBeacon;
}
/**
* @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
* not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
*
* Emits a {BeaconUpgraded} event.
*/
function _upgradeBeaconToAndCall(
address newBeacon,
bytes memory data,
bool forceCall
) internal {
_setBeacon(newBeacon);
emit BeaconUpgraded(newBeacon);
if (data.length > 0 || forceCall) {
_functionDelegateCall(IBeaconUpgradeable(newBeacon).implementation(), data);
}
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function _functionDelegateCall(address target, bytes memory data) private returns (bytes memory) {
require(AddressUpgradeable.isContract(target), "Address: delegate call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = target.delegatecall(data);
return AddressUpgradeable.verifyCallResult(success, returndata, "Address: low-level delegate call failed");
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library AddressUpgradeable {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)
pragma solidity ^0.8.0;
/**
* @dev This is the interface that {BeaconProxy} expects of its beacon.
*/
interface IBeaconUpgradeable {
/**
* @dev Must return an address that can be used as a delegate call target.
*
* {BeaconProxy} will check that this address is a contract.
*/
function implementation() external view returns (address);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/StorageSlot.sol)
pragma solidity ^0.8.0;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*
* _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
*/
library StorageSlotUpgradeable {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
}{
"remappings": [
"@openzeppelin/contracts-upgradeable/=node_modules/@openzeppelin/contracts-upgradeable/",
"@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/",
"@pythnetwork/pyth-sdk-solidity/=node_modules/@pythnetwork/pyth-sdk-solidity/",
"@uniswap/v2-core/=node_modules/@uniswap/v2-core/",
"@uniswap/v3-core/=node_modules/@uniswap/v3-core/",
"chainlink/=node_modules/@chainlink/contracts/",
"forge-std/=node_modules/forge-std/src/",
"phuture-oracles/=lib/phuture-price-oracles/contracts/",
"redstone/=node_modules/@redstone-finance/evm-connector/contracts/",
"solady/=node_modules/solady/src/",
"solmate/=node_modules/solmate/src/",
"src/=src/",
"@axelar-network/=node_modules/@axelar-network/",
"@chainlink/=node_modules/@chainlink/",
"@eth-optimism/=node_modules/@eth-optimism/",
"@layerzerolabs/=node_modules/@layerzerolabs/",
"@redstone-finance/=node_modules/@redstone-finance/",
"ds-test/=node_modules/ds-test/",
"hardhat-deploy/=node_modules/hardhat-deploy/",
"phuture-price-oracles/=lib/phuture-price-oracles/contracts/",
"solidity-bytes-utils/=node_modules/solidity-bytes-utils/"
],
"optimizer": {
"enabled": true,
"runs": 1000
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "none",
"appendCBOR": false
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "shanghai",
"viaIR": true,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"uint16","name":"_maxDepositFeeInBPs","type":"uint16"},{"internalType":"uint16","name":"_maxRedemptionFeeInBPs","type":"uint16"},{"internalType":"uint256","name":"_maxAUMDilutionPerSecond","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CurrenciesHashMismatch","type":"error"},{"inputs":[],"name":"ERC20TransferFailed","type":"error"},{"inputs":[{"internalType":"uint256","name":"currencyIndex","type":"uint256"}],"name":"ExcessNewAnatomyCurrencyIndex","type":"error"},{"inputs":[],"name":"FeeExceedsMaxFee","type":"error"},{"inputs":[],"name":"Forbidden","type":"error"},{"inputs":[],"name":"HashMismatch","type":"error"},{"inputs":[],"name":"IndexConfigHash","type":"error"},{"inputs":[],"name":"IndexConfigMismatch","type":"error"},{"inputs":[],"name":"IndexInitialConfig","type":"error"},{"inputs":[],"name":"InvalidSender","type":"error"},{"inputs":[],"name":"InvalidSigner","type":"error"},{"inputs":[],"name":"InvalidWithdrawal","type":"error"},{"inputs":[],"name":"NativeTransferFailed","type":"error"},{"inputs":[{"internalType":"uint256","name":"expectedCount","type":"uint256"}],"name":"NewAnatomyCurrencyCountMismatch","type":"error"},{"inputs":[{"internalType":"uint256","name":"currencyIndex","type":"uint256"}],"name":"NewAnatomyCurrencyIndexNotFound","type":"error"},{"inputs":[{"internalType":"uint256","name":"expectedCount","type":"uint256"}],"name":"NewAnatomyCurrencyIndexSetSizeMismatch","type":"error"},{"inputs":[{"internalType":"Currency","name":"expectedCurrency","type":"address"},{"internalType":"uint256","name":"expectedBalance","type":"uint256"}],"name":"NewAnatomyCurrencyMismatch","type":"error"},{"inputs":[],"name":"PermitDeadlineExpired","type":"error"},{"inputs":[],"name":"Rebalancing","type":"error"},{"inputs":[{"internalType":"Currency","name":"currency","type":"address"}],"name":"Registered","type":"error"},{"inputs":[],"name":"ZeroAddressTransfer","type":"error"},{"inputs":[],"name":"ZeroDeposit","type":"error"},{"inputs":[],"name":"ZeroShares","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previousAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"beacon","type":"address"}],"name":"BeaconUpgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"encodedConfig","type":"bytes"}],"name":"ConfigUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"Currency","name":"currency","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Consume","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"reserve","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"Currency","name":"currency","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Donate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint96","name":"depositFee","type":"uint96"},{"indexed":false,"internalType":"uint96","name":"redemptionFee","type":"uint96"},{"indexed":false,"internalType":"uint96","name":"AUMFee","type":"uint96"}],"name":"FeeAccrued","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint96","name":"fee","type":"uint96"}],"name":"FeeSettled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"snapshot","type":"uint256"},{"indexed":false,"internalType":"Currency[]","name":"currencies","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"balances","type":"uint256[]"}],"name":"FinishRebalancing","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"configBuilder","type":"address"}],"name":"SetConfigBuilder","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"rebalancer","type":"address"}],"name":"SetRebalancer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"snapshot","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"SnapshotTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"snapshot","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"kBalance","type":"uint256"},{"components":[{"internalType":"uint256[]","name":"currencyIndexSet","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"indexed":false,"internalType":"struct IVault.CurrencyWithdrawal","name":"withdrawals","type":"tuple"}],"name":"StartRebalancing","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":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"k","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"reserve","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"}],"name":"accrueFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","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":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"Currency","name":"currency","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"consume","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"components":[{"components":[{"internalType":"uint256","name":"latestSnapshot","type":"uint256"},{"internalType":"uint256","name":"AUMDilutionPerSecond","type":"uint256"},{"internalType":"bool","name":"useCustomAUMFee","type":"bool"},{"internalType":"address","name":"staticPriceOracle","type":"address"},{"internalType":"address","name":"metadata","type":"address"},{"internalType":"address","name":"forwarder","type":"address"}],"internalType":"struct IIndex.Config","name":"shared","type":"tuple"},{"components":[{"internalType":"uint16","name":"BPs","type":"uint16"},{"internalType":"bool","name":"useCustomCallback","type":"bool"}],"internalType":"struct IIndex.FeeConfig","name":"fee","type":"tuple"}],"internalType":"struct IIndex.DepositConfig","name":"config","type":"tuple"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"bytes","name":"payload","type":"bytes"}],"internalType":"struct IIndex.DepositParams","name":"params","type":"tuple"},{"internalType":"address","name":"cbTarget","type":"address"},{"internalType":"bytes","name":"cbData","type":"bytes"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"Currency","name":"currency","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"donate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"slot","type":"bytes32"}],"name":"extsload","outputs":[{"internalType":"bytes32","name":"value","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"slots","type":"bytes32[]"}],"name":"extsload","outputs":[{"internalType":"bytes32[]","name":"","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"Currency[]","name":"anatomyCurrencies","type":"address[]"},{"internalType":"uint256[]","name":"anatomyBalances","type":"uint256[]"},{"components":[{"internalType":"Currency[]","name":"currencies","type":"address[]"},{"internalType":"uint256[]","name":"balances","type":"uint256[]"},{"internalType":"uint256[]","name":"currencyIndexSet","type":"uint256[]"}],"internalType":"struct IVault.SnapshotAnatomy","name":"newAnatomy","type":"tuple"},{"components":[{"internalType":"uint256[]","name":"currencyIndexSet","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"internalType":"struct IVault.CurrencyWithdrawal","name":"withdrawals","type":"tuple"},{"internalType":"uint256","name":"lastKBalance","type":"uint256"},{"internalType":"Currency[]","name":"currencies","type":"address[]"}],"internalType":"struct IVault.EndRebalancingParams","name":"params","type":"tuple"}],"name":"finishRebalancingPhase","outputs":[{"components":[{"internalType":"uint256","name":"snapshot","type":"uint256"},{"internalType":"uint256[]","name":"currencyIdSet","type":"uint256[]"},{"internalType":"Currency[]","name":"currencies","type":"address[]"},{"internalType":"uint256[]","name":"balances","type":"uint256[]"}],"internalType":"struct IVault.RebalancingResult","name":"","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"Currency","name":"_reserve","type":"address"},{"internalType":"address","name":"_governance","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"kBalanceWads","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"kSelf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"Currency[]","name":"currencies","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint128","name":"shares","type":"uint128"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","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":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"components":[{"components":[{"internalType":"uint256","name":"latestSnapshot","type":"uint256"},{"internalType":"uint256","name":"AUMDilutionPerSecond","type":"uint256"},{"internalType":"bool","name":"useCustomAUMFee","type":"bool"},{"internalType":"address","name":"staticPriceOracle","type":"address"},{"internalType":"address","name":"metadata","type":"address"},{"internalType":"address","name":"forwarder","type":"address"}],"internalType":"struct IIndex.Config","name":"shared","type":"tuple"},{"components":[{"internalType":"uint16","name":"BPs","type":"uint16"},{"internalType":"bool","name":"useCustomCallback","type":"bool"}],"internalType":"struct IIndex.FeeConfig","name":"fee","type":"tuple"},{"internalType":"Currency[]","name":"currencies","type":"address[]"},{"internalType":"uint256[]","name":"balances","type":"uint256[]"}],"internalType":"struct IIndex.RedemptionConfig","name":"config","type":"tuple"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint128","name":"shares","type":"uint128"},{"internalType":"bytes","name":"payload","type":"bytes"}],"internalType":"struct IIndex.RedemptionParams","name":"params","type":"tuple"},{"internalType":"address","name":"forwardedSender","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"redeem","outputs":[{"components":[{"internalType":"uint256","name":"reserveValuation","type":"uint256"},{"internalType":"uint256","name":"totalValuation","type":"uint256"},{"internalType":"uint256","name":"totalReserveShares","type":"uint256"},{"internalType":"uint128","name":"totalSupplyAfterAUMAccrual","type":"uint128"},{"internalType":"uint256","name":"totalKBeforeRedeem","type":"uint256"},{"internalType":"uint256","name":"accountBalanceSharesBeforeRedeem","type":"uint256"},{"internalType":"uint96","name":"accountReserveRedeemed","type":"uint96"},{"internalType":"uint256","name":"accountReserveSharesRedeemed","type":"uint256"},{"internalType":"uint256","name":"accountKRedeemed","type":"uint256"},{"internalType":"uint256","name":"reservePriceInQ128","type":"uint256"}],"internalType":"struct IIndex.RedemptionInfo","name":"result","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"Currency[]","name":"currencies","type":"address[]"}],"name":"registerCurrencies","outputs":[{"internalType":"bytes32","name":"currenciesHash","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"reserve","outputs":[{"internalType":"Currency","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"reserveBalance","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"latestSnapshot","type":"uint256"},{"internalType":"uint256","name":"AUMDilutionPerSecond","type":"uint256"},{"internalType":"bool","name":"useCustomAUMFee","type":"bool"},{"internalType":"address","name":"staticPriceOracle","type":"address"},{"internalType":"address","name":"metadata","type":"address"},{"internalType":"address","name":"forwarder","type":"address"}],"internalType":"struct IIndex.Config","name":"_prevConfig","type":"tuple"},{"components":[{"components":[{"internalType":"uint256","name":"latestSnapshot","type":"uint256"},{"internalType":"uint256","name":"AUMDilutionPerSecond","type":"uint256"},{"internalType":"bool","name":"useCustomAUMFee","type":"bool"},{"internalType":"address","name":"staticPriceOracle","type":"address"},{"internalType":"address","name":"metadata","type":"address"},{"internalType":"address","name":"forwarder","type":"address"}],"internalType":"struct IIndex.Config","name":"shared","type":"tuple"},{"components":[{"internalType":"uint16","name":"BPs","type":"uint16"},{"internalType":"bool","name":"useCustomCallback","type":"bool"}],"internalType":"struct IIndex.FeeConfig","name":"fee","type":"tuple"}],"internalType":"struct IIndex.DepositConfig","name":"_depositConfig","type":"tuple"},{"components":[{"components":[{"internalType":"uint256","name":"latestSnapshot","type":"uint256"},{"internalType":"uint256","name":"AUMDilutionPerSecond","type":"uint256"},{"internalType":"bool","name":"useCustomAUMFee","type":"bool"},{"internalType":"address","name":"staticPriceOracle","type":"address"},{"internalType":"address","name":"metadata","type":"address"},{"internalType":"address","name":"forwarder","type":"address"}],"internalType":"struct IIndex.Config","name":"shared","type":"tuple"},{"components":[{"internalType":"uint16","name":"BPs","type":"uint16"},{"internalType":"bool","name":"useCustomCallback","type":"bool"}],"internalType":"struct IIndex.FeeConfig","name":"fee","type":"tuple"},{"internalType":"Currency[]","name":"currencies","type":"address[]"},{"internalType":"uint256[]","name":"balances","type":"uint256[]"}],"internalType":"struct IIndex.RedemptionConfig","name":"_redemptionConfig","type":"tuple"}],"name":"setConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_configBuilder","type":"address"}],"name":"setConfigBuilder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_feePool","type":"address"}],"name":"setFeePool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_rebalancer","type":"address"}],"name":"setRebalancer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"startIndexRebalancing","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256[]","name":"currencyIndexSet","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"internalType":"struct IVault.CurrencyWithdrawal","name":"withdrawals","type":"tuple"}],"name":"startRebalancingPhase","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":"","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":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"}],"name":"upgradeTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"snapshot","type":"uint256"},{"internalType":"uint256","name":"kAmount","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
610120346200018f57601f62005e3738819003918201601f19168301916001600160401b0383118484101762000193578084926060946040528339810103126200018f576200004e81620001a7565b9060406200005f60208301620001a7565b9101519030608052610100926012845260a05260c05260e0525f5460ff8160081c166200013a5760ff80821610620000ff575b50604051615c7f9182620001b88339608051828181610f8c015281816111d60152611353015260a05182818161159101526118ba015260c0518281816108410152611a0c015260e05182818161081801528181611568015281816119bd0152611a9b01525181610f1d0152f35b60ff90811916175f557f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498602060405160ff8152a15f62000092565b60405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b6064820152608490fd5b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b519061ffff821682036200018f5756fe6080604052600436101561001a575b3615610018575f80fd5b005b5f3560e01c806306fdde03146102a9578063095ea7b3146102a45780630ad58d2f1461029f57806317f159721461029a57806318160ddd1461029557806319db2228146102905780631e2eaeaf1461028b5780632137eb661461028657806323b872dd146102815780632f3eec491461027c578063313ce567146102775780633644e515146102725780633659cfe61461026d5780634f1ef2861461026857806352d1902d146102635780635e7a48c61461025e57806369945066146102595780636cfd15531461025457806370a082311461024f578063715018a61461024a5780637ecebe00146102455780637f925f8d146102405780638da5cb5b1461023b5780638f15b4141461023657806395d89b41146102315780639af1d35a1461022c5780639ed78dce14610227578063a10954fe14610222578063a68a29971461021d578063a9059cbb14610218578063cd3293de14610213578063d1509c4c1461020e578063d505accf14610209578063d7c0e03814610204578063dbd035ff146101ff578063dd62ed3e146101fa578063dedd60bc146101f5578063e0fb6993146101f0578063e2cbf4d4146101eb578063f2fde38b146101e65763f5f260e30361000e57612eee565b612e47565b612dca565b612d5e565b612cc3565b612c6a565b612bd3565b61278e565b612467565b612421565b6123fa565b6123d0565b61225e565b612237565b612046565b611fda565b611f33565b611e02565b611ddc565b611d99565b611d5c565b611d03565b611cc6565b611c27565b6117c8565b61141d565b611339565b611191565b610f63565b610f41565b610f04565b610dc5565b610d7a565b610c0a565b610bbd565b610b78565b610b51565b6106d2565b6105a2565b610517565b610421565b5f9103126102b857565b5f80fd5b90600182811c921680156102ea575b60208310146102d657565b634e487b7160e01b5f52602260045260245ffd5b91607f16916102cb565b634e487b7160e01b5f52604160045260245ffd5b67ffffffffffffffff811161031c57604052565b6102f4565b6080810190811067ffffffffffffffff82111761031c57604052565b6040810190811067ffffffffffffffff82111761031c57604052565b6020810190811067ffffffffffffffff82111761031c57604052565b6060810190811067ffffffffffffffff82111761031c57604052565b60a0810190811067ffffffffffffffff82111761031c57604052565b90601f8019910116810190811067ffffffffffffffff82111761031c57604052565b91908251928382525f5b8481106103f9575050825f602080949584010152601f8019910116010190565b6020818301810151848301820152016103d9565b90602061041e9281815201906103cf565b90565b346102b8575f3660031901126102b8576040515f610108805490610444826102bc565b808552916020916001918281169081156104d95750600114610481575b61047d86610471818803826103ad565b6040519182918261040d565b0390f35b5f90815293507f8543e9adbfbe1f62b7411fdf032fcfea758a7d6b332f64d971a1334c2ff364dd5b8385106104c6575050505081016020016104718261047d5f610461565b80548686018401529382019381016104a9565b905086955061047d9693506020925061047194915060ff191682840152151560051b82010192935f610461565b6001600160a01b038116036102b857565b346102b85760403660031901126102b85760043561053481610506565b6001600160a01b0360243591335f5261010b602052826105688260405f20906001600160a01b03165f5260205260405f2090565b5560405192835216907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b346102b85760603660031901126102b8576024356044356004356105c582610506565b6105d0833383613ec4565b805f526101016020526105e560405f20612f91565b905f526101026020526105fa60405f20612fe8565b918151925f5b84811061060957005b806106206106196001938561304a565b5188615271565b8061062d575b5001610600565b61064b90856001600160a01b03610644858a61304a565b5116613f49565b5f610626565b8151815260208083015190820152604080830151908201526060808301516001600160801b031690820152610140810192916080810151608083015260a081015160a08301526106b160c082015160c08401906001600160601b03169052565b60e081015160e0830152610100808201519083015261012080910151910152565b346102b8576003196060368201126102b8576004359067ffffffffffffffff82116102b8576080826004019183360301126102b8576024359061071482610506565b6044359161072183610506565b610729613063565b50610732614022565b610111549261077361074484806130bf565b94604095865161076a8161075c602082019485613251565b03601f1981018352826103ad565b51902090614077565b61079761078b60a061078586806130bf565b016132fe565b6001600160a01b031690565b3303610b4157602485016107ad61078b826132fe565b946001600160a01b0396878516968703610b14575b6108cc61086a6107d0613312565b9687896108096107f36107e383806130bf565b355f5261010660205260405f2090565b306001600160a01b03165f5260205260405f2090565b5492610813611113565b9384527f0000000000000000000000000000000000000000000000000000000000000000602085015261ffff7f00000000000000000000000000000000000000000000000000000000000000001688850152614194565b9560606001600160601b03916001600160801b038151166bffffffffffffffffffffffff60801b602083015160801b16906001600160e01b0319604084015160e01b1691171761010d5501511661010e906001600160601b0319825416179055565b61091d60446108f56108dd866132fe565b6001600160a01b03165f5261010a60205260405f2090565b54928360a0890152019161091761090b84613308565b6001600160801b031690565b9061338b565b6109296108dd856132fe565b5561093486806130bf565b35976101009361094b8588019a8b51903090613ec4565b5f5b61096361095a8a806130bf565b87810190613398565b9050811015610a1f5780896109c28d6109ba8461099d6109af6109a86109a38f9a61099d60019c6109948c806130bf565b90810190613398565b906133ce565b6132fe565b96806130bf565b610120810190613398565b359051615271565b8a83156109ec575b5089816109db575b5050500161094d565b6109e492613f49565b5f80896109d2565b90610a13610a0760c0610a199401516001600160601b031690565b6001600160601b031690565b906133de565b8a6109ca565b508397507fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9450829561047d9a889a7fbbbdee62287b5bf3bee13cab60a29ad729cf38109bccbd2a986a11c99b8ca70485610ae997610adb829a5f9e610ae39a610aa760c0610a96610a908e6132fe565b97613308565b9a519301516001600160601b031690565b925195869516991697849160409194936001600160601b03916001600160801b036060860197168552602085015216910152565b0390a46132fe565b93613308565b85516001600160801b03919091168152921691602090a3610b0a600160c955565b5191829182610651565b610b3c85610b2460448401613308565b6001600160801b03610b35876132fe565b91166140b2565b6107c2565b60048451636edaef2f60e11b8152fd5b346102b8575f3660031901126102b85760206001600160801b0361010d5416604051908152f35b346102b85760203660031901126102b857600435610b9581610506565b610b9d6143dd565b6001600160a01b0361011291166001600160a01b03198254161790555f80f35b346102b85760203660031901126102b857602060043554604051908152f35b9181601f840112156102b85782359167ffffffffffffffff83116102b857602083818601950101116102b857565b346102b85760803660031901126102b857600435610c2781610506565b60243560443591610c3783610506565b60643567ffffffffffffffff81116102b857610c57903690600401610bdc565b9360fb549060ff6001600160a01b0392610c75848260081c16614435565b1615610d6957610c97846001600160a01b03165f5261010560205260405f2090565b610ca286825461338b565b9055610caf858286613f49565b1693843b156102b857610cf4945f92836040518098819582947f7a7c73480000000000000000000000000000000000000000000000000000000084526004840161340b565b03925af1928315610d64577fb3762e93ec66871dd27c421b64edc79636345ff0a949cd04f7f8efce5bd4240e93610d4b575b50604080516001600160a01b039092168252602082019290925290819081015b0390a1005b80610d58610d5e92610308565b806102ae565b5f610d26565b61341c565b60046040516370e0699160e11b8152fd5b346102b85760603660031901126102b857610dba600435610d9a81610506565b602435610da681610506565b60443591610db53382856140b2565b614470565b602060405160018152f35b346102b85760203660031901126102b857600435610de281610506565b610df861078b610112546001600160a01b031690565b3303610ef35761010d5460801c6001600160601b0316610e2a826001600160a01b03165f5261010a60205260405f2090565b610e3e6001600160601b03831682546133de565b9055610e6e61010d7fffffffff000000000000000000000000ffffffffffffffffffffffffffffffff8154169055565b6040516001600160601b03821681527f984c2d523dd62865bad71db6b8b93c368cf7b3a3331818cb3b6c6cbeeefd8f9290602090a17fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef6001600160a01b0360405193169280610eee3094829190916001600160601b036020820193169052565b0390a3005b6004604051636edaef2f60e11b8152fd5b346102b8575f3660031901126102b857602060405160ff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346102b8575f3660031901126102b8576020610f5b613427565b604051908152f35b346102b85760203660031901126102b857600435610f8081610506565b6001600160a01b0390817f00000000000000000000000000000000000000000000000000000000000000001691610fb98330141561356a565b610fe87f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc9382855416146135db565b610ff06143dd565b60405190610ffd82610359565b5f82527f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff161561103657505061001891506157c7565b6020600491604094939451928380926352d1902d60e01b825286165afa5f91816110e2575b506110cf5760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201527f6f6e206973206e6f7420555550530000000000000000000000000000000000006064820152608490fd5b0390fd5b610018936110dd9114614512565b615633565b61110591925060203d60201161110c575b6110fd81836103ad565b810190614503565b905f61105b565b503d6110f3565b6040519061112082610375565b565b6040519061112082610321565b67ffffffffffffffff811161031c57601f01601f191660200190565b81601f820112156102b8578035906111628261112f565b9261117060405194856103ad565b828452602083830101116102b857815f926020809301838601378301015290565b60403660031901126102b8576004356111a981610506565b60243567ffffffffffffffff81116102b8576111c990369060040161114b565b906001600160a01b0391827f000000000000000000000000000000000000000000000000000000000000000016926112038430141561356a565b6112327f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc9482865416146135db565b61123a6143dd565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff161561127057505061001891506157c7565b6020600491604094939451928380926352d1902d60e01b825286165afa5f9181611318575b506113055760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201527f6f6e206973206e6f7420555550530000000000000000000000000000000000006064820152608490fd5b610018936113139114614512565b615772565b61133291925060203d60201161110c576110fd81836103ad565b905f611295565b346102b8575f3660031901126102b8576001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036113a4576040517f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8152602090f35b608460405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152fd5b90816101409103126102b85790565b60603660031901126102b857600467ffffffffffffffff81358181116102b85761144a903690840161140e565b906024359061145882610506565b6044359081116102b85761146f9036908501610bdc565b9091611479614022565b6101008401946001600160a01b039283611492886132fe565b16156117995761011054946114b86040968751602081019061076a8161075c8d85613681565b6114c761078b60a089016132fe565b330361178a57908491610107916114e583546001600160a01b031690565b906114ef82614583565b968161170e575b5050505061150e61151d91546001600160a01b031690565b9361151885614583565b61338b565b9216156116fc575b81156116d5575061047d94611685916116276115c5611542613312565b9761155a6107f382355f5261010660205260405f2090565b54611563611113565b9081527f0000000000000000000000000000000000000000000000000000000000000000602082015261ffff7f00000000000000000000000000000000000000000000000000000000000000001689820152896115bf866145f7565b92614618565b9660606001600160601b03916001600160801b038151166bffffffffffffffffffffffff60801b602083015160801b16906001600160e01b0319604084015160e01b1691171761010d5501511661010e906001600160601b0319825416179055565b6116336108dd836132fe565b61163e8782546133de565b90558361164a836132fe565b865192835260208301889052169033907fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d790604090a36132fe565b165f7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8351806116ba87829190602083019252565b0390a36116c7600160c955565b519081529081906020820190565b83517f56316e87000000000000000000000000000000000000000000000000000000008152fd5b906117089034906133de565b90611525565b94909192939416803b156102b857611757935f80948b51968795869485937f6718cb710000000000000000000000000000000000000000000000000000000085528c85016136a2565b03925af18015610d6457859261151d9261150e92611777575b81936114f6565b80610d5861178492610308565b5f611770565b828651636edaef2f60e11b8152fd5b50604051630e4c113160e31b8152fd5b60c09060031901126102b857600490565b908160c09103126102b85790565b346102b8576101e03660031901126102b8576117e3366117a9565b610100908160c3193601126102b8576101c4359067ffffffffffffffff82116102b8576118156004923690840161140e565b9061181e6143dd565b60ff61182c60fb5460ff1690565b1615611c17576040928351946020918287019187611849846136c2565b039461185d601f19968781018b528a6103ad565b88518420885186810190611881816118758c856136d0565b038a81018352826103ad565b51902003611c085761010f5480611a5d5750506118a2600191870187613398565b905003611a36575b6118b26136fb565b61ffff9081807f0000000000000000000000000000000000000000000000000000000000000000169116119081156119fc575b5080156119e5575b80156119ba575b6119ac578651822061010f557f060b3184cebba016b934939f7c049df437e9dfb2f8c056f31a471e11b8fa68a8610d4688886119808961196b6119778b8b61195d875182810190611954816119488461364c565b038681018352826103ad565b51902061011055565b865193849182019586613251565b039081018352826103ad565b51902061011155565b6119a260ef61199160fb5460ff1690565b1660ff1660ff1960fb54161760fb55565b519182918261040d565b8551634efbf5f560e01b8152fd5b507f000000000000000000000000000000000000000000000000000000000000000060e435116118f4565b506b033b2e3c9fd0803ce800000060e435106118ed565b9050611a0a60c08701613708565b7f000000000000000000000000000000000000000000000000000000000000000082169116115f6118e5565b85517ff4fa9a92000000000000000000000000000000000000000000000000000000008152fd5b909150875185810190611a8081611a7486856136d0565b038981018352826103ad565b51902003611bf957611ad090611ac0611a97613312565b91827f0000000000000000000000000000000000000000000000000000000000000000916147f4565b6001600160801b03909116825291565b6001600160601b038216611ae6575b50506118aa565b80611b1786611b789301611b0a85611b0583516001600160601b031690565b6136e0565b6001600160601b03169052565b60606001600160601b03916001600160801b038151166bffffffffffffffffffffffff60801b602083015160801b16906001600160e01b0319604084015160e01b1691171761010d5501511661010e906001600160601b0319825416179055565b86515f80825260208201526001600160601b03821660408201527f2e8b1ce72fe9e856aba73db235bac8b167d4333386ee7ba238377671101c26d290606090a186516001600160601b0391909116815230905f907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90602090a35f80611adf565b5085516314aa439b60e11b8152fd5b8288516314aa439b60e11b8152fd5b826040516370e0699160e11b8152fd5b346102b85760203660031901126102b8577fbb95ff23c3fa9a17ac8c5e7faa2ae0edbe64f8401afe5de0048052346d1217a16020600435611c6781610506565b611c6f6143dd565b60fb547fffffffffffffffffffffff0000000000000000000000000000000000000000ff74ffffffffffffffffffffffffffffffffffffffff008360081b1691161760fb556001600160a01b0360405191168152a1005b346102b85760203660031901126102b8576001600160a01b03600435611ceb81610506565b165f5261010a602052602060405f2054604051908152f35b346102b8575f3660031901126102b857611d1b6143dd565b5f6001600160a01b036097546001600160a01b03198116609755167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b346102b85760203660031901126102b8576001600160a01b03600435611d8181610506565b165f5261010c602052602060405f2054604051908152f35b346102b8575f3660031901126102b85760fd545f526101066020526020611dd360405f20306001600160a01b03165f5260205260405f2090565b54604051908152f35b346102b8575f3660031901126102b85760206001600160a01b0360975416604051908152f35b346102b85760803660031901126102b85767ffffffffffffffff6004358181116102b857611e3490369060040161114b565b906024359081116102b857611e50611ea791369060040161114b565b604435611e5c81610506565b60643591611e6983610506565b5f5494611e8d60ff8760081c161580978198611f25575b8115611f05575b50613712565b85611e9e600160ff195f5416175f55565b611eee57613a07565b611ead57005b611ebb61ff00195f54165f55565b604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498908060208101610d46565b611f0061010061ff00195f5416175f55565b613a07565b303b15915081611f17575b505f611e87565b6001915060ff16145f611f10565b600160ff8216109150611e80565b346102b8575f3660031901126102b8576040515f610109805490611f56826102bc565b808552916020916001918281169081156104d95750600114611f825761047d86610471818803826103ad565b5f90815293507fd7f48d1c2d4fdcceabee32a4fd1437f382c65f0f9af09a878c95c20147dc06a85b838510611fc7575050505081016020016104718261047d5f610461565b8054868601840152938201938101611faa565b346102b8575f3660031901126102b85760206001600160601b0361010d5460801c16604051908152f35b9181601f840112156102b85782359167ffffffffffffffff83116102b8576020808501948460051b0101116102b857565b6001600160801b038116036102b857565b346102b85760803660031901126102b85767ffffffffffffffff6004358181116102b857612078903690600401612004565b916024359081116102b857612091903690600401612004565b919092604435936120a185610506565b606435916120ae83612035565b6120b66143dd565b61210b6120d5846120d061010d546001600160801b031690565b613bb3565b6001600160801b0361010d91167fffffffffffffffffffffffffffffffff00000000000000000000000000000000825416179055565b612127866001600160a01b03165f5261010a60205260405f2090565b61213b6001600160801b03851682546133de565b9055604080516001600160801b039490941684526001600160a01b0393878516905f907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90602090a361219461218f613bce565b614ae9565b5f5b82811061219f57005b807f0553260a2e46b0577270d8992db02d30856ca880144c72d6e9503760946aef136121d16109a3600194878b6133ce565b6121dc838b896133ce565b35906121ec82308e8c8516614d6f565b612208816001600160a01b03165f5261010560205260405f2090565b6122138382546133de565b905585516001600160a01b039190911681526020810191909152604090a101612196565b346102b8575f3660031901126102b85760206001600160601b0361010e5416604051908152f35b346102b8575f60403660031901126102b8576004359061227d82610506565b60243567ffffffffffffffff81116102b85761229d90369060040161114b565b916122a6614022565b6122bd6001600160a01b0360fb5460081c16614435565b6122c681614583565b92333b156102b8575f61230691604051809381927fa8ad4e7a0000000000000000000000000000000000000000000000000000000083526004830161040d565b038183335af18015610d6457612399575b506123477f0553260a2e46b0577270d8992db02d30856ca880144c72d6e9503760946aef13929361151883614583565b90612364816001600160a01b03165f5261010560205260405f2090565b61236f8382546133de565b9055604080516001600160a01b039290921682526020820192909252a1612396600160c955565b80f35b7f0553260a2e46b0577270d8992db02d30856ca880144c72d6e9503760946aef1392506123c590610308565b6123475f9250612317565b346102b85760403660031901126102b857610dba6004356123f081610506565b6024359033614470565b346102b8575f3660031901126102b85760206001600160a01b036101075416604051908152f35b346102b85760403660031901126102b8576020611dd360243561244381610506565b6004355f52610106835260405f20906001600160a01b03165f5260205260405f2090565b346102b85760e03660031901126102b85760043561248481610506565b60243561249081610506565b6044359060843560643560ff821682036102b85742811061269b576020915f9161196b6125a26124be613427565b92896124dc816001600160a01b03165f5261010c60205260405f2090565b80549060018201905561254a6040519384928d8d8d8601968791959493909260a09360c08401977f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c985526001600160a01b038092166020860152166040840152606083015260808201520152565b039161255e601f19938481018352826103ad565b519020604051938491898301968790916042927f19010000000000000000000000000000000000000000000000000000000000008352600283015260228201520190565b5190206040805191825260ff92909216602082015260a4359181019190915260c435606082015281805260809060015afa15610d64575f51906001600160a01b0390818316801590811561268e575b50612664578361264e826126387f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925966001600160a01b03165f5261010b60205260405f2090565b906001600160a01b03165f5260205260405f2090565b5560405193845281169316918060208101610eee565b60046040517f815e1d64000000000000000000000000000000000000000000000000000000008152fd5b905082861614155f6125f1565b60046040517f05787bdf000000000000000000000000000000000000000000000000000000008152fd5b9081518082526020808093019301915f5b8281106126e4575050505090565b8351855293810193928101926001016126d6565b919060209283815281518482015261271e848301516080604084015260a08301906126c5565b90604083015192601f1992838382030160608401528680865192838152019501905f5b8181106127655750505061041e9495506060608091015192828503019101526126c5565b909195886127846001928951906001600160a01b036020921681520190565b9701929101612741565b346102b8576020806003193601126102b85760043567ffffffffffffffff81116102b8576127c09036906004016117ba565b906040908151906127d082610321565b5f825260608083818481960152818682015201526127f86001600160a01b0360fc5416614435565b60fb5460ff16908115612b705760fd549461281c865f5261010360205260405f2090565b549261282a85830183613be7565b93865194856128428682019260808701359084613bfc565b0395612856601f19978881018352826103ad565b51902003612b60575f1987015f81815261010360205260409020546128a2611a746128818680613398565b61289089899593950189613398565b8d949194519485938c85019788613c91565b51902003612b50576128bd905f5261010460205260405f2090565b8260ff54916128cb90612fe8565b916128d592614e85565b858201936128e38584613cb8565b806128ed91613398565b6129008a5f5261010160205260405f2090565b9161290a92613cee565b6129148584613cb8565b84810161292091613398565b6129338a5f5261010260205260405f2090565b9161293d92613d52565b6129478584613cb8565b87810161295391613398565b6129668a5f5261010460205260405f2090565b9161297092613d52565b61297a8584613cb8565b8061298491613398565b9161298f8786613cb8565b86810161299b91613398565b928a51938492898401966129af9388613c91565b0390810182526129bf90826103ad565b5190206129d5885f5261010360205260405f2090565b556129e9875f5261010660205260405f2090565b30612a0491906001600160a01b03165f5260205260405f2090565b670de0b6b3a764000090558551878152670de0b6b3a7640000602082015230908060408101037f9fb8c3be7f8f68cf2f5c24f5db3697cacd5cb1241a46a26e0cce3cc03069dbc7905f92a360fe16612a669060ff1660ff1960fb54161760fb55565b612a708382613cb8565b80612a7a91613398565b612a848584613cb8565b848101612a9091613398565b8851938493612aa193918c86613dac565b037fe27d394530699805ffbd390197d830f8c46fb3038de5ef2c449701627bc1bedf91a1612acf8382613cb8565b858101612adb91613398565b939092612ae88284613cb8565b80612af291613398565b92612afd9194613cb8565b818101612b0991613398565b949095612b14611122565b998a523690612b2292613dd8565b908801523690612b3192613e26565b848601523690612b4092613dd8565b908301525161047d8192826126f8565b60048751633f4d605360e01b8152fd5b60048651633f4d605360e01b8152fd5b600484516370e0699160e11b8152fd5b67ffffffffffffffff811161031c5760051b60200190565b60209060206040818301928281528551809452019301915f5b828110612bbf575050505090565b835185529381019392810192600101612bb1565b346102b8576020806003193601126102b85760043567ffffffffffffffff81116102b857366023820112156102b857806004013590612c1182612b80565b91612c1f60405193846103ad565b8083526024602084019160051b830101913683116102b857602401905b828210612c5b5761047d612c4f85613e7e565b60405191829182612b98565b81358152908401908401612c3c565b346102b85760403660031901126102b8576020611dd3600435612c8c81610506565b6001600160a01b0360243591612ca183610506565b165f5261010b835260405f20906001600160a01b03165f5260205260405f2090565b346102b8576003196020368201126102b8576004359067ffffffffffffffff908183116102b85760409083360301126102b857612d0a6001600160a01b0360fc5416614435565b60405190612d178261033d565b82600401358181116102b857612d339060043691860101613ea9565b825260248301359081116102b857610018926004612d549236920101613ea9565b6020820152614ae9565b346102b85760203660031901126102b8577f509ff0713b4465232ccc25d9ee84bb20cff8ebe31efe391a01233865558242b460206001600160a01b03600435612da681610506565b612dae6143dd565b16806001600160a01b031960fc54161760fc55604051908152a1005b346102b85760203660031901126102b85760043567ffffffffffffffff81116102b857612dfb903690600401612004565b90612e046143dd565b5f905f925b808410612e1b57602083604051908152f35b9091506001612e3d612e2e8584866133ce565b35612e3881610506565b6149c6565b9301929190612e09565b346102b85760203660031901126102b857600435612e6481610506565b612e6c6143dd565b6001600160a01b03811615612e8457610018906148f8565b608460405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152fd5b346102b8575f3660031901126102b857612f066143dd565b60fb805460ff19811660ff909116176010179055005b6040519060fe5480835282602091602082019060fe5f527f54075df80ec1ae6ac9100e1fd0ebf3246c17f5c933137af392011f4c5f61513a935f905b828210612f6e57505050611120925003836103ad565b85546001600160a01b031684526001958601958895509381019390910190612f58565b90604051918281549182825260209260208301915f5260205f20935f905b828210612fc557505050611120925003836103ad565b85546001600160a01b031684526001958601958895509381019390910190612faf565b90604051918281549182825260209260208301915f5260205f20935f905b82821061301c57505050611120925003836103ad565b855484526001958601958895509381019390910190613006565b634e487b7160e01b5f52603260045260245ffd5b805182101561305e5760209160051b010190565b613036565b60405190610140820182811067ffffffffffffffff82111761031c576040525f610120838281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e0820152826101008201520152565b90359061013e19813603018212156102b8570190565b801515036102b857565b60c435815260e4356020820152610104356130f9816130d5565b1515604082015260a06101243561310f81610506565b6001600160a01b038091166060840152806101443561312d81610506565b1660808401526101643561314081610506565b16910152565b60a09080358352602081013560208401526040810135613165816130d5565b151560408401528160608201359161317c83610506565b6001600160a01b03809316606086015282608082013561319b81610506565b166080860152013561314081610506565b61ffff8116036102b857565b6020809161ffff81356131ca816131ac565b16845201356131d8816130d5565b1515910152565b9035601e19823603018112156102b857016020813591019167ffffffffffffffff82116102b8578160051b360383136102b857565b90918281527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83116102b85760209260051b809284830137010190565b91906020926020815261016081019161326d6020830182613146565b61327d60e0830160c083016131b8565b61328b6101008201826131df565b919093610140928061012092858488015252610180850195905f5b8181106132d55750505061041e959650906132c3918101906131df565b929091601f1982860301910152613214565b90919689806001926001600160a01b038b356132f081610506565b1681520198019291016132a6565b3561041e81610506565b3561041e81612035565b6040519061331f82610321565b81606061010d546001600160801b03811683526001600160601b0390818160801c16602085015260e01c604084015261010e5416910152565b634e487b7160e01b5f52601160045260245ffd5b6b033b2e3c9fd0803ce7ffffff1981019190821161338657565b613358565b9190820391821161338657565b903590601e19813603018212156102b8570180359067ffffffffffffffff82116102b857602001918160051b360383136102b857565b919081101561305e5760051b0190565b9190820180921161338657565b908060209392818452848401375f828201840152601f01601f1916010190565b91602061041e9381815201916133eb565b6040513d5f823e3d90fd5b6040516101088054915f61343a846102bc565b80835260209485840194600191876001821691825f146135455750506001146134ec575b50505091816134756134e69361075c9503826103ad565b519020604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f95810195865260208601929092527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc69085015246606085015230608085015291829060a0850190565b51902090565b5f90815286935091907f8543e9adbfbe1f62b7411fdf032fcfea758a7d6b332f64d971a1334c2ff364dd5b82841061353057505050820101816134756134e661345e565b80548685018601528794909301928101613517565b60ff1916885293151560051b8601909301935084925061347591506134e6905061345e565b1561357157565b608460405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201527f64656c656761746563616c6c00000000000000000000000000000000000000006064820152fd5b156135e257565b608460405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201527f6163746976652070726f787900000000000000000000000000000000000000006064820152fd5b9061010082019161365c816130df565b61ffff6101843561366c816131ac565b1660c082015260e06101a4356131d8816130d5565b91906111209060c08061010086019561369a8185613146565b0191016131b8565b6040906001600160a01b0361041e959316815281602082015201916133eb565b9061112060c08301926130df565b60c0810192916111209190613146565b9190916001600160601b038080941691160191821161338657565b6101843561041e816131ac565b3561041e816131ac565b1561371957565b608460405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152fd5b81811061378e575050565b5f8155600101613783565b90601f82116137a6575050565b611120916101085f527f8543e9adbfbe1f62b7411fdf032fcfea758a7d6b332f64d971a1334c2ff364dd906020601f840160051c830193106137f0575b601f0160051c0190613783565b90915081906137e3565b90601f8211613807575050565b611120916101095f527fd7f48d1c2d4fdcceabee32a4fd1437f382c65f0f9af09a878c95c20147dc06a8906020601f840160051c830193106137f057601f0160051c0190613783565b90815167ffffffffffffffff811161031c57610108906138798161387484546102bc565b613799565b602080601f83116001146138ba575081906138ab9394955f926138af575b50508160011b915f199060031b1c19161790565b9055565b015190505f80613897565b90601f198316956138ed6101085f527f8543e9adbfbe1f62b7411fdf032fcfea758a7d6b332f64d971a1334c2ff364dd90565b925f905b88821061392857505083600195969710613910575b505050811b019055565b01515f1960f88460031b161c191690555f8080613906565b806001859682949686015181550195019301906138f1565b90815167ffffffffffffffff811161031c57610109906139698161396484546102bc565b6137fa565b602080601f831160011461399a575081906138ab9394955f926138af5750508160011b915f199060031b1c19161790565b90601f198316956139cd6101095f527fd7f48d1c2d4fdcceabee32a4fd1437f382c65f0f9af09a878c95c20147dc06a890565b925f905b8882106139ef5750508360019596971061391057505050811b019055565b806001859682949686015181550195019301906139d1565b909192613a3560ff5f5460081c16613a1e8161493f565b613a278161493f565b613a308161493f565b61493f565b613a3e336148f8565b613a5260ff5f5460081c16613a308161493f565b60018060c955613a606149b0565b613a686149b0565b90604051916020808401946060850160408752845180915282608087019501905f5b818110613b8857505050601f1993848682030160408701528280855192838152019401925f5b828110613b7557505050505093613b349383613ae0613b1394613b399996613b729c9b99039081018352826103ad565b5190205f80526101036020527ff167d7e9ac6011f0b837eaede5176b30419264c8a43ec5db1d59bf93c98c1f7f556148f8565b61010780546001600160a01b0319166001600160a01b038716179055613850565b613940565b61010d80547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff164260e01b6001600160e01b0319161790556149c6565b50565b8451865294810194938101938301613ab0565b90919284613ba78296988651906001600160a01b036020921681520190565b97959401929101613a8a565b9190916001600160801b038080941691160191821161338657565b60405190613bdb8261033d565b60606020838281520152565b903590603e19813603018212156102b8570190565b929190613c4560209160408652613c33613c29613c1983806131df565b6040808b015260808a0191613214565b91848101906131df565b878303603f1901606089015290613214565b930152565b9190808252602080920192915f5b828110613c66575050505090565b9091929382806001926001600160a01b038835613c8281610506565b16815201950193929101613c58565b9290613caa9061041e9593604086526040860191613c4a565b926020818503910152613214565b903590605e19813603018212156102b8570190565b91818110613cda57505050565b611120925f5260205f209182019101613783565b9067ffffffffffffffff831161031c5768010000000000000000831161031c57613d1d83835481855584613ccd565b905f526020805f20905f5b848110613d36575050505050565b60019082853595613d4687610506565b01948185015501613d28565b9067ffffffffffffffff831161031c5768010000000000000000831161031c57613d8183835481855584613ccd565b905f526020805f20905f5b848110613d9a575050505050565b83358382015592810192600101613d8c565b939161041e9593613dca928652606060208701526060860191613c4a565b926040818503910152613214565b9291613de382612b80565b91613df160405193846103ad565b829481845260208094019160051b81019283116102b857905b828210613e175750505050565b81358152908301908301613e0a565b9291613e3182612b80565b91613e3f60405193846103ad565b829481845260208094019160051b81019283116102b857905b828210613e655750505050565b8380918335613e7381610506565b815201910190613e58565b805160051b8101602090602001602083015b818110613e9d5750505090565b80515481528201613e90565b9080601f830112156102b85781602061041e93359101613dd8565b90918015613f4457815f52610106602052613ef38360405f20906001600160a01b03165f5260205260405f2090565b928354908282039182116133865793556040805192835260208301919091525f926001600160a01b0316917f9fb8c3be7f8f68cf2f5c24f5db3697cacd5cb1241a46a26e0cce3cc03069dbc79190a3565b505050565b8215613f44576001600160a01b03818116613f9f5750505f8080613f6f9481945af11590565b613f7557565b60046040517ff4b3b1bc000000000000000000000000000000000000000000000000000000008152fd5b6020925f8093613ff296604494604051947fa9059cbb00000000000000000000000000000000000000000000000000000000865216600485015260248401525af15f51600114601f3d11163d1517161590565b613ff857565b60046040517ff27f64e4000000000000000000000000000000000000000000000000000000008152fd5b600260c9541461403357600260c955565b606460405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152fd5b60ff60fb5416610d69570361408857565b60046040517ffab3fbfd000000000000000000000000000000000000000000000000000000008152fd5b91906001600160a01b031690815f5261010b806020526140e68260405f20906001600160a01b03165f5260205260405f2090565b5493600185016140f8575b5050505050565b840393841161338657614124925f5260205260405f20906001600160a01b03165f5260205260405f2090565b555f808080806140f1565b903590601e19813603018212156102b8570180359067ffffffffffffffff82116102b8576020019181360383136102b857565b6001600160801b03918216908216039190821161338657565b6001600160601b03918216908216039190821161338657565b939290916141a0613063565b94604092838501906001600160801b0392836141bb84613308565b16156143cd57918185938a935160808501526141d789806130bf565b856020840151906141e7926147f4565b95909360608601946142029086906001600160801b03169052565b838a015161ffff169061421490613308565b61421e8c806130bf565b60c0019061422c8d806130bf565b9261423695615378565b909461424281836136e0565b89516001600160601b038216815230905f907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90602090a360208901908151614291906001600160601b031690565b9061429b916136e0565b6001600160601b0390811690915289515f815292811660208401521660408201527f2e8b1ce72fe9e856aba73db235bac8b167d4333386ee7ba238377671101c26d290606090a16142ec88806130bf565b97606081016142fa9161412f565b6060880180518451919b61431c9492936001600160601b0390921692906154d2565b6101208601528085526020850182905283518a51878916949361435893909290916001600160601b0316908a166001600160801b0316866155a3565b60c087019a60e0880197015285526143799089906001600160601b03169052565b51925191516001600160801b03169485169161439493615616565b6101008801526143a391614162565b6001600160801b03169052516001600160601b031681516001600160601b031690611b0a9161417b565b60048651639811e0c760e01b8152fd5b6001600160a01b036097541633036143f157565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b6001600160a01b0316330361444657565b60046040517fee90c468000000000000000000000000000000000000000000000000000000008152fd5b91906001600160a01b038082169384156144f2571691825f5261010a60205260405f2090815491818303928311613386577fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef936020936144e392556001600160a01b03165f5261010a60205260405f2090565b818154019055604051908152a3565b6004604051630e4c113160e31b8152fd5b908160209103126102b8575190565b1561451957565b608460405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f7860448201527f6961626c655555494400000000000000000000000000000000000000000000006064820152fd5b6001600160a01b03168061459657504790565b6020602491604051928380927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa908115610d64575f916145de575090565b61041e915060203d60201161110c576110fd81836103ad565b6c010000000000000000000000008110156102b8576001600160601b031690565b93929193602085015161462c9083836147f4565b95908284610120839501614640908361412f565b60608301805187519198936001600160601b03936146629392851691886154d2565b91926146719291508b16615291565b9161467b92615874565b60409094015161ffff169160c0810185339461469695615458565b906001600160801b0316976146ab81836136e0565b6040516001600160601b038216815230905f907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90602090a3602087019081516146fb906001600160601b031690565b90614705916136e0565b6001600160601b039081169091526040805193821684525f60208501529116908201527f2e8b1ce72fe9e856aba73db235bac8b167d4333386ee7ba238377671101c26d290606090a18615614780576120d083611b0a61112097611b0561477397516001600160601b031690565b6001600160801b03169052565b6004604051639811e0c760e01b8152fd5b3561041e816130d5565b9160c06111209294936147b381610140810197613146565b01906060906001600160801b038151168352816020820151916001600160601b03809316602086015263ffffffff6040820151166040860152015116910152565b919290928361480560408501614791565b156148e6576020908461482361078b61078b608061485999016132fe565b906040518097819482937fa24777b90000000000000000000000000000000000000000000000000000000084526004840161479b565b03915afa928315610d64575f936148c5575b5082116148b4576148a6611120925b604061488d86516001600160801b031690565b95019461489e865163ffffffff1690565b9042926158b8565b9391949063ffffffff169052565b6004604051634efbf5f560e01b8152fd5b6148df91935060203d60201161110c576110fd81836103ad565b915f61486b565b50506148a6602061112093013561487a565b609754906001600160a01b0380911691826001600160a01b0319821617609755167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3565b1561494657565b608460405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152fd5b6040516149bc81610359565b5f8152905f368137565b9060ff6149e5836001600160a01b03165f5261010060205260405f2090565b5416614aaf5760fe546801000000000000000081101561031c57600181018060fe5581101561305e5760fe5f527f54075df80ec1ae6ac9100e1fd0ebf3246c17f5c933137af392011f4c5f61513a016001600160a01b0383166001600160a01b0319825416179055611120614aa260ff54604051614a828161075c886020830195869092916001600160a01b036020916040840195845216910152565b519020938460ff556001600160a01b03165f5261010060205260405f2090565b805460ff19166001179055565b6040517f2d3734a80000000000000000000000000000000000000000000000000000000081526001600160a01b0383166004820152602490fd5b90601060fb541615610d695761010e916001600160601b03835416926001600160a01b039061010790614b31838354166001600160a01b03165f5261010560205260405f2090565b80549087820180921161338657556001600160601b031981541690555416907f0553260a2e46b0577270d8992db02d30856ca880144c72d6e9503760946aef136040809381519081526020966020820152a16001906001614b9460fb5460ff1690565b16614d5f5760fd5491614ba5612f1c565b95614bc1614bbc855f5261010460205260405f2090565b612fe8565b5f919082845b614c8d575b50505050507fab22f004d2dde8ab3e8a99aac401a37dbc6c4d8a71c03a384a93da5df6551863939450614c8890614c0f6107f3845f5261010660205260405f2090565b5493614c1c853086613ec4565b614c3e81516020810190614c358161075c8a8886615a32565b51902094615a49565b93614c52855f5261010360205260405f2090565b55614c756001614c6460fb5460ff1690565b1760ff1660ff1960fb54161760fb55565b614c7e8460fd55565b5193849384615a57565b0390a1565b8951811015614d5a579081614ca6869594938851615ae4565b614cb6575b840190919293614bc7565b93509091614ccb614cc78584615ae4565b1590565b614d3157908480838c614d26614d1e614d06614cf98b614cf28f9b8d8a9f9e9d015161304a565b519561304a565b516001600160a01b031690565b6001600160a01b03165f5261010560205260405f2090565b9182546133de565b905501939050614cab565b600488517fc945242d000000000000000000000000000000000000000000000000000000008152fd5b614bcc565b600483516370e0699160e11b8152fd5b5f614e1a949381926040519560208701957f23b872dd0000000000000000000000000000000000000000000000000000000087526001600160a01b03938480921660248a0152166044880152606487015260648652614dcd86610391565b169260405194614ddc8661033d565b602086527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65646020870152519082855af1614e14615ba4565b91615c18565b80518015908115614e31575b506111209150615a73565b602091508290810103126102b8576020611120910151614e50816130d5565b5f614e26565b604051906060820182811067ffffffffffffffff82111761031c576040525f6040838281528260208201520152565b92919092614e91614e56565b935f905f5b60a08501614ea48187613398565b9050821015615186576109a38261099d614ebe9389613398565b6040805160208082019687526001600160a01b03841682840152929591929190614eeb816060810161075c565b51902094614f0b816001600160a01b03165f5261010560205260405f2090565b549081615163575b614f1d8589615ae4565b6150be575b81614f9657505050614f5582614f50614f49614f40858b018b613cb8565b85810190613398565b3691613dd8565b615ae4565b614f6457506001905b01614e96565b517faf3860f8000000000000000000000000000000000000000000000000000000008152600481019190915260249150fd5b90919288614fb4614cc787614f50614f4961095a8787018097613cb8565b61508d578385614ff9858f6109a38f91614fda614fd489614fe795613cb8565b80613398565b9c9091019b8c51916133ce565b6001600160a01b039081169116141590565b928c8415615065575b5050505061502357505050908161501c6001935160010190565b9052614f5e565b517fda8602120000000000000000000000000000000000000000000000000000000081526001600160a01b039190911660048201526024810191909152604490fd5b615081939450615079929161099491613cb8565b8751916133ce565b351415835f808c615002565b81517f22c63c1300000000000000000000000000000000000000000000000000000000815260048101879052602490fd5b906150ea90610a136150df8d6150d6878e018e613398565b909151916133ce565b3560808c0135615271565b90838b60608b018b61510689614f50614f49614fd48686613be7565b615119575b5050516001018c5250614f22565b9161513861512f6151459361514c969895613be7565b88810190613398565b96909101958651916133ce565b359061338b565b91615158815160010190565b9052838b5f8b61510b565b5f615180826001600160a01b03165f5261010560205260405f2090565b55614f13565b5050915093919293036152475760200190815160408201906151ab614fd48385613cb8565b9050810361521457506151d3614f496151c96151d893865195613cb8565b6040810190613398565b615b16565b036151e05750565b516040517fb938158e0000000000000000000000000000000000000000000000000000000081526004810191909152602490fd5b6040517fb705ebd10000000000000000000000000000000000000000000000000000000081526004810191909152602490fd5b60046040517fb7758f70000000000000000000000000000000000000000000000000000000008152fd5b90670de0b6b3a764000091815f190481118202158302156102b857020490565b6001600160801b03811160801b158202156102b85760801b0490565b906b033b2e3c9fd0803ce800000091815f190481118202158302156102b857020490565b815f190481118202158302156102b857020490565b908160209103126102b8575161041e816131ac565b92936001600160801b036001600160a01b0392969561536b610160956153268861018081019b613146565b80516001600160801b031660c089015260208101516001600160601b0390811660e08a0152604082015163ffffffff166101008a015260609091015116610120880152565b1661014085015216910152565b919493909293615393602061538c87613708565b9601614791565b6153a9575b505050506153a591615b62565b9091565b6020929394509085916153c461078b61078b608085016132fe565b916153fe604051968795869485947f8c4bdeda000000000000000000000000000000000000000000000000000000008652600486016152fb565b03915afa908115610d64575f91615429575b50809161ffff8091169116116148b4575f808080615398565b61544b915060203d602011615451575b61544381836103ad565b8101906152e6565b5f615410565b503d615439565b91949390929361546c602061538c87613708565b61547d57505050506153a591615b62565b60209293945090859161549861078b61078b608085016132fe565b916153fe604051968795869485947f6c77c9ea000000000000000000000000000000000000000000000000000000008652600486016152fb565b9061552e949260606040930135906154e982610506565b5f6001600160a01b0385518099819682957ff14340890000000000000000000000000000000000000000000000000000000084526020600485015260248401916133eb565b0393165af1928315610d64575f905f94615566575b5090615553826155599394615291565b93615271565b8281018091116133865792565b9350506040833d60401161559b575b81615582604093836103ad565b810103126102b857825160209093015192615553615543565b3d9150615575565b909491935f955f94826155ee575b505050828110156155e657925b83836155c8575050565b6155e29192955083906001600160601b03809416906152d1565b1692565b5081926155be565b9080929395505f190481118202158302156102b85702908082049106151501915f80806155b1565b9080841461562b578061041e940392036152d1565b505050505f90565b61563c816157c7565b6040516001600160a01b0382167fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a282511580159061576b575b61568157505050565b813b1561570357505f8281926020613b7295519201905af46156a1615ba4565b604051916156ae83610375565b602783527f416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c60208401527f206661696c6564000000000000000000000000000000000000000000000000006040840152615bd3565b8062461bcd60e51b6084925260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f60448201527f6e747261637400000000000000000000000000000000000000000000000000006064820152fd5b505f615678565b61577b816157c7565b6040516001600160a01b0382167fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a28251158015906157bf5761568157505050565b506001615678565b803b1561580a576001600160a01b037f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc91166001600160a01b0319825416179055565b608460405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201527f6f74206120636f6e7472616374000000000000000000000000000000000000006064820152fd5b6001600160801b039290918316806158aa575050606490045b7001000000000000000000000000000000008110156102b8571690565b6158b3926152d1565b61588d565b929193905f92819563ffffffff809216956b033b2e3c9fd0803ce8000000918282116158e5575050505050565b87039283169182156140f1579497509294509092829182156159d85750600191848316156159cb57637fffffff90945b60011c1692835b615966575050505061594a61594561593661595b9361336c565b6001600160801b0385166152ad565b6145f7565b916001600160601b03831690613bb3565b925f808080806140f1565b8060801c6102b8578002926b019d971e4fe8401e74000000938481019081106102b8578290049383821661599f575b50821c928361591c565b848692960291858304036159c1575b81019081106102b857819004935f615995565b84156159ae575f80fd5b50637fffffff8194615915565b92509250505f146159f6575061595b61594a6159456159365f61336c565b61594a61594561593661595b9361336c565b61041e916020615a2183516040845260408401906126c5565b9201519060208184039101526126c5565b929190613c45602091604086526040860190615a08565b5f1981146133865760010190565b61041e9392606092825260208201528160408201520190615a08565b15615a7a57565b608460405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152fd5b91905f928160081c9080518210615afa57505050565b60019293945060ff91615b0c9161304a565b5192161b16151590565b5f9190825b8151841015615b5d57615b2e848361304a565b51805f915b615b4c5750810180911161338657600190930192615b1b565b6001909101905f1981011680615b33565b925050565b906001600160801b039061ffff828416911661271090805f190483118102158202156102b857615b939202046145f7565b916001600160601b03831690031691565b3d15615bce573d90615bb58261112f565b91615bc360405193846103ad565b82523d5f602084013e565b606090565b90919015615bdf575090565b905b805190919015615bf45750805190602001fd5b6110cb9060405191829162461bcd60e51b83526020600484015260248301906103cf565b91929015615c795750815115615c2c575090565b3b15615c355790565b606460405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152fd5b82615be15600000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000003e80000000000000000000000000000000000000000033b2e3cc9ba9e21e3ab9439
Deployed Bytecode
0x6080604052600436101561001a575b3615610018575f80fd5b005b5f3560e01c806306fdde03146102a9578063095ea7b3146102a45780630ad58d2f1461029f57806317f159721461029a57806318160ddd1461029557806319db2228146102905780631e2eaeaf1461028b5780632137eb661461028657806323b872dd146102815780632f3eec491461027c578063313ce567146102775780633644e515146102725780633659cfe61461026d5780634f1ef2861461026857806352d1902d146102635780635e7a48c61461025e57806369945066146102595780636cfd15531461025457806370a082311461024f578063715018a61461024a5780637ecebe00146102455780637f925f8d146102405780638da5cb5b1461023b5780638f15b4141461023657806395d89b41146102315780639af1d35a1461022c5780639ed78dce14610227578063a10954fe14610222578063a68a29971461021d578063a9059cbb14610218578063cd3293de14610213578063d1509c4c1461020e578063d505accf14610209578063d7c0e03814610204578063dbd035ff146101ff578063dd62ed3e146101fa578063dedd60bc146101f5578063e0fb6993146101f0578063e2cbf4d4146101eb578063f2fde38b146101e65763f5f260e30361000e57612eee565b612e47565b612dca565b612d5e565b612cc3565b612c6a565b612bd3565b61278e565b612467565b612421565b6123fa565b6123d0565b61225e565b612237565b612046565b611fda565b611f33565b611e02565b611ddc565b611d99565b611d5c565b611d03565b611cc6565b611c27565b6117c8565b61141d565b611339565b611191565b610f63565b610f41565b610f04565b610dc5565b610d7a565b610c0a565b610bbd565b610b78565b610b51565b6106d2565b6105a2565b610517565b610421565b5f9103126102b857565b5f80fd5b90600182811c921680156102ea575b60208310146102d657565b634e487b7160e01b5f52602260045260245ffd5b91607f16916102cb565b634e487b7160e01b5f52604160045260245ffd5b67ffffffffffffffff811161031c57604052565b6102f4565b6080810190811067ffffffffffffffff82111761031c57604052565b6040810190811067ffffffffffffffff82111761031c57604052565b6020810190811067ffffffffffffffff82111761031c57604052565b6060810190811067ffffffffffffffff82111761031c57604052565b60a0810190811067ffffffffffffffff82111761031c57604052565b90601f8019910116810190811067ffffffffffffffff82111761031c57604052565b91908251928382525f5b8481106103f9575050825f602080949584010152601f8019910116010190565b6020818301810151848301820152016103d9565b90602061041e9281815201906103cf565b90565b346102b8575f3660031901126102b8576040515f610108805490610444826102bc565b808552916020916001918281169081156104d95750600114610481575b61047d86610471818803826103ad565b6040519182918261040d565b0390f35b5f90815293507f8543e9adbfbe1f62b7411fdf032fcfea758a7d6b332f64d971a1334c2ff364dd5b8385106104c6575050505081016020016104718261047d5f610461565b80548686018401529382019381016104a9565b905086955061047d9693506020925061047194915060ff191682840152151560051b82010192935f610461565b6001600160a01b038116036102b857565b346102b85760403660031901126102b85760043561053481610506565b6001600160a01b0360243591335f5261010b602052826105688260405f20906001600160a01b03165f5260205260405f2090565b5560405192835216907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b346102b85760603660031901126102b8576024356044356004356105c582610506565b6105d0833383613ec4565b805f526101016020526105e560405f20612f91565b905f526101026020526105fa60405f20612fe8565b918151925f5b84811061060957005b806106206106196001938561304a565b5188615271565b8061062d575b5001610600565b61064b90856001600160a01b03610644858a61304a565b5116613f49565b5f610626565b8151815260208083015190820152604080830151908201526060808301516001600160801b031690820152610140810192916080810151608083015260a081015160a08301526106b160c082015160c08401906001600160601b03169052565b60e081015160e0830152610100808201519083015261012080910151910152565b346102b8576003196060368201126102b8576004359067ffffffffffffffff82116102b8576080826004019183360301126102b8576024359061071482610506565b6044359161072183610506565b610729613063565b50610732614022565b610111549261077361074484806130bf565b94604095865161076a8161075c602082019485613251565b03601f1981018352826103ad565b51902090614077565b61079761078b60a061078586806130bf565b016132fe565b6001600160a01b031690565b3303610b4157602485016107ad61078b826132fe565b946001600160a01b0396878516968703610b14575b6108cc61086a6107d0613312565b9687896108096107f36107e383806130bf565b355f5261010660205260405f2090565b306001600160a01b03165f5260205260405f2090565b5492610813611113565b9384527f0000000000000000000000000000000000000000033b2e3cc9ba9e21e3ab9439602085015261ffff7f00000000000000000000000000000000000000000000000000000000000003e81688850152614194565b9560606001600160601b03916001600160801b038151166bffffffffffffffffffffffff60801b602083015160801b16906001600160e01b0319604084015160e01b1691171761010d5501511661010e906001600160601b0319825416179055565b61091d60446108f56108dd866132fe565b6001600160a01b03165f5261010a60205260405f2090565b54928360a0890152019161091761090b84613308565b6001600160801b031690565b9061338b565b6109296108dd856132fe565b5561093486806130bf565b35976101009361094b8588019a8b51903090613ec4565b5f5b61096361095a8a806130bf565b87810190613398565b9050811015610a1f5780896109c28d6109ba8461099d6109af6109a86109a38f9a61099d60019c6109948c806130bf565b90810190613398565b906133ce565b6132fe565b96806130bf565b610120810190613398565b359051615271565b8a83156109ec575b5089816109db575b5050500161094d565b6109e492613f49565b5f80896109d2565b90610a13610a0760c0610a199401516001600160601b031690565b6001600160601b031690565b906133de565b8a6109ca565b508397507fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9450829561047d9a889a7fbbbdee62287b5bf3bee13cab60a29ad729cf38109bccbd2a986a11c99b8ca70485610ae997610adb829a5f9e610ae39a610aa760c0610a96610a908e6132fe565b97613308565b9a519301516001600160601b031690565b925195869516991697849160409194936001600160601b03916001600160801b036060860197168552602085015216910152565b0390a46132fe565b93613308565b85516001600160801b03919091168152921691602090a3610b0a600160c955565b5191829182610651565b610b3c85610b2460448401613308565b6001600160801b03610b35876132fe565b91166140b2565b6107c2565b60048451636edaef2f60e11b8152fd5b346102b8575f3660031901126102b85760206001600160801b0361010d5416604051908152f35b346102b85760203660031901126102b857600435610b9581610506565b610b9d6143dd565b6001600160a01b0361011291166001600160a01b03198254161790555f80f35b346102b85760203660031901126102b857602060043554604051908152f35b9181601f840112156102b85782359167ffffffffffffffff83116102b857602083818601950101116102b857565b346102b85760803660031901126102b857600435610c2781610506565b60243560443591610c3783610506565b60643567ffffffffffffffff81116102b857610c57903690600401610bdc565b9360fb549060ff6001600160a01b0392610c75848260081c16614435565b1615610d6957610c97846001600160a01b03165f5261010560205260405f2090565b610ca286825461338b565b9055610caf858286613f49565b1693843b156102b857610cf4945f92836040518098819582947f7a7c73480000000000000000000000000000000000000000000000000000000084526004840161340b565b03925af1928315610d64577fb3762e93ec66871dd27c421b64edc79636345ff0a949cd04f7f8efce5bd4240e93610d4b575b50604080516001600160a01b039092168252602082019290925290819081015b0390a1005b80610d58610d5e92610308565b806102ae565b5f610d26565b61341c565b60046040516370e0699160e11b8152fd5b346102b85760603660031901126102b857610dba600435610d9a81610506565b602435610da681610506565b60443591610db53382856140b2565b614470565b602060405160018152f35b346102b85760203660031901126102b857600435610de281610506565b610df861078b610112546001600160a01b031690565b3303610ef35761010d5460801c6001600160601b0316610e2a826001600160a01b03165f5261010a60205260405f2090565b610e3e6001600160601b03831682546133de565b9055610e6e61010d7fffffffff000000000000000000000000ffffffffffffffffffffffffffffffff8154169055565b6040516001600160601b03821681527f984c2d523dd62865bad71db6b8b93c368cf7b3a3331818cb3b6c6cbeeefd8f9290602090a17fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef6001600160a01b0360405193169280610eee3094829190916001600160601b036020820193169052565b0390a3005b6004604051636edaef2f60e11b8152fd5b346102b8575f3660031901126102b857602060405160ff7f0000000000000000000000000000000000000000000000000000000000000012168152f35b346102b8575f3660031901126102b8576020610f5b613427565b604051908152f35b346102b85760203660031901126102b857600435610f8081610506565b6001600160a01b0390817f0000000000000000000000008491fb3d4d8515bad77740ac16b7cf1c625c8f981691610fb98330141561356a565b610fe87f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc9382855416146135db565b610ff06143dd565b60405190610ffd82610359565b5f82527f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff161561103657505061001891506157c7565b6020600491604094939451928380926352d1902d60e01b825286165afa5f91816110e2575b506110cf5760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201527f6f6e206973206e6f7420555550530000000000000000000000000000000000006064820152608490fd5b0390fd5b610018936110dd9114614512565b615633565b61110591925060203d60201161110c575b6110fd81836103ad565b810190614503565b905f61105b565b503d6110f3565b6040519061112082610375565b565b6040519061112082610321565b67ffffffffffffffff811161031c57601f01601f191660200190565b81601f820112156102b8578035906111628261112f565b9261117060405194856103ad565b828452602083830101116102b857815f926020809301838601378301015290565b60403660031901126102b8576004356111a981610506565b60243567ffffffffffffffff81116102b8576111c990369060040161114b565b906001600160a01b0391827f0000000000000000000000008491fb3d4d8515bad77740ac16b7cf1c625c8f9816926112038430141561356a565b6112327f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc9482865416146135db565b61123a6143dd565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff161561127057505061001891506157c7565b6020600491604094939451928380926352d1902d60e01b825286165afa5f9181611318575b506113055760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201527f6f6e206973206e6f7420555550530000000000000000000000000000000000006064820152608490fd5b610018936113139114614512565b615772565b61133291925060203d60201161110c576110fd81836103ad565b905f611295565b346102b8575f3660031901126102b8576001600160a01b037f0000000000000000000000008491fb3d4d8515bad77740ac16b7cf1c625c8f981630036113a4576040517f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8152602090f35b608460405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152fd5b90816101409103126102b85790565b60603660031901126102b857600467ffffffffffffffff81358181116102b85761144a903690840161140e565b906024359061145882610506565b6044359081116102b85761146f9036908501610bdc565b9091611479614022565b6101008401946001600160a01b039283611492886132fe565b16156117995761011054946114b86040968751602081019061076a8161075c8d85613681565b6114c761078b60a089016132fe565b330361178a57908491610107916114e583546001600160a01b031690565b906114ef82614583565b968161170e575b5050505061150e61151d91546001600160a01b031690565b9361151885614583565b61338b565b9216156116fc575b81156116d5575061047d94611685916116276115c5611542613312565b9761155a6107f382355f5261010660205260405f2090565b54611563611113565b9081527f0000000000000000000000000000000000000000033b2e3cc9ba9e21e3ab9439602082015261ffff7f00000000000000000000000000000000000000000000000000000000000003e81689820152896115bf866145f7565b92614618565b9660606001600160601b03916001600160801b038151166bffffffffffffffffffffffff60801b602083015160801b16906001600160e01b0319604084015160e01b1691171761010d5501511661010e906001600160601b0319825416179055565b6116336108dd836132fe565b61163e8782546133de565b90558361164a836132fe565b865192835260208301889052169033907fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d790604090a36132fe565b165f7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8351806116ba87829190602083019252565b0390a36116c7600160c955565b519081529081906020820190565b83517f56316e87000000000000000000000000000000000000000000000000000000008152fd5b906117089034906133de565b90611525565b94909192939416803b156102b857611757935f80948b51968795869485937f6718cb710000000000000000000000000000000000000000000000000000000085528c85016136a2565b03925af18015610d6457859261151d9261150e92611777575b81936114f6565b80610d5861178492610308565b5f611770565b828651636edaef2f60e11b8152fd5b50604051630e4c113160e31b8152fd5b60c09060031901126102b857600490565b908160c09103126102b85790565b346102b8576101e03660031901126102b8576117e3366117a9565b610100908160c3193601126102b8576101c4359067ffffffffffffffff82116102b8576118156004923690840161140e565b9061181e6143dd565b60ff61182c60fb5460ff1690565b1615611c17576040928351946020918287019187611849846136c2565b039461185d601f19968781018b528a6103ad565b88518420885186810190611881816118758c856136d0565b038a81018352826103ad565b51902003611c085761010f5480611a5d5750506118a2600191870187613398565b905003611a36575b6118b26136fb565b61ffff9081807f00000000000000000000000000000000000000000000000000000000000003e8169116119081156119fc575b5080156119e5575b80156119ba575b6119ac578651822061010f557f060b3184cebba016b934939f7c049df437e9dfb2f8c056f31a471e11b8fa68a8610d4688886119808961196b6119778b8b61195d875182810190611954816119488461364c565b038681018352826103ad565b51902061011055565b865193849182019586613251565b039081018352826103ad565b51902061011155565b6119a260ef61199160fb5460ff1690565b1660ff1660ff1960fb54161760fb55565b519182918261040d565b8551634efbf5f560e01b8152fd5b507f0000000000000000000000000000000000000000033b2e3cc9ba9e21e3ab943960e435116118f4565b506b033b2e3c9fd0803ce800000060e435106118ed565b9050611a0a60c08701613708565b7f00000000000000000000000000000000000000000000000000000000000003e882169116115f6118e5565b85517ff4fa9a92000000000000000000000000000000000000000000000000000000008152fd5b909150875185810190611a8081611a7486856136d0565b038981018352826103ad565b51902003611bf957611ad090611ac0611a97613312565b91827f0000000000000000000000000000000000000000033b2e3cc9ba9e21e3ab9439916147f4565b6001600160801b03909116825291565b6001600160601b038216611ae6575b50506118aa565b80611b1786611b789301611b0a85611b0583516001600160601b031690565b6136e0565b6001600160601b03169052565b60606001600160601b03916001600160801b038151166bffffffffffffffffffffffff60801b602083015160801b16906001600160e01b0319604084015160e01b1691171761010d5501511661010e906001600160601b0319825416179055565b86515f80825260208201526001600160601b03821660408201527f2e8b1ce72fe9e856aba73db235bac8b167d4333386ee7ba238377671101c26d290606090a186516001600160601b0391909116815230905f907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90602090a35f80611adf565b5085516314aa439b60e11b8152fd5b8288516314aa439b60e11b8152fd5b826040516370e0699160e11b8152fd5b346102b85760203660031901126102b8577fbb95ff23c3fa9a17ac8c5e7faa2ae0edbe64f8401afe5de0048052346d1217a16020600435611c6781610506565b611c6f6143dd565b60fb547fffffffffffffffffffffff0000000000000000000000000000000000000000ff74ffffffffffffffffffffffffffffffffffffffff008360081b1691161760fb556001600160a01b0360405191168152a1005b346102b85760203660031901126102b8576001600160a01b03600435611ceb81610506565b165f5261010a602052602060405f2054604051908152f35b346102b8575f3660031901126102b857611d1b6143dd565b5f6001600160a01b036097546001600160a01b03198116609755167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b346102b85760203660031901126102b8576001600160a01b03600435611d8181610506565b165f5261010c602052602060405f2054604051908152f35b346102b8575f3660031901126102b85760fd545f526101066020526020611dd360405f20306001600160a01b03165f5260205260405f2090565b54604051908152f35b346102b8575f3660031901126102b85760206001600160a01b0360975416604051908152f35b346102b85760803660031901126102b85767ffffffffffffffff6004358181116102b857611e3490369060040161114b565b906024359081116102b857611e50611ea791369060040161114b565b604435611e5c81610506565b60643591611e6983610506565b5f5494611e8d60ff8760081c161580978198611f25575b8115611f05575b50613712565b85611e9e600160ff195f5416175f55565b611eee57613a07565b611ead57005b611ebb61ff00195f54165f55565b604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498908060208101610d46565b611f0061010061ff00195f5416175f55565b613a07565b303b15915081611f17575b505f611e87565b6001915060ff16145f611f10565b600160ff8216109150611e80565b346102b8575f3660031901126102b8576040515f610109805490611f56826102bc565b808552916020916001918281169081156104d95750600114611f825761047d86610471818803826103ad565b5f90815293507fd7f48d1c2d4fdcceabee32a4fd1437f382c65f0f9af09a878c95c20147dc06a85b838510611fc7575050505081016020016104718261047d5f610461565b8054868601840152938201938101611faa565b346102b8575f3660031901126102b85760206001600160601b0361010d5460801c16604051908152f35b9181601f840112156102b85782359167ffffffffffffffff83116102b8576020808501948460051b0101116102b857565b6001600160801b038116036102b857565b346102b85760803660031901126102b85767ffffffffffffffff6004358181116102b857612078903690600401612004565b916024359081116102b857612091903690600401612004565b919092604435936120a185610506565b606435916120ae83612035565b6120b66143dd565b61210b6120d5846120d061010d546001600160801b031690565b613bb3565b6001600160801b0361010d91167fffffffffffffffffffffffffffffffff00000000000000000000000000000000825416179055565b612127866001600160a01b03165f5261010a60205260405f2090565b61213b6001600160801b03851682546133de565b9055604080516001600160801b039490941684526001600160a01b0393878516905f907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90602090a361219461218f613bce565b614ae9565b5f5b82811061219f57005b807f0553260a2e46b0577270d8992db02d30856ca880144c72d6e9503760946aef136121d16109a3600194878b6133ce565b6121dc838b896133ce565b35906121ec82308e8c8516614d6f565b612208816001600160a01b03165f5261010560205260405f2090565b6122138382546133de565b905585516001600160a01b039190911681526020810191909152604090a101612196565b346102b8575f3660031901126102b85760206001600160601b0361010e5416604051908152f35b346102b8575f60403660031901126102b8576004359061227d82610506565b60243567ffffffffffffffff81116102b85761229d90369060040161114b565b916122a6614022565b6122bd6001600160a01b0360fb5460081c16614435565b6122c681614583565b92333b156102b8575f61230691604051809381927fa8ad4e7a0000000000000000000000000000000000000000000000000000000083526004830161040d565b038183335af18015610d6457612399575b506123477f0553260a2e46b0577270d8992db02d30856ca880144c72d6e9503760946aef13929361151883614583565b90612364816001600160a01b03165f5261010560205260405f2090565b61236f8382546133de565b9055604080516001600160a01b039290921682526020820192909252a1612396600160c955565b80f35b7f0553260a2e46b0577270d8992db02d30856ca880144c72d6e9503760946aef1392506123c590610308565b6123475f9250612317565b346102b85760403660031901126102b857610dba6004356123f081610506565b6024359033614470565b346102b8575f3660031901126102b85760206001600160a01b036101075416604051908152f35b346102b85760403660031901126102b8576020611dd360243561244381610506565b6004355f52610106835260405f20906001600160a01b03165f5260205260405f2090565b346102b85760e03660031901126102b85760043561248481610506565b60243561249081610506565b6044359060843560643560ff821682036102b85742811061269b576020915f9161196b6125a26124be613427565b92896124dc816001600160a01b03165f5261010c60205260405f2090565b80549060018201905561254a6040519384928d8d8d8601968791959493909260a09360c08401977f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c985526001600160a01b038092166020860152166040840152606083015260808201520152565b039161255e601f19938481018352826103ad565b519020604051938491898301968790916042927f19010000000000000000000000000000000000000000000000000000000000008352600283015260228201520190565b5190206040805191825260ff92909216602082015260a4359181019190915260c435606082015281805260809060015afa15610d64575f51906001600160a01b0390818316801590811561268e575b50612664578361264e826126387f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925966001600160a01b03165f5261010b60205260405f2090565b906001600160a01b03165f5260205260405f2090565b5560405193845281169316918060208101610eee565b60046040517f815e1d64000000000000000000000000000000000000000000000000000000008152fd5b905082861614155f6125f1565b60046040517f05787bdf000000000000000000000000000000000000000000000000000000008152fd5b9081518082526020808093019301915f5b8281106126e4575050505090565b8351855293810193928101926001016126d6565b919060209283815281518482015261271e848301516080604084015260a08301906126c5565b90604083015192601f1992838382030160608401528680865192838152019501905f5b8181106127655750505061041e9495506060608091015192828503019101526126c5565b909195886127846001928951906001600160a01b036020921681520190565b9701929101612741565b346102b8576020806003193601126102b85760043567ffffffffffffffff81116102b8576127c09036906004016117ba565b906040908151906127d082610321565b5f825260608083818481960152818682015201526127f86001600160a01b0360fc5416614435565b60fb5460ff16908115612b705760fd549461281c865f5261010360205260405f2090565b549261282a85830183613be7565b93865194856128428682019260808701359084613bfc565b0395612856601f19978881018352826103ad565b51902003612b60575f1987015f81815261010360205260409020546128a2611a746128818680613398565b61289089899593950189613398565b8d949194519485938c85019788613c91565b51902003612b50576128bd905f5261010460205260405f2090565b8260ff54916128cb90612fe8565b916128d592614e85565b858201936128e38584613cb8565b806128ed91613398565b6129008a5f5261010160205260405f2090565b9161290a92613cee565b6129148584613cb8565b84810161292091613398565b6129338a5f5261010260205260405f2090565b9161293d92613d52565b6129478584613cb8565b87810161295391613398565b6129668a5f5261010460205260405f2090565b9161297092613d52565b61297a8584613cb8565b8061298491613398565b9161298f8786613cb8565b86810161299b91613398565b928a51938492898401966129af9388613c91565b0390810182526129bf90826103ad565b5190206129d5885f5261010360205260405f2090565b556129e9875f5261010660205260405f2090565b30612a0491906001600160a01b03165f5260205260405f2090565b670de0b6b3a764000090558551878152670de0b6b3a7640000602082015230908060408101037f9fb8c3be7f8f68cf2f5c24f5db3697cacd5cb1241a46a26e0cce3cc03069dbc7905f92a360fe16612a669060ff1660ff1960fb54161760fb55565b612a708382613cb8565b80612a7a91613398565b612a848584613cb8565b848101612a9091613398565b8851938493612aa193918c86613dac565b037fe27d394530699805ffbd390197d830f8c46fb3038de5ef2c449701627bc1bedf91a1612acf8382613cb8565b858101612adb91613398565b939092612ae88284613cb8565b80612af291613398565b92612afd9194613cb8565b818101612b0991613398565b949095612b14611122565b998a523690612b2292613dd8565b908801523690612b3192613e26565b848601523690612b4092613dd8565b908301525161047d8192826126f8565b60048751633f4d605360e01b8152fd5b60048651633f4d605360e01b8152fd5b600484516370e0699160e11b8152fd5b67ffffffffffffffff811161031c5760051b60200190565b60209060206040818301928281528551809452019301915f5b828110612bbf575050505090565b835185529381019392810192600101612bb1565b346102b8576020806003193601126102b85760043567ffffffffffffffff81116102b857366023820112156102b857806004013590612c1182612b80565b91612c1f60405193846103ad565b8083526024602084019160051b830101913683116102b857602401905b828210612c5b5761047d612c4f85613e7e565b60405191829182612b98565b81358152908401908401612c3c565b346102b85760403660031901126102b8576020611dd3600435612c8c81610506565b6001600160a01b0360243591612ca183610506565b165f5261010b835260405f20906001600160a01b03165f5260205260405f2090565b346102b8576003196020368201126102b8576004359067ffffffffffffffff908183116102b85760409083360301126102b857612d0a6001600160a01b0360fc5416614435565b60405190612d178261033d565b82600401358181116102b857612d339060043691860101613ea9565b825260248301359081116102b857610018926004612d549236920101613ea9565b6020820152614ae9565b346102b85760203660031901126102b8577f509ff0713b4465232ccc25d9ee84bb20cff8ebe31efe391a01233865558242b460206001600160a01b03600435612da681610506565b612dae6143dd565b16806001600160a01b031960fc54161760fc55604051908152a1005b346102b85760203660031901126102b85760043567ffffffffffffffff81116102b857612dfb903690600401612004565b90612e046143dd565b5f905f925b808410612e1b57602083604051908152f35b9091506001612e3d612e2e8584866133ce565b35612e3881610506565b6149c6565b9301929190612e09565b346102b85760203660031901126102b857600435612e6481610506565b612e6c6143dd565b6001600160a01b03811615612e8457610018906148f8565b608460405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152fd5b346102b8575f3660031901126102b857612f066143dd565b60fb805460ff19811660ff909116176010179055005b6040519060fe5480835282602091602082019060fe5f527f54075df80ec1ae6ac9100e1fd0ebf3246c17f5c933137af392011f4c5f61513a935f905b828210612f6e57505050611120925003836103ad565b85546001600160a01b031684526001958601958895509381019390910190612f58565b90604051918281549182825260209260208301915f5260205f20935f905b828210612fc557505050611120925003836103ad565b85546001600160a01b031684526001958601958895509381019390910190612faf565b90604051918281549182825260209260208301915f5260205f20935f905b82821061301c57505050611120925003836103ad565b855484526001958601958895509381019390910190613006565b634e487b7160e01b5f52603260045260245ffd5b805182101561305e5760209160051b010190565b613036565b60405190610140820182811067ffffffffffffffff82111761031c576040525f610120838281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e0820152826101008201520152565b90359061013e19813603018212156102b8570190565b801515036102b857565b60c435815260e4356020820152610104356130f9816130d5565b1515604082015260a06101243561310f81610506565b6001600160a01b038091166060840152806101443561312d81610506565b1660808401526101643561314081610506565b16910152565b60a09080358352602081013560208401526040810135613165816130d5565b151560408401528160608201359161317c83610506565b6001600160a01b03809316606086015282608082013561319b81610506565b166080860152013561314081610506565b61ffff8116036102b857565b6020809161ffff81356131ca816131ac565b16845201356131d8816130d5565b1515910152565b9035601e19823603018112156102b857016020813591019167ffffffffffffffff82116102b8578160051b360383136102b857565b90918281527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83116102b85760209260051b809284830137010190565b91906020926020815261016081019161326d6020830182613146565b61327d60e0830160c083016131b8565b61328b6101008201826131df565b919093610140928061012092858488015252610180850195905f5b8181106132d55750505061041e959650906132c3918101906131df565b929091601f1982860301910152613214565b90919689806001926001600160a01b038b356132f081610506565b1681520198019291016132a6565b3561041e81610506565b3561041e81612035565b6040519061331f82610321565b81606061010d546001600160801b03811683526001600160601b0390818160801c16602085015260e01c604084015261010e5416910152565b634e487b7160e01b5f52601160045260245ffd5b6b033b2e3c9fd0803ce7ffffff1981019190821161338657565b613358565b9190820391821161338657565b903590601e19813603018212156102b8570180359067ffffffffffffffff82116102b857602001918160051b360383136102b857565b919081101561305e5760051b0190565b9190820180921161338657565b908060209392818452848401375f828201840152601f01601f1916010190565b91602061041e9381815201916133eb565b6040513d5f823e3d90fd5b6040516101088054915f61343a846102bc565b80835260209485840194600191876001821691825f146135455750506001146134ec575b50505091816134756134e69361075c9503826103ad565b519020604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f95810195865260208601929092527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc69085015246606085015230608085015291829060a0850190565b51902090565b5f90815286935091907f8543e9adbfbe1f62b7411fdf032fcfea758a7d6b332f64d971a1334c2ff364dd5b82841061353057505050820101816134756134e661345e565b80548685018601528794909301928101613517565b60ff1916885293151560051b8601909301935084925061347591506134e6905061345e565b1561357157565b608460405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201527f64656c656761746563616c6c00000000000000000000000000000000000000006064820152fd5b156135e257565b608460405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201527f6163746976652070726f787900000000000000000000000000000000000000006064820152fd5b9061010082019161365c816130df565b61ffff6101843561366c816131ac565b1660c082015260e06101a4356131d8816130d5565b91906111209060c08061010086019561369a8185613146565b0191016131b8565b6040906001600160a01b0361041e959316815281602082015201916133eb565b9061112060c08301926130df565b60c0810192916111209190613146565b9190916001600160601b038080941691160191821161338657565b6101843561041e816131ac565b3561041e816131ac565b1561371957565b608460405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152fd5b81811061378e575050565b5f8155600101613783565b90601f82116137a6575050565b611120916101085f527f8543e9adbfbe1f62b7411fdf032fcfea758a7d6b332f64d971a1334c2ff364dd906020601f840160051c830193106137f0575b601f0160051c0190613783565b90915081906137e3565b90601f8211613807575050565b611120916101095f527fd7f48d1c2d4fdcceabee32a4fd1437f382c65f0f9af09a878c95c20147dc06a8906020601f840160051c830193106137f057601f0160051c0190613783565b90815167ffffffffffffffff811161031c57610108906138798161387484546102bc565b613799565b602080601f83116001146138ba575081906138ab9394955f926138af575b50508160011b915f199060031b1c19161790565b9055565b015190505f80613897565b90601f198316956138ed6101085f527f8543e9adbfbe1f62b7411fdf032fcfea758a7d6b332f64d971a1334c2ff364dd90565b925f905b88821061392857505083600195969710613910575b505050811b019055565b01515f1960f88460031b161c191690555f8080613906565b806001859682949686015181550195019301906138f1565b90815167ffffffffffffffff811161031c57610109906139698161396484546102bc565b6137fa565b602080601f831160011461399a575081906138ab9394955f926138af5750508160011b915f199060031b1c19161790565b90601f198316956139cd6101095f527fd7f48d1c2d4fdcceabee32a4fd1437f382c65f0f9af09a878c95c20147dc06a890565b925f905b8882106139ef5750508360019596971061391057505050811b019055565b806001859682949686015181550195019301906139d1565b909192613a3560ff5f5460081c16613a1e8161493f565b613a278161493f565b613a308161493f565b61493f565b613a3e336148f8565b613a5260ff5f5460081c16613a308161493f565b60018060c955613a606149b0565b613a686149b0565b90604051916020808401946060850160408752845180915282608087019501905f5b818110613b8857505050601f1993848682030160408701528280855192838152019401925f5b828110613b7557505050505093613b349383613ae0613b1394613b399996613b729c9b99039081018352826103ad565b5190205f80526101036020527ff167d7e9ac6011f0b837eaede5176b30419264c8a43ec5db1d59bf93c98c1f7f556148f8565b61010780546001600160a01b0319166001600160a01b038716179055613850565b613940565b61010d80547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff164260e01b6001600160e01b0319161790556149c6565b50565b8451865294810194938101938301613ab0565b90919284613ba78296988651906001600160a01b036020921681520190565b97959401929101613a8a565b9190916001600160801b038080941691160191821161338657565b60405190613bdb8261033d565b60606020838281520152565b903590603e19813603018212156102b8570190565b929190613c4560209160408652613c33613c29613c1983806131df565b6040808b015260808a0191613214565b91848101906131df565b878303603f1901606089015290613214565b930152565b9190808252602080920192915f5b828110613c66575050505090565b9091929382806001926001600160a01b038835613c8281610506565b16815201950193929101613c58565b9290613caa9061041e9593604086526040860191613c4a565b926020818503910152613214565b903590605e19813603018212156102b8570190565b91818110613cda57505050565b611120925f5260205f209182019101613783565b9067ffffffffffffffff831161031c5768010000000000000000831161031c57613d1d83835481855584613ccd565b905f526020805f20905f5b848110613d36575050505050565b60019082853595613d4687610506565b01948185015501613d28565b9067ffffffffffffffff831161031c5768010000000000000000831161031c57613d8183835481855584613ccd565b905f526020805f20905f5b848110613d9a575050505050565b83358382015592810192600101613d8c565b939161041e9593613dca928652606060208701526060860191613c4a565b926040818503910152613214565b9291613de382612b80565b91613df160405193846103ad565b829481845260208094019160051b81019283116102b857905b828210613e175750505050565b81358152908301908301613e0a565b9291613e3182612b80565b91613e3f60405193846103ad565b829481845260208094019160051b81019283116102b857905b828210613e655750505050565b8380918335613e7381610506565b815201910190613e58565b805160051b8101602090602001602083015b818110613e9d5750505090565b80515481528201613e90565b9080601f830112156102b85781602061041e93359101613dd8565b90918015613f4457815f52610106602052613ef38360405f20906001600160a01b03165f5260205260405f2090565b928354908282039182116133865793556040805192835260208301919091525f926001600160a01b0316917f9fb8c3be7f8f68cf2f5c24f5db3697cacd5cb1241a46a26e0cce3cc03069dbc79190a3565b505050565b8215613f44576001600160a01b03818116613f9f5750505f8080613f6f9481945af11590565b613f7557565b60046040517ff4b3b1bc000000000000000000000000000000000000000000000000000000008152fd5b6020925f8093613ff296604494604051947fa9059cbb00000000000000000000000000000000000000000000000000000000865216600485015260248401525af15f51600114601f3d11163d1517161590565b613ff857565b60046040517ff27f64e4000000000000000000000000000000000000000000000000000000008152fd5b600260c9541461403357600260c955565b606460405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152fd5b60ff60fb5416610d69570361408857565b60046040517ffab3fbfd000000000000000000000000000000000000000000000000000000008152fd5b91906001600160a01b031690815f5261010b806020526140e68260405f20906001600160a01b03165f5260205260405f2090565b5493600185016140f8575b5050505050565b840393841161338657614124925f5260205260405f20906001600160a01b03165f5260205260405f2090565b555f808080806140f1565b903590601e19813603018212156102b8570180359067ffffffffffffffff82116102b8576020019181360383136102b857565b6001600160801b03918216908216039190821161338657565b6001600160601b03918216908216039190821161338657565b939290916141a0613063565b94604092838501906001600160801b0392836141bb84613308565b16156143cd57918185938a935160808501526141d789806130bf565b856020840151906141e7926147f4565b95909360608601946142029086906001600160801b03169052565b838a015161ffff169061421490613308565b61421e8c806130bf565b60c0019061422c8d806130bf565b9261423695615378565b909461424281836136e0565b89516001600160601b038216815230905f907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90602090a360208901908151614291906001600160601b031690565b9061429b916136e0565b6001600160601b0390811690915289515f815292811660208401521660408201527f2e8b1ce72fe9e856aba73db235bac8b167d4333386ee7ba238377671101c26d290606090a16142ec88806130bf565b97606081016142fa9161412f565b6060880180518451919b61431c9492936001600160601b0390921692906154d2565b6101208601528085526020850182905283518a51878916949361435893909290916001600160601b0316908a166001600160801b0316866155a3565b60c087019a60e0880197015285526143799089906001600160601b03169052565b51925191516001600160801b03169485169161439493615616565b6101008801526143a391614162565b6001600160801b03169052516001600160601b031681516001600160601b031690611b0a9161417b565b60048651639811e0c760e01b8152fd5b6001600160a01b036097541633036143f157565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b6001600160a01b0316330361444657565b60046040517fee90c468000000000000000000000000000000000000000000000000000000008152fd5b91906001600160a01b038082169384156144f2571691825f5261010a60205260405f2090815491818303928311613386577fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef936020936144e392556001600160a01b03165f5261010a60205260405f2090565b818154019055604051908152a3565b6004604051630e4c113160e31b8152fd5b908160209103126102b8575190565b1561451957565b608460405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f7860448201527f6961626c655555494400000000000000000000000000000000000000000000006064820152fd5b6001600160a01b03168061459657504790565b6020602491604051928380927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa908115610d64575f916145de575090565b61041e915060203d60201161110c576110fd81836103ad565b6c010000000000000000000000008110156102b8576001600160601b031690565b93929193602085015161462c9083836147f4565b95908284610120839501614640908361412f565b60608301805187519198936001600160601b03936146629392851691886154d2565b91926146719291508b16615291565b9161467b92615874565b60409094015161ffff169160c0810185339461469695615458565b906001600160801b0316976146ab81836136e0565b6040516001600160601b038216815230905f907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90602090a3602087019081516146fb906001600160601b031690565b90614705916136e0565b6001600160601b039081169091526040805193821684525f60208501529116908201527f2e8b1ce72fe9e856aba73db235bac8b167d4333386ee7ba238377671101c26d290606090a18615614780576120d083611b0a61112097611b0561477397516001600160601b031690565b6001600160801b03169052565b6004604051639811e0c760e01b8152fd5b3561041e816130d5565b9160c06111209294936147b381610140810197613146565b01906060906001600160801b038151168352816020820151916001600160601b03809316602086015263ffffffff6040820151166040860152015116910152565b919290928361480560408501614791565b156148e6576020908461482361078b61078b608061485999016132fe565b906040518097819482937fa24777b90000000000000000000000000000000000000000000000000000000084526004840161479b565b03915afa928315610d64575f936148c5575b5082116148b4576148a6611120925b604061488d86516001600160801b031690565b95019461489e865163ffffffff1690565b9042926158b8565b9391949063ffffffff169052565b6004604051634efbf5f560e01b8152fd5b6148df91935060203d60201161110c576110fd81836103ad565b915f61486b565b50506148a6602061112093013561487a565b609754906001600160a01b0380911691826001600160a01b0319821617609755167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3565b1561494657565b608460405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152fd5b6040516149bc81610359565b5f8152905f368137565b9060ff6149e5836001600160a01b03165f5261010060205260405f2090565b5416614aaf5760fe546801000000000000000081101561031c57600181018060fe5581101561305e5760fe5f527f54075df80ec1ae6ac9100e1fd0ebf3246c17f5c933137af392011f4c5f61513a016001600160a01b0383166001600160a01b0319825416179055611120614aa260ff54604051614a828161075c886020830195869092916001600160a01b036020916040840195845216910152565b519020938460ff556001600160a01b03165f5261010060205260405f2090565b805460ff19166001179055565b6040517f2d3734a80000000000000000000000000000000000000000000000000000000081526001600160a01b0383166004820152602490fd5b90601060fb541615610d695761010e916001600160601b03835416926001600160a01b039061010790614b31838354166001600160a01b03165f5261010560205260405f2090565b80549087820180921161338657556001600160601b031981541690555416907f0553260a2e46b0577270d8992db02d30856ca880144c72d6e9503760946aef136040809381519081526020966020820152a16001906001614b9460fb5460ff1690565b16614d5f5760fd5491614ba5612f1c565b95614bc1614bbc855f5261010460205260405f2090565b612fe8565b5f919082845b614c8d575b50505050507fab22f004d2dde8ab3e8a99aac401a37dbc6c4d8a71c03a384a93da5df6551863939450614c8890614c0f6107f3845f5261010660205260405f2090565b5493614c1c853086613ec4565b614c3e81516020810190614c358161075c8a8886615a32565b51902094615a49565b93614c52855f5261010360205260405f2090565b55614c756001614c6460fb5460ff1690565b1760ff1660ff1960fb54161760fb55565b614c7e8460fd55565b5193849384615a57565b0390a1565b8951811015614d5a579081614ca6869594938851615ae4565b614cb6575b840190919293614bc7565b93509091614ccb614cc78584615ae4565b1590565b614d3157908480838c614d26614d1e614d06614cf98b614cf28f9b8d8a9f9e9d015161304a565b519561304a565b516001600160a01b031690565b6001600160a01b03165f5261010560205260405f2090565b9182546133de565b905501939050614cab565b600488517fc945242d000000000000000000000000000000000000000000000000000000008152fd5b614bcc565b600483516370e0699160e11b8152fd5b5f614e1a949381926040519560208701957f23b872dd0000000000000000000000000000000000000000000000000000000087526001600160a01b03938480921660248a0152166044880152606487015260648652614dcd86610391565b169260405194614ddc8661033d565b602086527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65646020870152519082855af1614e14615ba4565b91615c18565b80518015908115614e31575b506111209150615a73565b602091508290810103126102b8576020611120910151614e50816130d5565b5f614e26565b604051906060820182811067ffffffffffffffff82111761031c576040525f6040838281528260208201520152565b92919092614e91614e56565b935f905f5b60a08501614ea48187613398565b9050821015615186576109a38261099d614ebe9389613398565b6040805160208082019687526001600160a01b03841682840152929591929190614eeb816060810161075c565b51902094614f0b816001600160a01b03165f5261010560205260405f2090565b549081615163575b614f1d8589615ae4565b6150be575b81614f9657505050614f5582614f50614f49614f40858b018b613cb8565b85810190613398565b3691613dd8565b615ae4565b614f6457506001905b01614e96565b517faf3860f8000000000000000000000000000000000000000000000000000000008152600481019190915260249150fd5b90919288614fb4614cc787614f50614f4961095a8787018097613cb8565b61508d578385614ff9858f6109a38f91614fda614fd489614fe795613cb8565b80613398565b9c9091019b8c51916133ce565b6001600160a01b039081169116141590565b928c8415615065575b5050505061502357505050908161501c6001935160010190565b9052614f5e565b517fda8602120000000000000000000000000000000000000000000000000000000081526001600160a01b039190911660048201526024810191909152604490fd5b615081939450615079929161099491613cb8565b8751916133ce565b351415835f808c615002565b81517f22c63c1300000000000000000000000000000000000000000000000000000000815260048101879052602490fd5b906150ea90610a136150df8d6150d6878e018e613398565b909151916133ce565b3560808c0135615271565b90838b60608b018b61510689614f50614f49614fd48686613be7565b615119575b5050516001018c5250614f22565b9161513861512f6151459361514c969895613be7565b88810190613398565b96909101958651916133ce565b359061338b565b91615158815160010190565b9052838b5f8b61510b565b5f615180826001600160a01b03165f5261010560205260405f2090565b55614f13565b5050915093919293036152475760200190815160408201906151ab614fd48385613cb8565b9050810361521457506151d3614f496151c96151d893865195613cb8565b6040810190613398565b615b16565b036151e05750565b516040517fb938158e0000000000000000000000000000000000000000000000000000000081526004810191909152602490fd5b6040517fb705ebd10000000000000000000000000000000000000000000000000000000081526004810191909152602490fd5b60046040517fb7758f70000000000000000000000000000000000000000000000000000000008152fd5b90670de0b6b3a764000091815f190481118202158302156102b857020490565b6001600160801b03811160801b158202156102b85760801b0490565b906b033b2e3c9fd0803ce800000091815f190481118202158302156102b857020490565b815f190481118202158302156102b857020490565b908160209103126102b8575161041e816131ac565b92936001600160801b036001600160a01b0392969561536b610160956153268861018081019b613146565b80516001600160801b031660c089015260208101516001600160601b0390811660e08a0152604082015163ffffffff166101008a015260609091015116610120880152565b1661014085015216910152565b919493909293615393602061538c87613708565b9601614791565b6153a9575b505050506153a591615b62565b9091565b6020929394509085916153c461078b61078b608085016132fe565b916153fe604051968795869485947f8c4bdeda000000000000000000000000000000000000000000000000000000008652600486016152fb565b03915afa908115610d64575f91615429575b50809161ffff8091169116116148b4575f808080615398565b61544b915060203d602011615451575b61544381836103ad565b8101906152e6565b5f615410565b503d615439565b91949390929361546c602061538c87613708565b61547d57505050506153a591615b62565b60209293945090859161549861078b61078b608085016132fe565b916153fe604051968795869485947f6c77c9ea000000000000000000000000000000000000000000000000000000008652600486016152fb565b9061552e949260606040930135906154e982610506565b5f6001600160a01b0385518099819682957ff14340890000000000000000000000000000000000000000000000000000000084526020600485015260248401916133eb565b0393165af1928315610d64575f905f94615566575b5090615553826155599394615291565b93615271565b8281018091116133865792565b9350506040833d60401161559b575b81615582604093836103ad565b810103126102b857825160209093015192615553615543565b3d9150615575565b909491935f955f94826155ee575b505050828110156155e657925b83836155c8575050565b6155e29192955083906001600160601b03809416906152d1565b1692565b5081926155be565b9080929395505f190481118202158302156102b85702908082049106151501915f80806155b1565b9080841461562b578061041e940392036152d1565b505050505f90565b61563c816157c7565b6040516001600160a01b0382167fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a282511580159061576b575b61568157505050565b813b1561570357505f8281926020613b7295519201905af46156a1615ba4565b604051916156ae83610375565b602783527f416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c60208401527f206661696c6564000000000000000000000000000000000000000000000000006040840152615bd3565b8062461bcd60e51b6084925260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f60448201527f6e747261637400000000000000000000000000000000000000000000000000006064820152fd5b505f615678565b61577b816157c7565b6040516001600160a01b0382167fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a28251158015906157bf5761568157505050565b506001615678565b803b1561580a576001600160a01b037f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc91166001600160a01b0319825416179055565b608460405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201527f6f74206120636f6e7472616374000000000000000000000000000000000000006064820152fd5b6001600160801b039290918316806158aa575050606490045b7001000000000000000000000000000000008110156102b8571690565b6158b3926152d1565b61588d565b929193905f92819563ffffffff809216956b033b2e3c9fd0803ce8000000918282116158e5575050505050565b87039283169182156140f1579497509294509092829182156159d85750600191848316156159cb57637fffffff90945b60011c1692835b615966575050505061594a61594561593661595b9361336c565b6001600160801b0385166152ad565b6145f7565b916001600160601b03831690613bb3565b925f808080806140f1565b8060801c6102b8578002926b019d971e4fe8401e74000000938481019081106102b8578290049383821661599f575b50821c928361591c565b848692960291858304036159c1575b81019081106102b857819004935f615995565b84156159ae575f80fd5b50637fffffff8194615915565b92509250505f146159f6575061595b61594a6159456159365f61336c565b61594a61594561593661595b9361336c565b61041e916020615a2183516040845260408401906126c5565b9201519060208184039101526126c5565b929190613c45602091604086526040860190615a08565b5f1981146133865760010190565b61041e9392606092825260208201528160408201520190615a08565b15615a7a57565b608460405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152fd5b91905f928160081c9080518210615afa57505050565b60019293945060ff91615b0c9161304a565b5192161b16151590565b5f9190825b8151841015615b5d57615b2e848361304a565b51805f915b615b4c5750810180911161338657600190930192615b1b565b6001909101905f1981011680615b33565b925050565b906001600160801b039061ffff828416911661271090805f190483118102158202156102b857615b939202046145f7565b916001600160601b03831690031691565b3d15615bce573d90615bb58261112f565b91615bc360405193846103ad565b82523d5f602084013e565b606090565b90919015615bdf575090565b905b805190919015615bf45750805190602001fd5b6110cb9060405191829162461bcd60e51b83526020600484015260248301906103cf565b91929015615c795750815115615c2c575090565b3b15615c355790565b606460405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152fd5b82615be156
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000003e80000000000000000000000000000000000000000033b2e3cc9ba9e21e3ab9439
-----Decoded View---------------
Arg [0] : _maxDepositFeeInBPs (uint16): 1000
Arg [1] : _maxRedemptionFeeInBPs (uint16): 1000
Arg [2] : _maxAUMDilutionPerSecond (uint256): 1000000003020259369417413689
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 00000000000000000000000000000000000000000000000000000000000003e8
Arg [1] : 00000000000000000000000000000000000000000000000000000000000003e8
Arg [2] : 0000000000000000000000000000000000000000033b2e3cc9ba9e21e3ab9439
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 32 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
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.