Source Code
More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 25 from a total of 99 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Deposit | 51134075 | 1 hr ago | IN | 0 MON | 0.03988745 | ||||
| Deposit | 51129938 | 2 hrs ago | IN | 0 MON | 0.05834847 | ||||
| Deposit | 51128353 | 2 hrs ago | IN | 0 MON | 0.05722455 | ||||
| Deposit | 51055328 | 10 hrs ago | IN | 0 MON | 0.06103364 | ||||
| Deposit | 51031946 | 13 hrs ago | IN | 0 MON | 0.05722638 | ||||
| Deposit | 51030053 | 13 hrs ago | IN | 0 MON | 0.05986349 | ||||
| Deposit | 51019349 | 14 hrs ago | IN | 0 MON | 0.03988433 | ||||
| Deposit | 51013961 | 15 hrs ago | IN | 0 MON | 0.05722465 | ||||
| Withdraw | 51011046 | 15 hrs ago | IN | 0 MON | 0.04003254 | ||||
| Request Redeem | 51010971 | 15 hrs ago | IN | 0 MON | 0.06654979 | ||||
| Withdraw | 50946527 | 22 hrs ago | IN | 0 MON | 0.04081787 | ||||
| Request Redeem | 50946434 | 22 hrs ago | IN | 0 MON | 0.0726351 | ||||
| Deposit | 50926350 | 24 hrs ago | IN | 0 MON | 0.03812788 | ||||
| Deposit | 50923451 | 25 hrs ago | IN | 0 MON | 0.05986349 | ||||
| Deposit | 50864581 | 31 hrs ago | IN | 0 MON | 0.05722465 | ||||
| Deposit | 50864004 | 31 hrs ago | IN | 0 MON | 0.05986469 | ||||
| Approve | 50844914 | 33 hrs ago | IN | 0 MON | 0.00538299 | ||||
| Deposit | 50794134 | 39 hrs ago | IN | 0 MON | 0.05203681 | ||||
| Deposit | 50791839 | 39 hrs ago | IN | 0 MON | 0.06177711 | ||||
| Deposit | 50783573 | 40 hrs ago | IN | 0 MON | 0.06048625 | ||||
| Request Redeem | 50570849 | 2 days ago | IN | 0 MON | 0.06577654 | ||||
| Approve | 50558988 | 2 days ago | IN | 0 MON | 0.00807707 | ||||
| Transfer | 50558907 | 2 days ago | IN | 0 MON | 0.22157055 | ||||
| Approve | 50542035 | 2 days ago | IN | 0 MON | 0.00538273 | ||||
| Approve | 50498051 | 3 days ago | IN | 0 MON | 0.00538273 |
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 47576366 | 16 days ago | Contract Creation | 0 MON |
Loading...
Loading
Contract Name:
AccountableAsyncRedeemVault
Compiler Version
v0.8.27+commit.40a35a09
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.20;
import "../constants/Errors.sol";
import {IStrategyVaultHooks, IUpdateLateStatus} from "../interfaces/IAccountableStrategy.sol";
import {PermissionLevel} from "../interfaces/IAccess.sol";
import {
IAccountableAsyncRedeemVault,
IControllerOperator,
IAsyncRedeem,
IAsyncCancelRedeem,
IAccountableVault,
VaultState
} from "../interfaces/IAccountableAsyncVault.sol";
import {IAccountableWithdrawalQueue} from "../interfaces/IAccountableWithdrawalQueue.sol";
import {AccountableVault} from "./AccountableVault.sol";
import {AccountableWithdrawalQueue} from "./queue/AccountableWithdrawalQueue.sol";
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
/// @title AccountableAsyncRedeemVault
/// @notice An ERC4626-compatible vault with ERC7540 asynchronous redemptions
/// @dev Implements IAccountableAsyncRedeemVault interface for async operations and access control
/// @custom:security-contact [email protected]
contract AccountableAsyncRedeemVault is IAccountableAsyncRedeemVault, AccountableWithdrawalQueue, AccountableVault {
using Math for uint256;
uint128 private constant INSTANT_REQUEST_ID = 0;
/// @notice AccountableAsyncVault constructor
/// @param asset_ The underlying asset token for the vault
/// @param strategy_ The loan manager contract address
/// @param sharesTransferable_ Whether shares are transferable
/// @param name_ The name of the vault issued share token
/// @param symbol_ The symbol of the vault issued share token
constructor(
IERC20 asset_,
address strategy_,
bool sharesTransferable_,
PermissionLevel permissionLevel_,
string memory name_,
string memory symbol_,
uint256 precision_
) AccountableWithdrawalQueue(precision_) AccountableVault(asset_, permissionLevel_) ERC20(name_, symbol_) {
if (strategy_ == address(0)) revert ZeroAddress();
strategy = IStrategyVaultHooks(strategy_);
transferableShares = sharesTransferable_;
precision = precision_;
}
/// @inheritdoc IAccountableVault
function deposit(uint256 assets, address receiver, address controller)
public
onlyAuth(receiver, controller)
returns (uint256 shares)
{
_checkMinAmount(assets);
_checkController(controller);
uint256 price = strategy.onDeposit(address(this), assets, receiver, controller);
shares = _convertToShares(assets, price, Math.Rounding.Floor);
_mint(receiver, shares);
_deposit(controller, assets);
emit Deposit(controller, receiver, assets, shares);
}
/// @inheritdoc IERC4626
function deposit(uint256 assets, address receiver) public override returns (uint256 shares) {
shares = deposit(assets, receiver, msg.sender);
}
/// @inheritdoc IAccountableVault
function mint(uint256 shares, address receiver, address controller)
public
onlyAuth(receiver, controller)
returns (uint256 assets)
{
_checkMinAmount(shares);
_checkController(controller);
uint256 price = strategy.onMint(address(this), shares, receiver, controller);
assets = _convertToAssets(shares, price, Math.Rounding.Ceil);
_mint(receiver, shares);
_deposit(controller, assets);
emit Deposit(controller, receiver, assets, shares);
}
/// @inheritdoc IERC4626
function mint(uint256 shares, address receiver) public override returns (uint256 assets) {
assets = mint(shares, receiver, msg.sender);
}
/// @inheritdoc IAsyncRedeem
function requestRedeem(uint256 shares, address controller, address owner)
public
onlyAuth(owner, controller)
returns (uint256 requestId)
{
_checkOperator(owner);
_checkController(controller);
_checkMinAmount(shares);
_checkShares(owner, shares);
VaultState storage state = _vaultStates[controller];
state.pendingRedeemRequest += shares;
(bool canFulfill, uint256 price) = strategy.onRequestRedeem(address(this), shares, controller, owner);
if (canFulfill) {
requestId = INSTANT_REQUEST_ID;
_fulfillRedeemRequest(INSTANT_REQUEST_ID, controller, shares, price);
} else {
requestId = _push(controller, shares);
}
_transfer(owner, address(this), shares);
/// @dev RequestId is non-zero if in queue, 0 otherwise (instant fulfill)
emit RedeemRequest(controller, owner, requestId, msg.sender, shares);
}
/// @inheritdoc IAsyncRedeem
function pendingRedeemRequest(uint256, address controller) public view returns (uint256 pendingShares) {
pendingShares = _vaultStates[controller].pendingRedeemRequest;
}
/// @inheritdoc IAsyncRedeem
function claimableRedeemRequest(uint256, address controller) public view returns (uint256 claimableShares) {
claimableShares = maxRedeem(controller);
}
/// @inheritdoc IERC4626
function redeem(uint256 shares, address receiver, address controller)
public
onlyAuth(receiver, controller)
returns (uint256 assets)
{
_checkMinAmount(shares);
_checkController(controller);
if (shares > maxRedeem(controller)) revert ExceedsMaxRedeem();
VaultState storage state = _vaultStates[controller];
uint256 redeemPrice = state.redeemPrice;
assets = _convertToAssets(shares, redeemPrice, Math.Rounding.Floor);
uint256 assetsUp = _convertToAssets(shares, redeemPrice, Math.Rounding.Ceil);
strategy.onRedeem(address(this), shares, receiver, controller);
_updateReservedLiquidity(assets);
_updateRedeemState(state, assets, assetsUp, shares, shares);
_burn(address(this), shares);
_withdraw(receiver, assets);
emit Withdraw(msg.sender, receiver, controller, assets, shares);
}
/// @inheritdoc IERC4626
function withdraw(uint256 assets, address receiver, address controller)
public
onlyAuth(receiver, controller)
returns (uint256 shares)
{
_checkMinAmount(assets);
_checkController(controller);
if (assets > maxWithdraw(controller)) revert ExceedsMaxRedeem();
VaultState storage state = _vaultStates[controller];
uint256 withdrawPrice = state.withdrawPrice;
shares = _convertToShares(assets, withdrawPrice, Math.Rounding.Floor);
uint256 sharesUp = _convertToShares(assets, withdrawPrice, Math.Rounding.Ceil);
strategy.onWithdraw(address(this), assets, receiver, controller);
_updateReservedLiquidity(assets);
_updateRedeemState(state, assets, assets, shares, sharesUp);
_burn(address(this), shares);
_withdraw(receiver, assets);
emit Withdraw(msg.sender, receiver, controller, assets, shares);
}
function _updateRedeemState(
VaultState storage state,
uint256 assets,
uint256 assetsUp,
uint256 shares,
uint256 sharesUp
) private {
uint256 maxWithdraw_ = state.maxWithdraw;
uint256 redeemShares_ = state.redeemShares;
if (assets > maxWithdraw_) revert ExceedsRedeemLimit();
state.maxWithdraw = maxWithdraw_ > assetsUp ? maxWithdraw_ - assetsUp : 0;
if (shares > redeemShares_) revert ExceedsRedeemLimit();
state.redeemShares = redeemShares_ > sharesUp ? redeemShares_ - sharesUp : 0;
if (state.maxWithdraw == 0) state.redeemShares = 0;
if (state.redeemShares == 0) state.maxWithdraw = 0;
}
/// @inheritdoc IAsyncCancelRedeem
function cancelRedeemRequest(address controller, address receiver) public onlyAuth(receiver, controller) {
_checkController(controller);
VaultState storage state = _vaultStates[controller];
if (state.pendingRedeemRequest == 0) revert NoPendingRedeemRequest();
bool canCancel = strategy.onCancelRedeemRequest(address(this), controller);
if (!canCancel) revert CancelRedeemRequestFailed();
uint256 requestId = _requestIds[controller];
uint256 pendingShares = state.pendingRedeemRequest;
state.pendingRedeemRequest = 0;
_transfer(address(this), receiver, pendingShares);
_reduce(controller, pendingShares);
try IUpdateLateStatus(address(strategy)).updateLateStatus() {} catch {}
emit CancelRedeemRequest(controller, receiver, requestId, msg.sender);
}
// ========================================================================== //
// Queue operations //
// ========================================================================== //
/// @inheritdoc IAccountableWithdrawalQueue
function fulfillRedeemRequest(address controller, uint256 shares) public onlyStrategy {
_fulfillRedeemRequest(_requestIds[controller], controller, shares, sharePrice());
_reduce(controller, shares);
}
/// @inheritdoc IAccountableWithdrawalQueue
function processUpToShares(uint256 maxShares) public onlyStrategy returns (uint256 assetsUsed) {
assetsUsed = _processUpToShares(maxShares, _liquidity(), sharePrice());
}
/// @inheritdoc IAccountableWithdrawalQueue
function processUpToRequestId(uint256 maxRequestId)
public
onlyStrategy
returns (uint256 processedShares, uint256 assetsUsed)
{
(processedShares, assetsUsed) = _processUpToRequestId(maxRequestId, _liquidity(), sharePrice());
}
/// @inheritdoc IAccountableWithdrawalQueue
function previewRequiredShares(uint256 maxAssets)
public
view
returns (uint256 processedShares, uint256 assetsUsed)
{
(processedShares, assetsUsed) = _previewRequiredShares(maxAssets, sharePrice());
}
/// @inheritdoc IAccountableWithdrawalQueue
function previewMaxRequestId(uint256 maxAssets) public view returns (uint256 maxRequestId, uint256 assetsUsed) {
(maxRequestId, assetsUsed) = _previewMaxRequestId(maxAssets, sharePrice());
}
/// @dev Computes free liquidity excluding accrued locked assets and reserved queue liquidity
function _liquidity() internal view returns (uint256) {
uint256 excludedAssets = strategy.accruedAssets(address(this)) + reservedLiquidity;
return totalAssets() > excludedAssets ? totalAssets() - excludedAssets : 0;
}
/// @dev Fulfills a redeem request
function _fulfillRedeemRequest(uint128 requestId, address controller, uint256 shares, uint256 price)
internal
override
{
VaultState storage state = _vaultStates[controller];
uint256 pendingRedeemRequest_ = state.pendingRedeemRequest;
if (pendingRedeemRequest_ == 0) revert NoRedeemRequest();
if (pendingRedeemRequest_ < shares) revert InsufficientAmount();
uint256 assets = _convertToAssets(shares, price, Math.Rounding.Floor);
if (assets > _liquidity()) revert InsufficientLiquidity();
reservedLiquidity += assets;
state.maxWithdraw += assets;
state.redeemShares += shares;
state.pendingRedeemRequest -= shares;
state.redeemPrice = state.maxWithdraw.mulDiv(precision, state.redeemShares);
state.withdrawPrice = state.maxWithdraw.mulDiv(precision, state.redeemShares, Math.Rounding.Ceil);
/// @dev RequestId is non-zero if in queue, 0 otherwise (instant fulfill)
emit RedeemClaimable(controller, requestId, assets, shares);
}
/// @inheritdoc IERC4626
function maxDeposit(address controller) public view override returns (uint256 maxAssets) {
maxAssets = strategy.maxDeposit(address(this), controller);
}
/// @inheritdoc IERC4626
function maxMint(address controller) public view override returns (uint256 maxShares) {
maxShares = _convertToShares(maxDeposit(controller), sharePrice(), Math.Rounding.Floor);
}
/// @inheritdoc IERC4626
function maxRedeem(address controller) public view override returns (uint256 maxShares) {
VaultState storage state = _vaultStates[controller];
maxShares = state.redeemShares;
if (maxShares == 0) return 0;
}
/// @inheritdoc IERC4626
function maxWithdraw(address controller) public view override returns (uint256 maxAssets) {
VaultState storage state = _vaultStates[controller];
maxAssets = state.maxWithdraw;
if (state.redeemShares == 0) return 0;
}
/// @inheritdoc IERC4626
/// @notice Preview deposit works for sync deposit vaults
function previewDeposit(uint256 assets) public view returns (uint256 shares) {
shares = _convertToShares(assets, sharePrice(), Math.Rounding.Floor);
}
/// @inheritdoc IERC4626
/// @notice Preview mint works for sync deposit vaults
function previewMint(uint256 shares) public view returns (uint256 assets) {
assets = _convertToAssets(shares, sharePrice(), Math.Rounding.Ceil);
}
/// @inheritdoc IERC4626
/// @notice Preview functions are not supported for async vaults
function previewRedeem(uint256) public pure returns (uint256) {
revert();
}
/// @inheritdoc IERC4626
/// @notice Preview functions are not supported for async vaults
function previewWithdraw(uint256) public pure returns (uint256) {
revert();
}
/// @inheritdoc IERC165
function supportsInterface(bytes4 interfaceId) public pure override returns (bool) {
return interfaceId == type(IAccountableAsyncRedeemVault).interfaceId || interfaceId == type(IERC165).interfaceId
|| interfaceId == type(IAsyncRedeem).interfaceId || interfaceId == type(IAsyncCancelRedeem).interfaceId
|| interfaceId == type(IAccountableVault).interfaceId || interfaceId == type(IERC4626).interfaceId
|| interfaceId == type(IControllerOperator).interfaceId || interfaceId == type(IERC20).interfaceId
|| interfaceId == type(IAccountableWithdrawalQueue).interfaceId
|| interfaceId == type(IERC20Metadata).interfaceId;
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.20;
import {PermissionLevel} from "../interfaces/IAccess.sol";
import {IAsyncVaultFactory} from "../interfaces/IAsyncVaultFactory.sol";
import {FailedDeployment} from "../constants/Errors.sol";
import {AccountableAsyncRedeemVault} from "../vault/AccountableAsyncRedeemVault.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
/// @title AsyncVaultFactory
/// @notice Factory for creating async vaults
contract AsyncVaultFactory is IAsyncVaultFactory {
string internal constant ZERO_VAULT_ADDRESS = "zero vault address";
/// @inheritdoc IAsyncVaultFactory
function createAsyncRedeemVault(
IERC20 asset_,
address proxy_,
bool sharesTransferable_,
PermissionLevel permissionLevel_,
string memory name_,
string memory symbol_,
uint256 precision_
) external returns (address vault) {
vault = address(
new AccountableAsyncRedeemVault(
asset_, proxy_, sharesTransferable_, permissionLevel_, name_, symbol_, precision_
)
);
if (vault == address(0)) revert FailedDeployment(ZERO_VAULT_ADDRESS);
emit AsyncRedeemVaultCreated(vault);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/// @notice Struct containing transaction authentication data (EIP-712 typed)
/// @dev Chain ID is part of the EIP-712 domain separator, not this struct
struct TxAuthData {
/// @notice The calldata of the function being called (selector + encoded args)
bytes functionCallData;
/// @notice The address of the contract where the transaction is being executed
address contractAddress;
/// @notice The address of the account executing/controlling the transaction
address account;
/// @notice The per-account nonce (prevents replay)
uint256 nonce;
/// @notice The block number after which the transaction is considered expired
uint256 blockExpiration;
}
/// @notice Struct containing verification data for verifyMany function
struct VerifyManyData {
/// @notice The function call data extracted from msgData
bytes argsWithSelector;
/// @notice The block expiration timestamp
uint256 blockExpiration;
/// @notice The start position of signatures in msgData
uint256 signaturesStart;
/// @notice The number of signatures to verify
uint256 numSignatures;
}
/// @notice Enum representing different permission levels
enum PermissionLevel {
/// @notice No permission
None,
/// @notice KYC based permission
KYC,
/// @notice Whitelist based permission
Whitelist
}
/// @title Whitelistable Interface
/// @notice Interface for managing whitelisted accounts
interface IWhitelistable {
/// @notice Emitted when allowed status is set for an account
/// @param account The address of the account
/// @param allowed The allowed status
event AllowedSet(address indexed account, bool allowed);
/// @notice Set allowed accounts
/// @param accounts Array of account addresses
/// @param allowed Array of allowed status corresponding to acounts
function setAllowed(address[] calldata accounts, bool[] calldata allowed) external;
/// @notice Check if an account is allowed
/// @param account The address to check allowed status for
/// @return bool True if the account is allowed, false otherwise
function allowed(address account) external view returns (bool);
/// @notice Check if multiple accounts are allowed
/// @param accounts Array of account addresses
/// @return bool True if the accounts are allowed, false otherwise
function allowedMany(address[] calldata accounts) external view returns (bool);
}
/// @title Authorizable Interface
/// @notice Interface for managing authorizable accounts
interface IAuthorizable {
/// @notice Emitted when the signer address is changed
/// @param oldSigner The old signer address
/// @param newSigner The new signer address
event SignerChanged(address indexed oldSigner, address indexed newSigner);
/// @notice Emitted when a transaction authentication data is verified
/// @param chainID The chain ID where the transaction is intended to be processed
/// @param nonce The nonce of the user being verified to prevent replay attacks
/// @param blockExpiration The block number after which the transaction is considered expired
/// @param contractAddress The address of the contract where the transaction is being executed
/// @param userAddress The address of the user executing the transaction
/// @param functionCallData The calldata of the function being called
event TxAuthDataVerified(
uint256 chainID,
uint256 nonce,
uint256 blockExpiration,
address indexed contractAddress,
address indexed userAddress,
bytes functionCallData
);
/// @notice Set the signer address
/// @param signer The address of the signer
function setSigner(address signer) external;
/// @notice Get the signer address
/// @return The signer address
function signer() external view returns (address);
/// @notice Get the nonce for a given user
/// @param user The address of the user
/// @return The nonce of the user
function nonces(address user) external view returns (uint256);
/// @notice Get the message hash for a given transaction authentication data
/// @param txAuthData The transaction authentication data
/// @return The message hash
function getMessageHash(TxAuthData calldata txAuthData) external view returns (bytes32);
}
/// @title Access Interface
/// @notice Interface for managing access to a contract
interface IAccess is IAuthorizable, IWhitelistable {
/// @notice Get the permission level for the loan
/// @return The permission level enum value
function permissionLevel() external view returns (PermissionLevel);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.20;
import {PermissionLevel} from "./IAccess.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
/// @title IAsyncVaultFactory
/// @notice Interface for creating async vaults
interface IAsyncVaultFactory {
/// @notice Emitted when a new async redeem vault is created
/// @param vault The address of the created vault
event AsyncRedeemVaultCreated(address indexed vault);
/// @notice Creates a new async redeem vault
/// @param asset The asset token address for the vault
/// @param proxy The proxy address for the vault
/// @param sharesTransferable Whether shares are transferable
/// @param permissionLevel The permission level for the vault
/// @param name The name of the vault
/// @param symbol The symbol of the vault
/// @param precision The precision for the vault
function createAsyncRedeemVault(
IERC20 asset,
address proxy,
bool sharesTransferable,
PermissionLevel permissionLevel,
string memory name,
string memory symbol,
uint256 precision
) external returns (address);
}// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.20; // ========================================================================== // // Authorization Errors // // ========================================================================== // /// @notice Error thrown when unauthorized error Unauthorized(); /// @notice Thrown when a signature verification fails due to invalid signer error InvalidSigner(); /// @notice Thrown when an operation is attempted with invalid operator permissions error InvalidOperator(); /// @notice Error thrown when invalid pending borrower is provided error InvalidPendingBorrower(); /// @notice Thrown when KYC status is not verified error KYCNotVerified(); /// @notice Thrown when a block expiration is invalid (e.g. in the past) error InvalidBlockExpiration(); /// @notice Thrown when a signature verification fails error InvalidSignature(); /// @notice Thrown when a message data length is invalid error InvalidMsgDataLength(); /// @notice Thrown when an accounts array is empty error EmptyAccountsArray(); // ========================================================================== // // Vault operations errors // // ========================================================================== // /// @notice Error thrown when trying to cancel a deposit request failed error CancelDepositRequestFailed(); /// @notice Error thrown when trying to cancel a redeem request failed error CancelRedeemRequestFailed(); /// @notice Error thrown when deposit amount exceeds max deposit error ExceedsMaxDeposit(); /// @notice Error thrown when assets exceed redemption limits error ExceedsRedeemLimit(); /// @notice Error thrown when redeem amount exceeds max redeem error ExceedsMaxRedeem(); /// @notice Error thrown when deposit/withdraw amount is insufficient error InsufficientAmount(); /// @notice Error thrown when redeem share amount is insufficient error InsufficientShares(); /// @notice Error thrown when no redeem request exists error NoRedeemRequest(); /// @notice Error thrown when no pending redeem request exists error NoPendingRedeemRequest(); /// @notice Error thrown when no cancel redeem request exists error NoCancelRedeemRequest(); /// @notice Thrown when attempting to transfer shares that are not transferable error SharesNotTransferable(); /// @notice Error thrown when no queue request exists error NoQueueRequest(); /// @notice Error thrown when redeem amount exceeds liquidity error InsufficientLiquidity(); /// @notice Error thrown when no queue requests exist error NoQueueRequests(); /// @notice Error thrown when asset is not whitelisted error AssetNotWhitelisted(); // ========================================================================== // // Loan operations errors // // ========================================================================== // /// @notice Error thrown when loan terms are already set error LoanTermsAlreadySet(); /// @notice Error thrown when loan terms are not set error LoanTermsNotSet(); /// @notice Error thrown when loan is ongoing error LoanOngoing(); /// @notice Error thrown when loan is not ongoing error LoanNotOngoing(); /// @notice Error thrown when loan is not in default error LoanNotInDefault(); /// @notice Error thrown when loan terms are not met error LoanTermsNotMet(); /// @notice Error thrown when loan has not matured error LoanNotMatured(); /// @notice Error thrown when repayment terms are not met error LoanCannotBeRepaid(); /// @notice Error thrown when interest is already claimed error InterestAlreadyClaimed(); /// @notice Error thrown when there are outstanding interest payments error OutstandingInterestPayments(); /// @notice Thrown when an operation is attempted with invalid controller permissions error InvalidController(); /// @notice Thrown when an operation is attempted with invalid vault manager permissions error InvalidVaultManager(); /// @notice Thrown when an operation is attempted with invalid interval duration pair error InvalidIntervalDurationPair(); /// @notice Thrown when an operation is attempted with invalid interval length error InvalidIntervalLength(); /// @notice Thrown when an operation is attempted with invalid withdrawal period error InvalidWithdrawalPeriod(); /// @notice Error thrown when capacity is set to a lower value than acceptable error CapacityTooLow(); /// @notice Error thrown when accept grace period is longer than acceptable for the loan error AcceptGracePeriodTooLong(); /// @notice Error thrown when a threshold exceeds the max bound error ThresholdTooHigh(); /// @notice Error thrown when attempting to pay when no payment is due error NoPaymentDue(); // ========================================================================== // // General errors // // ========================================================================== // /// @notice Thrown when an index is out of bounds error OutOfBounds(); /// @notice Thrown when an invalid range is provided error InvalidRange(); /// @notice Thrown when an operation is requested with zero amount error ZeroAmount(); /// @notice Thrown when an input address is address(0) error ZeroAddress(); /// @notice Thrown when deployment of a loan proxy contract fails /// @param reason The reason for the failed deployment error FailedDeployment(string reason); /// @notice Thrown when a deposit is not allowed error DepositNotAllowed(); /// @notice Thrown when a redeem is not allowed error RedeemNotAllowed(); /// @notice Thrown when input arrays lengths don't match error ArrayLengthMismatch(); /// @notice Error thrown when an operation is not required/allowed for the current permission level error PermissionLevelMismatch(); /// @notice Error thrown when an operation is not supported by the strategy error NotSupportedByStrategy(); // ========================================================================== // // Fee Manager errors // // ========================================================================== // /// @notice Error thrown when manager split is invalid error InvalidManagerSplit(); /// @notice Error thrown when performance fee is invalid error InvalidPerformanceFee(); /// @notice Error thrown when establishment fee is invalid error InvalidEstablishmentFee(); // ========================================================================== // // Rewards errors // // ========================================================================== // /// @notice Error thrown when a root is already set error RootAlreadySet(); /// @notice Error thrown when no root is set error RootNotSet(); /// @notice Error thrown when a root is already pending error RootAlreadyPending(); /// @notice Error thrown when no pending root is set error NoPendingRoot(); /// @notice Error thrown when timelock is not expired error TimelockNotExpired(); /// @notice Error thrown when a proof is invalid error InvalidProof(); /// @notice Error thrown when the amount to claim is not enough error NotEnoughClaimableAmount(); /// @notice Error thrown when an invalid rewards type is provided error InvalidRewardsType();
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.20;
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
/// @notice Struct containing loan terms and state
struct Loan {
/// @notice Minimum deposit amount allowed
uint256 minDeposit;
/// @notice Minimum redeem amount allowed
uint256 minRedeem;
/// @notice Maximum loan amount that can be drawn
/// The full threshold can be met after deposit period if the loan is not locked
uint256 maxCapacity;
/// @notice Minimum loan amount for the loan to be accepted
/// The threshold needs to be met during deposit period or loan can be rejected
uint256 minCapacity;
/// @notice Liquidity ratio that has to be maintained in the vault at all times
/// Expressed in basis points and cannot exceed 1e6, defaults to 0
uint256 reserveThreshold;
/// @notice Principal amount still to be repaid
uint256 outstandingPrincipal;
/// @notice Interest amount still to be paid
uint256 outstandingInterest;
/// @notice all funds accepted and available for borrowing
uint256 drawableFunds;
/// @notice Annual interest rate in basis points
uint256 interestRate;
/// @notice Late interest penalty in basis points
uint256 lateInterestPenalty;
/// @notice Total claimable interest available for users
uint256 claimableInterest;
/// @notice Time interval between interest payments
uint256 interestInterval;
/// @notice Time of loan start
uint256 startTime;
/// @notice Time of terms set
uint256 termsSetTime;
/// @notice Time of terms update
uint256 termsUpdateTime;
/// @notice Loan duration in seconds
uint256 duration;
/// @notice Deposit period in seconds
uint256 depositPeriod;
/// @notice Grace period after deposit period for borrower to accept loan
uint256 acceptGracePeriod;
/// @notice Withdrawal window period in seconds
/// If set it allows redemption requests
uint256 withdrawalPeriod;
/// @notice Late interest payment grace period in seconds
/// This is the time period before a loan is considered delinquent
uint256 lateInterestGracePeriod;
}
/// @notice Struct containing loan terms
struct LoanTerms {
/// @notice Minimum deposit amount allowed
uint256 minDeposit;
/// @notice Minimum redeem amount allowed
uint256 minRedeem;
/// @notice Maximum loan capacity
uint256 maxCapacity;
/// @notice Minimum loan capacity
uint256 minCapacity;
/// @notice Annual interest rate in basis points
uint256 interestRate;
/// @notice Late interest penalty in basis points
uint256 lateInterestPenalty;
/// @notice Late interest grace period in seconds
uint256 lateInterestGracePeriod;
/// @notice Time interval between interest payments
uint256 interestInterval;
/// @notice Duration of the loan in seconds
uint256 duration;
/// @notice Deposit period in seconds
uint256 depositPeriod;
/// @notice Grace period after deposit period for borrower to accept loan
uint256 acceptGracePeriod;
/// @notice Withdrawal window period in seconds
uint256 withdrawalPeriod;
}
/// @notice Struct containing DVN proof data
struct DVNProof {
/// @notice Merkle root of the DVN merkle tree
bytes32 root;
/// @notice Signature of the DVN payload
bytes32 signature;
/// @notice Message hash that was signed
bytes32 messageHash;
}
/// @notice Enum representing different loan states
enum LoanState {
/// @notice Loan terms are not set
Initialized,
/// @notice Loan terms are set
TermsSet,
/// @notice Loan is accepted by borrower and locked
OngoingLocked,
/// @notice Loan is accepted by borrower and dynamic deposits are allowed
OngoingDynamic,
/// @notice Loan is rejected
Rejected,
/// @notice Loan is repaid
Repaid,
/// @notice Loan is in default
InDefault,
/// @notice Loan is in default claims
InDefaultClaims
}
/// @notice Interface for managing strategy vault hooks
interface IStrategyVaultHooks {
/// @notice Hook for handling deposit requests
/// @param share The address of the share token
/// @param assets The amount of assets requested
/// @param controller The address of the controller
/// @param owner The address of the owner of the assets
/// @return canFulfill Whether the deposit can be fulfilled instantly
/// @return price The price of the share
function onRequestDeposit(address share, uint256 assets, address controller, address owner)
external
returns (bool canFulfill, uint256 price);
/// @notice Hook for handling redeem requests
/// @param share The address of the share token
/// @param shares The amount of shares requested
/// @param controller The address of the controller
/// @param owner The address of the owner of the shares
/// @return canFulfill Whether the redeem can be fulfilled instantly
/// @return price The price of the share
function onRequestRedeem(address share, uint256 shares, address controller, address owner)
external
returns (bool canFulfill, uint256 price);
/// @notice Hook for handling cancel deposit requests
/// @param share The address of the share token
/// @param controller The address of the controller
/// @return canCancel Whether the deposit can be cancelled instantly
function onCancelDepositRequest(address share, address controller) external returns (bool canCancel);
/// @notice Hook for handling cancel redeem requests
/// @param share The address of the share token
/// @param controller The address of the controller
/// @return canCancel Whether the redeem can be cancelled instantly
function onCancelRedeemRequest(address share, address controller) external returns (bool canCancel);
/// @notice Hook for handling deposit requests
/// @param share The address of the share token
/// @param assets The amount of assets to deposit
/// @param receiver The address of the receiver
/// @param controller The address of the controller
function onDeposit(address share, uint256 assets, address receiver, address controller)
external
returns (uint256 price);
/// @notice Hook for handling mint requests
/// @param share The address of the share token
/// @param shares The amount of shares to mint
/// @param receiver The address of the receiver
/// @param controller The address of the controller
function onMint(address share, uint256 shares, address receiver, address controller)
external
returns (uint256 price);
/// @notice Hook for handling redeem requests
/// @param share The address of the share token
/// @param shares The amount of shares to redeem
/// @param receiver The address of the receiver
function onRedeem(address share, uint256 shares, address receiver, address controller) external;
/// @notice Hook for handling withdraw requests
/// @param share The address of the share token
/// @param assets The amount of assets to withdraw
/// @param receiver The address of the receiver
/// @param controller The address of the controller
function onWithdraw(address share, uint256 assets, address receiver, address controller) external;
/// @notice Hook for handling vault transfers
/// @param from The address of the sender
/// @param to The address of the receiver
/// @param amount The amount of shares to transfer
function onTransfer(address share, address from, address to, uint256 amount) external;
/// @notice Operator authorization
/// @param operator The address of the operator
/// @dev Reverts for unauthorized operator. Operator should not be an input value of another call
function authOperator(address operator) external;
/// @notice Centralized share price
/// @param share The address of the share token
function sharePrice(address share) external view returns (uint256 price);
/// @notice Centralized accrued assets
/// @param share The address of the share token
/// @return assets The accrued assets to be distributed
function accruedAssets(address share) external view returns (uint256 assets);
/// @notice Centralized max deposit capacity
/// @param share The address of the share token
/// @param controller The address of the controller
/// @return maxAssets The maximum amount of assets that can be deposited
function maxDeposit(address share, address controller) external view returns (uint256 maxAssets);
/// @notice Centralized max redeem capacity
/// @param share The address of the share token
/// @param controller The address of the controller
/// @return maxShares The maximum amount of shares that can be redeemed
function maxRedeem(address share, address controller) external view returns (uint256 maxShares);
}
/// @notice Interface for managing fee manager hooks
interface IFeeManagerHooks {
/// @notice Hook for handling fee structure changes
function onFeeStructureChange() external;
}
interface IUpdateLateStatus {
/// @notice Updates the late status of the loan
function updateLateStatus() external;
}
/// @notice Interface for managing base strategy components
interface IAccountableStrategy is IStrategyVaultHooks, IFeeManagerHooks, IERC165 {
/// @notice Event emitted when the borrower is changed
event BorrowerChanged(address indexed oldBorrower, address indexed newBorrower);
/// @notice Event emitted when the pending borrower is set
event PendingBorrowerSet(address indexed pendingBorrower);
/// @notice Event emitted when the safety module is set
event SafetyModuleSet(address indexed safetyModule);
/// @notice Event emitted when the investment manager is set
event InvestmentManagerSet(address indexed investmentManager);
/// @notice Event emitted when the proof signer is set
event ProofSignerSet(address indexed proofSigner);
/// @notice Event emitted when the DVN proof is published
event DVNProofPublished(bytes32 indexed root, bytes32 indexed signature, bytes32 indexed messageHash);
/// @notice Event emitted when the default is rejected
event LoanDefaultRejected();
/// @notice Event emitted when the default is accepted
event LoanDefaulted(uint256 principal, uint256 collateral);
/// @notice Event emitted when the penalties enabled flag is set
event PenaltiesEnabledSet(bool enabled);
/// @notice Event emitted when the security admin enabled flag is set
event SecurityAdminEnabledSet(bool enabled);
/// @notice Event emitted when the operations admin enabled flag is set
event OperationsAdminEnabledSet(bool enabled);
/// @notice Event emitted when the reserve threshold is set
event ReserveThresholdSet(uint256 threshold);
/// @notice Event emitted when the rewards distributor is set
event RewardsDistributorSet(address indexed rewardsDistributor);
/// @notice Event emitted when the price oracle is set
event PriceOracleSet(address indexed priceOracle);
/// @notice Set a new pending borrower
/// @param newBorrower Address of the new pending borrower
function setPendingBorrower(address newBorrower) external;
/// @notice Accept the borrower role as pending borrower
function acceptBorrowerRole() external;
/// @notice Set a new safety module contract
/// @dev It can act as a factory in a deploy-and-set manner
/// @param safetyModule Address of the new safety module
function setSafetyModule(address safetyModule) external;
/// @notice Set a new rewards distributor contract
/// @dev It can act as a factory in a deploy-and-set manner
/// @param rewards Address of the new rewards distributor
function setRewardsDistributor(address rewards) external;
/// @notice Set a new price oracle contract
/// @param priceOracle Address of the new price oracle
function setPriceOracle(address priceOracle) external;
/// @notice Set a new investment manager contract
/// @param investmentManager Address of the new investment manager
function setInvestmentManager(address investmentManager) external;
/// @notice Set the auth signer address
/// @dev This is function relays data to the vault's access module
/// It sets the kyc verification signer when permission level is `KYC`
/// @param authSigner Address of the new auth signer
function setAuthSigner(address authSigner) external;
/// @notice Set the lenders addresses and permissions
/// @dev This is function relays data to the vault's access module
/// It whitelists lenders when permission level is `Whitelist`
/// @param lenders Addresses of the lenders to be whitelisted
/// @param allowed Whether the lenders are allowed to perform actions
function setLenders(address[] calldata lenders, bool[] calldata allowed) external;
/// @notice Set the proof signer address
/// @param proofSigner Address of the new proof signer
function setProofSigner(address proofSigner) external;
/// @notice Publish a new DVN proof
/// @param proof Latest DVN proof data
function publishDVNProof(DVNProof memory proof) external;
/// @notice Accept the default of the loan
function acceptDefault() external;
/// @notice Reject the default of the loan
function rejectDefault() external;
/// @notice Set the penalties enabled flag
/// @param enabled Whether penalties are enabled
function setPenaltiesEnabled(bool enabled) external;
/// @notice Set the security admin enabled flag
/// @param enabled Whether security admin is enabled
function setSecurityAdminEnabled(bool enabled) external;
/// @notice Set the operations admin enabled flag
/// @param enabled Whether operations admin is enabled
function setOperationsAdminEnabled(bool enabled) external;
/// @notice Set the shares transferable flag
/// @param transferable Whether shares are transferable
function setSharesTransferable(bool transferable) external;
/// @notice Set the min reserve threshold required in the vault
/// @param threshold The threshold expressed in basis points
function setReserveThreshold(uint256 threshold) external;
/// @notice Get the global registry contract address
/// @return The global registry address
function globals() external view returns (address);
/// @notice Get the current borrower address
/// @return The borrower address
function borrower() external view returns (address);
/// @notice Get the pending borrower address
/// @return The pending borrower address
function pendingBorrower() external view returns (address);
/// @notice Get the investment manager contract address
/// @return The investment manager address
function investmentManager() external view returns (address);
/// @notice Get the fee manager contract address
/// @return The fee manager address
function feeManager() external view returns (address);
/// @notice Get the safety module contract address
/// @return The safety module address
function safetyModule() external view returns (address);
/// @notice Get the rewards distributor contract address
/// @return The rewards distributor address
function rewards() external view returns (address);
/// @notice Get the price oracle contract address
/// @return The price oracle address
function priceOracle() external view returns (address);
/// @notice Get the proof signer address
/// @return The proof signer address
/// @dev Returns the pub key of the node signing proofs
function proofSigner() external view returns (address);
/// @notice Get the vault contract address
/// @return The vault address
function vault() external view returns (address);
/// @notice Get the current loan state
/// @return The loan struct
function loan() external view returns (Loan memory);
/// @notice Get the DVN proof
/// @return The latest DVN proof data
function dvnProof() external view returns (DVNProof memory);
/// @notice Get the loan state
/// @return The loan state enum value
function loanState() external view returns (LoanState);
/// @notice Get the penalties enabled flag
/// @return The penalties enabled flag
function penaltiesEnabled() external view returns (bool);
/// @notice Get the security admin enabled flag
/// @return The security admin enabled flag
function securityAdminEnabled() external view returns (bool);
/// @notice Get the operations admin enabled flag
/// @return The operations admin enabled flag
function operationsAdminEnabled() external view returns (bool);
/// @notice Get the precision for the strategy
/// @return The precision
function PRECISION() external view returns (uint256);
/// @notice Get the basis points for the strategy
/// @return The basis points
function BASIS_POINTS() external view returns (uint256);
/// @notice Get the version of the strategy
/// @dev Increment when upgrading the strategy
function version() external view returns (uint256);
}
/// @notice Interface for managing loan lifecycle and payments
interface IAccountableLoan is IAccountableStrategy {
/// @notice Event emitted when the loan is initialized
/// @param minCapacity The minimum loan capacity
/// @param maxCapacity The maximum loan capacity
/// @param interestRate The interest rate of the loan
/// @param lateInterestPenalty The late interest penalty
/// @param interestInterval The interest interval
/// @param duration The duration of the loan
event LoanTermsSet(
uint256 minCapacity,
uint256 maxCapacity,
uint256 interestRate,
uint256 lateInterestPenalty,
uint256 interestInterval,
uint256 duration
);
/// @notice Event emitted when the default is initiated
event LoanDefaultInitiated();
/// @notice Event emitted when a default is covered by safety collateral
/// @param safetyModule The address of the safety module
/// @param provider The address of the provider
/// @param collateral The amount of collateral covered
event DefaultCovered(address indexed safetyModule, address indexed provider, uint256 collateral);
/// @notice Event emitted when funds are borrowed
/// @param borrower The address of the borrower
/// @param assets The amount of funds borrowed
event Borrowed(address indexed borrower, uint256 assets);
/// @notice Event emitted when the loan is repaid
/// @param assets The amount of funds repaid
event LoanRepaid(uint256 assets);
/// @notice Event emitted when the loan is partially repaid
/// @param amount The amount of funds repaid to close loan
/// @param remainingInterest The remaining interest amount
event LoanPrepaid(uint256 amount, uint256 remainingInterest);
/// @notice Event emitted when interest is paid
/// @param borrower The address of the borrower
/// @param totalAmount The total amount paid
/// @param interestPenalty The interest penalty amount paid
/// @param performanceFee The performance fee amount paid
/// @param establishmentFee The establishment fee amount paid
/// @param paymentInterval The interval of the payment
event InterestPaid(
address indexed borrower,
uint256 totalAmount,
uint256 interestPenalty,
uint256 performanceFee,
uint256 establishmentFee,
uint256 paymentInterval
);
/// @notice Initialize a new loan with the given terms
/// @param terms The loan terms to initialize with
function setTerms(LoanTerms memory terms) external;
/// @notice Update an existing loan with new terms
/// @param terms The new loan terms to update to
function updateTerms(LoanTerms memory terms) external;
/// @notice Initialize loan default state
function defaultLoan() external;
/// @notice Cover the default of the loan
/// @param assets The amount of assets to cover
function coverDefault(uint256 assets) external;
/// @notice Borrow funds from the loan
/// @param assets The amount of funds to borrow
function borrow(uint256 assets) external;
/// @notice Repay the loan amount
/// @param assets The amount of funds to repay
function repay(uint256 assets) external;
/// @notice Make a partial loan repayment
function prepay() external;
/// @notice Make an interest payment
/// @param assets The interest amount to pay
function pay(uint256 assets) external;
/// @notice Get the period of time the loan has been delinquent
/// @return The period of time the loan has been delinquent
function timeDelinquent() external view returns (uint256);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.20;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
/// @notice Struct tracking vault state for a controller
struct VaultState {
/// @notice Maximum shares that can be minted
uint256 maxMint;
/// @notice Maximum assets that can be withdrawn
uint256 maxWithdraw;
/// @notice Total accumulated assets unclaimed
uint256 depositAssets;
/// @notice Total accumulated shares unclaimed
uint256 redeemShares;
/// @notice Share price floored for deposit
uint256 depositPrice;
/// @notice Share price ceiled for mint
uint256 mintPrice;
/// @notice Share price floored for redeem
uint256 redeemPrice;
/// @notice Share price ceiled for withdraw
uint256 withdrawPrice;
/// @notice Pending deposit amount
uint256 pendingDepositRequest;
/// @notice Pending redeem amount
uint256 pendingRedeemRequest;
}
interface IControllerOperator {
/// @notice Emitted when an operator's approval status is updated
/// @param controller The controller address that approved/revoked
/// @param operator The operator address being approved/revoked
/// @param approved The new approval status
event OperatorSet(address indexed controller, address indexed operator, bool approved);
/// @notice Sets or revokes operator approval for a caller
/// @param operator The address to set approval for
/// @param approved True to approve, false to revoke
/// @return bool True if successful
function setOperator(address operator, bool approved) external returns (bool);
/// @notice Checks if an address is an approved operator for a controller
/// @param controller The controller address to check
/// @param operator The operator address to check
/// @return status True if operator is approved for controller
function isOperator(address controller, address operator) external view returns (bool status);
}
interface IAsyncDeposit {
/// @notice Emitted when a deposit request is created
/// @param controller The controller address for the deposit
/// @param owner The owner address that will receive shares
/// @param requestId The unique ID for tracking the request
/// @param sender The address that initiated the request
/// @param assets The amount of assets being deposited
event DepositRequest(
address indexed controller, address indexed owner, uint256 indexed requestId, address sender, uint256 assets
);
/// @notice Requests a deposit of assets
/// @param assets Amount of assets to deposit
/// @param controller Address controlling the deposit
/// @param owner Address that will own the shares
/// @return uint256 Request ID for tracking the deposit
function requestDeposit(uint256 assets, address controller, address owner) external returns (uint256);
/// @notice Gets pending deposit amount for a request
/// @param requestId ID of the deposit request
/// @param controller Controller address for the request
/// @return uint256 Amount of assets pending deposit
function pendingDepositRequest(uint256 requestId, address controller) external view returns (uint256);
/// @notice Gets claimable deposit amount for a request
/// @param requestId ID of the deposit request
/// @param controller Controller address for the request
/// @return uint256 Amount of assets claimable
function claimableDepositRequest(uint256 requestId, address controller) external view returns (uint256);
}
interface IAsyncRedeem {
/// @notice Emitted when a redeem request is created
/// @param controller The controller address for the redemption
/// @param owner The owner of the shares being redeemed
/// @param requestId The unique ID for tracking the request
/// @param sender The address that initiated the request
/// @param assets The amount of assets being redeemed
event RedeemRequest(
address indexed controller, address indexed owner, uint256 indexed requestId, address sender, uint256 assets
);
/// @notice Requests redemption of shares
/// @param shares Amount of shares to redeem
/// @param controller Controller address for redemption
/// @param owner Owner of the shares
/// @return uint256 Request ID for tracking redemption
function requestRedeem(uint256 shares, address controller, address owner) external returns (uint256);
/// @notice Gets pending redeem amount for a request
/// @param requestId ID of the redeem request
/// @param controller Controller address for the request
/// @return uint256 Amount of shares pending redemption
function pendingRedeemRequest(uint256 requestId, address controller) external view returns (uint256);
/// @notice Gets claimable redeem amount for a request
/// @param requestId ID of the redeem request
/// @param controller Controller address for the request
/// @return uint256 Amount of shares claimable
function claimableRedeemRequest(uint256 requestId, address controller) external view returns (uint256);
}
interface IAsyncCancelDeposit {
/// @notice Emitted when a deposit request is cancelled
/// @param controller The controller address for the deposit
/// @param receiver The address that received the cancelled deposit
/// @param requestId The ID of the cancelled request
/// @param sender The address that initiated the cancellation
event CancelDepositRequest(address indexed controller, address indexed receiver, uint256 requestId, address sender);
/// @notice Cancels a pending deposit request
/// @param controller Controller address for the request
/// @param receiver The address that received the cancelled deposit
function cancelDepositRequest(address controller, address receiver) external;
}
interface IAsyncCancelRedeem {
/// @notice Emitted when a redeem request is cancelled
/// @param controller The controller address for the redemption
/// @param receiver The address that received the cancelled redeem
/// @param requestId The ID of the cancelled request
/// @param sender The address that initiated the cancellation
event CancelRedeemRequest(address indexed controller, address indexed receiver, uint256 requestId, address sender);
/// @notice Cancels a pending redeem request
/// @param controller Controller address for the request
/// @param receiver The address that received the cancelled redeem
function cancelRedeemRequest(address controller, address receiver) external;
}
interface IAccountableVault is IERC20, IERC20Metadata, IERC4626, IControllerOperator {
/// @notice Emitted when assets are locked in the vault
/// @param caller The address that locked the assets
/// @param assets The amount of assets locked
event LockAssets(address indexed caller, uint256 assets);
/// @notice Emitted when locked assets are released
/// @param caller The address that released the assets
/// @param assets The amount of assets released
event ReleaseAssets(address indexed caller, uint256 assets);
/// @notice Emitted when shares transferability is changed
/// @param oldStatus The old transferability status
/// @param newStatus The new transferability status
event SharesTransferableSet(bool oldStatus, bool newStatus);
/// @notice Deposits assets and mints shares to receiver
/// @dev Added for ERC7540 compatibility
/// @param assets Amount of assets to deposit
/// @param receiver Address receiving the shares
/// @param controller Controller address for the deposit
/// @return uint256 Amount of shares minted
function deposit(uint256 assets, address receiver, address controller) external returns (uint256);
/// @notice Mints exact amount of shares by depositing assets
/// @dev Added for ERC7540 compatibility
/// @param shares Amount of shares to mint
/// @param receiver Address receiving the shares
/// @param controller Controller address for the mint
/// @return uint256 Amount of assets deposited
function mint(uint256 shares, address receiver, address controller) external returns (uint256);
/// @notice Locks assets in the vault
/// @param assets Amount of assets to lock
function lockAssets(uint256 assets, address sender) external;
/// @notice Releases previously locked assets
/// @param assets Amount of assets to release
function releaseAssets(uint256 assets, address receiver) external;
/// @notice Issues shares to a receiver
/// @param shares Amount of shares to issue
/// @param receiver Address to receive the shares
function mintShares(uint256 shares, address receiver) external;
/// @notice Repossesses shares from a sender
/// @param shares Amount of shares to repossess
/// @param sender Address to repossess the shares from
function burnShares(uint256 shares, address sender) external;
/// @notice Forces a transfer of shares from one address to another
/// @param from The address to transfer shares from
/// @param to The address to transfer shares to
/// @param shares The amount of shares to transfer
function forceTransferShares(address from, address to, uint256 shares) external;
/// @notice Sets the transferability of shares
/// @param transferable True to set shares transferable, false to set them non-transferable
function setSharesTransferable(bool transferable) external;
/// @notice Checks if shares can be transferred
/// @return bool True if shares are transferable
function transferableShares() external view returns (bool);
/// @notice Current asset share ratio
/// @return uint256 Asset share ratio
function assetShareRatio() external view returns (uint256);
/// @notice Gets the current share price
/// @return uint256 Price per share in assets
function sharePrice() external view returns (uint256);
/// @notice The share token address
/// @return address Share token address
function share() external view returns (address);
/// @notice Gets the state of the vault
/// @param controller The controller address for the vault
/// @return state The state of the vault given the controller
function getState(address controller) external view returns (VaultState memory state);
}
interface IAccountableAsyncRedeemVault is IAccountableVault, IAsyncRedeem, IAsyncCancelRedeem, IERC165 {
/// @notice Emitted when a redeem becomes claimable
/// @param controller The controller address for the redemption
/// @param requestId The ID of the redeem request
/// @param assets The amount of assets to be received
/// @param shares The amount of shares redeemed
event RedeemClaimable(address indexed controller, uint256 indexed requestId, uint256 assets, uint256 shares);
}
interface IAccountableAsyncVault is
IAccountableVault,
IAsyncDeposit,
IAsyncRedeem,
IAsyncCancelDeposit,
IAsyncCancelRedeem,
IERC165
{
/// @notice Emitted when a deposit becomes claimable
/// @param controller The controller address for the deposit
/// @param requestId The ID of the deposit request
/// @param assets The amount of assets deposited
/// @param shares The amount of shares to be minted
event DepositClaimable(address indexed controller, uint256 indexed requestId, uint256 assets, uint256 shares);
/// @notice Emitted when a redeem becomes claimable
/// @param controller The controller address for the redemption
/// @param requestId The ID of the redeem request
/// @param assets The amount of assets to be received
/// @param shares The amount of shares redeemed
event RedeemClaimable(address indexed controller, uint256 indexed requestId, uint256 assets, uint256 shares);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.20;
/// @notice Struct tracking a withdrawal request
struct WithdrawalRequest {
/// @notice The number of shares requested
uint256 shares;
/// @notice The controller of the request
address controller;
}
/// @notice Struct tracking the withdrawal queue
struct WithdrawalQueue {
/// @notice The next request ID to be processed
uint128 nextRequestId;
/// @notice The last request ID to be processed
uint128 lastRequestId;
/// @notice The mapping of request IDs to withdrawal requests
mapping(uint128 requestId => WithdrawalRequest request) requests;
}
/// @notice Interface for the withdrawal queue
interface IAccountableWithdrawalQueue {
/// @notice Fulfill a redeem request
/// @param controller The controller of the request
/// @param shares The number of shares to fulfill
function fulfillRedeemRequest(address controller, uint256 shares) external;
/// @notice Process up to `maxShares` shares
/// @param maxShares The maximum number of shares to process
/// @return assetsUsed The number of assets used to process the shares
function processUpToShares(uint256 maxShares) external returns (uint256 assetsUsed);
/// @notice Process up to `maxRequestId` request
/// @param maxRequestId The last request ID to process
/// @return processedShares The number of shares that were processed
/// @return assetsUsed The number of assets used to process the shares
function processUpToRequestId(uint256 maxRequestId)
external
returns (uint256 processedShares, uint256 assetsUsed);
/// @notice Preview required shares that can be processed with `maxAssets`
/// @param maxAssets The maximum number of assets to be matched with `maxAssets`
/// @return processedShares The number of shares that can be processed with the assets
/// @return assetsUsed The number of assets used to process the shares
function previewRequiredShares(uint256 maxAssets)
external
view
returns (uint256 processedShares, uint256 assetsUsed);
/// @notice Preview the last request ID that can be processed with `maxAssets`
/// @param maxAssets The maximum number of assets to be matched with `maxAssets`
/// @return maxRequestId The last request ID that can be processed with the assets
/// @return assetsUsed The number of assets used to process the shares
function previewMaxRequestId(uint256 maxAssets) external view returns (uint256 maxRequestId, uint256 assetsUsed);
/// @notice Get the total number of shares queued
/// @return totalQueuedShares The total number of shares queued
function totalQueuedShares() external view returns (uint256 totalQueuedShares);
/// @notice Get the reserved liquidity
/// @return reservedLiquidity The reserved liquidity
function reservedLiquidity() external view returns (uint256 reservedLiquidity);
/// @notice Get the withdrawal queue indices
/// @return nextRequestId The next request ID to be processed
/// @return lastRequestId The last request ID to be processed
function queue() external view returns (uint128 nextRequestId, uint128 lastRequestId);
/// @notice Get the withdrawal request for a controller
/// @param controller The controller of the request
/// @return request The withdrawal request
function withdrawalRequest(address controller) external view returns (WithdrawalRequest memory request);
/// @notice Get the withdrawal requests
/// @param start The start index of the queue
/// @param end The end index of the queue
/// @return requests The withdrawal requests
function withdrawalRequests(uint128 start, uint128 end)
external
view
returns (WithdrawalRequest[] memory requests);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.20;
import "../constants/Errors.sol";
import {IStrategyVaultHooks} from "../interfaces/IAccountableStrategy.sol";
import {IAuthorizable, IWhitelistable, PermissionLevel} from "../interfaces/IAccess.sol";
import {IAccountableVault, IControllerOperator, VaultState} from "../interfaces/IAccountableAsyncVault.sol";
import {AccessBase} from "../access/AccessBase.sol";
import {Authorizable} from "../access/Authorizable.sol";
import {Whitelistable} from "../access/Whitelistable.sol";
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
/// @title AccountableVault
/// @notice Base contract for Accountable async vaults
/// @custom:security-contact [email protected]
abstract contract AccountableVault is IAccountableVault, ERC20, AccessBase {
using Math for uint256;
using SafeERC20 for IERC20;
/// @notice Underlying asset
IERC20 internal immutable _asset;
/// @notice Decimals of the underlying asset
uint8 internal immutable _underlyingDecimals;
/// @notice Total assets in the vault
uint256 internal _totalAssets;
/// @notice Mapping of vault states by controller
mapping(address controller => VaultState state) internal _vaultStates;
/// @notice Minimum amount in wei to prevent dust attacks
uint256 public constant MIN_AMOUNT_WEI = 10_000;
/// @notice The loan manager contract that handles deposit/redeem requests
IStrategyVaultHooks public strategy;
/// @notice Precision for share calculations
uint256 public precision;
/// @notice Mapping of owner addresses to their approved operators
mapping(address => mapping(address => bool)) public isOperator;
/// @notice Whether the vault is transferable
bool public transferableShares;
/// @notice Ensures only the loan manager can call certain functions
modifier onlyStrategy() {
if (msg.sender != address(strategy)) {
revert Unauthorized();
}
_;
}
/// @notice Ensures only authorized accounts can call certain functions
modifier onlyAuth(address receiverOwner, address controller) {
if (receiverOwner == controller) {
if (!_isVerified(controller, msg.data)) revert Unauthorized();
} else {
address[] memory accounts = new address[](2);
accounts[0] = receiverOwner;
accounts[1] = controller;
if (!_areVerified(accounts, msg.data)) revert Unauthorized();
}
_;
}
constructor(IERC20 asset_, PermissionLevel permissionLevel_) AccessBase(permissionLevel_) {
(bool success, uint8 assetDecimals) = _tryGetAssetDecimals(asset_);
_underlyingDecimals = success ? assetDecimals : 18;
_asset = asset_;
}
/// @dev Try to get the decimals of the underlying asset
function _tryGetAssetDecimals(IERC20 asset_) private view returns (bool ok, uint8 assetDecimals) {
(bool success, bytes memory encodedDecimals) =
address(asset_).staticcall(abi.encodeCall(IERC20Metadata.decimals, ()));
if (success && encodedDecimals.length >= 32) {
uint256 returnedDecimals = abi.decode(encodedDecimals, (uint256));
if (returnedDecimals <= type(uint8).max) {
return (true, uint8(returnedDecimals));
}
}
return (false, 0);
}
/// @inheritdoc IControllerOperator
function setOperator(address operator, bool approved) public returns (bool) {
if (msg.sender == operator) {
revert InvalidOperator();
}
isOperator[msg.sender][operator] = approved;
emit OperatorSet(msg.sender, operator, approved);
return true;
}
/// @inheritdoc IERC20Metadata
function decimals() public view virtual override(IERC20Metadata, ERC20) returns (uint8) {
return _underlyingDecimals;
}
/// @inheritdoc IERC4626
function asset() public view virtual returns (address) {
return address(_asset);
}
/// @inheritdoc IERC4626
function totalAssets() public view returns (uint256) {
return _totalAssets;
}
/// @inheritdoc IERC20
function transfer(address to, uint256 amount) public virtual override(ERC20, IERC20) returns (bool) {
_checkTransfer(amount, msg.sender, to);
strategy.onTransfer(address(this), msg.sender, to, amount);
return super.transfer(to, amount);
}
/// @inheritdoc IERC20
function transferFrom(address from, address to, uint256 amount)
public
virtual
override(ERC20, IERC20)
returns (bool)
{
_checkTransfer(amount, from, to);
strategy.onTransfer(address(this), from, to, amount);
return super.transferFrom(from, to, amount);
}
/// @dev Checks transfer restrictions before executing the underlying transfer
function _checkTransfer(uint256, address, address to) private {
if (!transferableShares) revert SharesNotTransferable();
if (!_isVerified(to, msg.data)) revert Unauthorized();
}
/// @inheritdoc IERC4626
function convertToShares(uint256 assets) public view returns (uint256) {
return _convertToShares(assets, sharePrice(), Math.Rounding.Floor);
}
/// @inheritdoc IERC4626
function convertToAssets(uint256 shares) public view returns (uint256) {
return _convertToAssets(shares, sharePrice(), Math.Rounding.Floor);
}
/// @inheritdoc IAccountableVault
function assetShareRatio() public view returns (uint256) {
uint256 shares = totalSupply();
uint256 reserved = IStrategyVaultHooks(strategy).accruedAssets(address(this));
return shares == 0 ? precision : (totalAssets() - reserved).mulDiv(precision, shares, Math.Rounding.Floor);
}
/// @dev Computes the assets based on shares and price
function _convertToAssets(uint256 shares, uint256 price, Math.Rounding rounding)
internal
view
virtual
returns (uint256 assets)
{
assets = shares.mulDiv(price, precision, rounding);
}
/// @dev Computes the shares based on assets and price
function _convertToShares(uint256 assets, uint256 price, Math.Rounding rounding)
internal
view
virtual
returns (uint256 shares)
{
shares = assets.mulDiv(precision, price, rounding);
}
/// @inheritdoc IAccountableVault
function sharePrice() public view returns (uint256) {
return strategy.sharePrice(address(this));
}
/// @inheritdoc IAccountableVault
function share() public view returns (address) {
return address(this);
}
/// @inheritdoc IAccountableVault
function getState(address controller) public view returns (VaultState memory) {
return _vaultStates[controller];
}
/// @inheritdoc IAccountableVault
function lockAssets(uint256 assets, address sender) public onlyStrategy {
_deposit(sender, assets);
emit LockAssets(sender, assets);
}
/// @inheritdoc IAccountableVault
function releaseAssets(uint256 assets, address receiver) public onlyStrategy {
_withdraw(receiver, assets);
emit ReleaseAssets(receiver, assets);
}
/// @inheritdoc IAccountableVault
function mintShares(uint256 shares, address receiver) public onlyStrategy {
_mint(receiver, shares);
}
/// @inheritdoc IAccountableVault
function burnShares(uint256 shares, address sender) public onlyStrategy {
_burn(sender, shares);
}
/// @inheritdoc IAccountableVault
function forceTransferShares(address from, address to, uint256 shares) public onlyStrategy {
strategy.onTransfer(address(this), from, to, shares);
_transfer(from, to, shares);
}
/// @inheritdoc IAccountableVault
function setSharesTransferable(bool sharesTransferable_) public onlyStrategy {
bool oldStatus = transferableShares;
transferableShares = sharesTransferable_;
emit SharesTransferableSet(oldStatus, sharesTransferable_);
}
/// @inheritdoc IAuthorizable
function setSigner(address signer_) public override(IAuthorizable, Authorizable) onlyStrategy {
if (permissionLevel != PermissionLevel.KYC) revert PermissionLevelMismatch();
super.setSigner(signer_);
}
/// @inheritdoc IWhitelistable
function setAllowed(address[] calldata accounts, bool[] calldata statuses)
public
override(IWhitelistable, Whitelistable)
onlyStrategy
{
if (permissionLevel != PermissionLevel.Whitelist) revert PermissionLevelMismatch();
super.setAllowed(accounts, statuses);
}
/// @dev Deposit assets into the vault and increment total assets
function _deposit(address caller, uint256 assets) internal virtual {
_totalAssets += assets;
_asset.safeTransferFrom(caller, address(this), assets);
}
/// @dev Withdraw assets from the vault and decrement total assets
function _withdraw(address receiver, uint256 assets) internal virtual {
_totalAssets -= assets;
_asset.safeTransfer(receiver, assets);
}
/// @dev Checks if the caller is an approved operator for the owner
/// @param owner The owner address to check against
function _checkOperator(address owner) internal view {
if (owner != msg.sender && !isOperator[owner][msg.sender]) {
revert InvalidOperator();
}
}
/// @dev Checks if the caller is an approved operator for the controller
/// @param controller The controller address to check against
function _checkController(address controller) internal view {
if (controller != msg.sender && !isOperator[controller][msg.sender]) {
revert InvalidController();
}
}
/// @dev Checks if the owner has sufficient shares
/// @param owner The owner address to check
/// @param shares The amount of shares to check for
function _checkShares(address owner, uint256 shares) internal view {
if (balanceOf(owner) < shares || shares == 0) {
revert InsufficientShares();
}
}
/// @dev Checks if the amount is greater than the minimum amount
function _checkMinAmount(uint256 amount) internal pure {
if (amount < MIN_AMOUNT_WEI) revert InsufficientAmount();
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.20;
import {InsufficientShares, InvalidRange, OutOfBounds, NoQueueRequest} from "../../constants/Errors.sol";
import {
IAccountableWithdrawalQueue,
WithdrawalRequest,
WithdrawalQueue
} from "../../interfaces/IAccountableWithdrawalQueue.sol";
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
/// @title AccountableWithdrawalQueue
/// @notice A contract that manages the withdrawal queue
/// @custom:security-contact [email protected]
abstract contract AccountableWithdrawalQueue is IAccountableWithdrawalQueue {
using Math for uint256;
/// @notice Price precision
uint256 internal _precision;
/// @notice Withdrawal queue
WithdrawalQueue internal _queue;
/// @notice Mapping of controller to request ID
mapping(address controller => uint128 requestId) internal _requestIds;
/// @inheritdoc IAccountableWithdrawalQueue
uint256 public totalQueuedShares;
/// @inheritdoc IAccountableWithdrawalQueue
/// @dev The reserved liquidity is the amount of assets that are reserved for withdrawals
/// @dev Has to be excluded from total liquidity calculations to avoid double counting
uint256 public reservedLiquidity;
constructor(uint256 precision_) {
_precision = precision_;
_queue.nextRequestId = 1;
}
/// @inheritdoc IAccountableWithdrawalQueue
function queue() external view returns (uint128 nextRequestId, uint128 lastRequestId) {
(nextRequestId, lastRequestId) = (_queue.nextRequestId, _queue.lastRequestId);
}
/// @inheritdoc IAccountableWithdrawalQueue
function withdrawalRequest(address controller) external view returns (WithdrawalRequest memory request) {
request = _queue.requests[_requestIds[controller]];
}
/// @inheritdoc IAccountableWithdrawalQueue
function withdrawalRequests(uint128 start, uint128 end)
external
view
returns (WithdrawalRequest[] memory requests)
{
if (start == 0 || start > end) revert InvalidRange();
if (end > _queue.lastRequestId) revert OutOfBounds();
uint128 len = end - start + 1;
requests = new WithdrawalRequest[](len);
for (uint128 i = 0; i < len;) {
requests[i] = _queue.requests[start + i];
unchecked {
++i;
}
}
}
/// @dev Pushes a new withdrawal request to the queue
function _push(address controller, uint256 shares) internal returns (uint128 requestId) {
uint128 requestId_ = _requestIds[controller];
if (requestId_ == 0) {
requestId = ++_queue.lastRequestId;
_requestIds[controller] = requestId;
_queue.requests[requestId] = WithdrawalRequest(shares, controller);
} else {
requestId = requestId_;
_queue.requests[requestId_].shares += shares;
}
totalQueuedShares += shares;
}
/// @dev Reduces or removes the shares of a withdrawal request
function _reduce(address controller, uint256 shares) internal returns (uint256 remainingShares) {
uint128 requestId = _requestIds[controller];
if (requestId == 0) revert NoQueueRequest();
uint256 currentShares = _queue.requests[requestId].shares;
if (shares > currentShares || currentShares == 0) revert InsufficientShares();
remainingShares = currentShares - shares;
totalQueuedShares -= shares;
if (remainingShares == 0) {
_delete(controller, requestId);
} else {
_queue.requests[requestId].shares = remainingShares;
}
}
/// @dev Deletes a withdrawal request and its controller from the queue
function _delete(address controller, uint128 requestId) private {
delete _queue.requests[requestId];
delete _requestIds[controller];
}
/// @dev Processes up to the given number of shares
function _processUpToShares(uint256 maxShares, uint256 liquidity, uint256 currentPrice)
internal
returns (uint256 assetsUsed)
{
if (maxShares == 0 || totalQueuedShares == 0) return 0;
uint256 precision_ = _precision;
uint128 nextRequestId = _queue.nextRequestId;
uint128 lastRequestId = _queue.lastRequestId;
while (maxShares > 0 && nextRequestId <= lastRequestId) {
WithdrawalRequest memory request_ = _queue.requests[nextRequestId];
(uint256 shares_, uint256 assets_, bool processed_) =
_processRequest(request_, liquidity, maxShares, currentPrice, precision_);
if (shares_ == 0) {
if (processed_) {
++nextRequestId;
continue;
}
break;
}
_fulfillRedeemRequest(nextRequestId, request_.controller, shares_, currentPrice);
assetsUsed += assets_;
liquidity -= assets_;
maxShares -= shares_;
if (!processed_) break;
++nextRequestId;
}
_queue.nextRequestId = nextRequestId;
}
/// @dev Processes requests up to the given request ID
function _processUpToRequestId(uint256 maxRequestId, uint256 liquidity, uint256 currentPrice)
internal
returns (uint256 processedShares, uint256 assetsUsed)
{
uint256 maxShares_ = totalQueuedShares;
if (maxRequestId == 0 || maxShares_ == 0) return (0, 0);
uint256 precision_ = _precision;
uint128 nextRequestId = _queue.nextRequestId;
uint128 lastRequestId = _queue.lastRequestId;
uint256 cappedMaxRequestId = maxRequestId > lastRequestId ? lastRequestId : maxRequestId;
while (nextRequestId <= cappedMaxRequestId) {
WithdrawalRequest memory request_ = _queue.requests[nextRequestId];
(uint256 shares_, uint256 assets_, bool processed_) =
_processRequest(request_, liquidity, maxShares_, currentPrice, precision_);
if (shares_ == 0) {
if (processed_) {
++nextRequestId;
continue;
}
break;
}
_fulfillRedeemRequest(nextRequestId, request_.controller, shares_, currentPrice);
processedShares += shares_;
assetsUsed += assets_;
liquidity -= assets_;
if (!processed_) break;
++nextRequestId;
}
_queue.nextRequestId = nextRequestId;
}
/// @dev Processes a withdrawal request updating all relevant state
function _processRequest(
WithdrawalRequest memory request,
uint256 liquidity,
uint256 maxShares,
uint256 currentPrice,
uint256 precision
) internal returns (uint256 processedShares, uint256 assetsUsed, bool processed) {
if (request.controller == address(0)) return (0, 0, true);
uint256 liquidShares = liquidity.mulDiv(precision, currentPrice);
uint256 sharesToProcess = _min3(request.shares, liquidShares, maxShares);
if (sharesToProcess == 0) return (0, 0, false);
processedShares = sharesToProcess;
assetsUsed = sharesToProcess.mulDiv(currentPrice, precision);
processed = (sharesToProcess == request.shares);
_reduce(request.controller, processedShares);
}
/// @dev Returns the number of shares that can be processed with the given assets
function _previewRequiredShares(uint256 maxAssets, uint256 currentPrice)
internal
view
returns (uint256 processedShares, uint256 assetsUsed)
{
uint256 precision_ = _precision;
uint128 nextRequestId = _queue.nextRequestId;
uint128 lastRequestId = _queue.lastRequestId;
uint256 remainingShares = totalQueuedShares;
while (maxAssets > 0 && remainingShares > 0 && nextRequestId <= lastRequestId) {
WithdrawalRequest memory request_ = _queue.requests[nextRequestId];
uint256 requestAssets = request_.shares.mulDiv(currentPrice, precision_);
if (requestAssets > maxAssets) {
uint256 maxAvailable = Math.min(maxAssets, requestAssets);
uint256 maxShares = maxAvailable.mulDiv(precision_, currentPrice);
if (maxShares > 0) {
processedShares += maxShares;
assetsUsed += maxShares.mulDiv(currentPrice, precision_);
}
break;
}
processedShares += request_.shares;
remainingShares -= request_.shares;
assetsUsed += requestAssets;
maxAssets -= requestAssets;
++nextRequestId;
}
}
/// @dev Returns the maximum request ID that can be processed with the given assets
function _previewMaxRequestId(uint256 maxAssets, uint256 currentPrice)
internal
view
returns (uint256 maxRequestId, uint256 assetsUsed)
{
uint256 precision_ = _precision;
uint128 nextRequestId_ = _queue.nextRequestId;
uint128 lastRequestId_ = _queue.lastRequestId;
uint256 remainingShares = totalQueuedShares;
while (maxAssets > 0 && remainingShares > 0 && nextRequestId_ <= lastRequestId_) {
WithdrawalRequest memory request_ = _queue.requests[nextRequestId_];
uint256 requestAssets = request_.shares.mulDiv(currentPrice, precision_);
if (requestAssets > maxAssets) {
uint256 maxAvailable = Math.min(maxAssets, requestAssets);
uint256 maxShares = maxAvailable.mulDiv(precision_, currentPrice);
if (maxShares > 0) {
maxRequestId = nextRequestId_;
assetsUsed += maxShares.mulDiv(currentPrice, precision_);
}
break;
}
assetsUsed += requestAssets;
maxAssets -= requestAssets;
remainingShares -= request_.shares;
maxRequestId = nextRequestId_++;
}
}
/// @dev Updates the reserved liquidity, to be triggered on withdraw/redeem
function _updateReservedLiquidity(uint256 assets) internal {
reservedLiquidity = assets < reservedLiquidity ? reservedLiquidity - assets : 0;
}
/// @dev Returns the minimum of three values
function _min3(uint256 a, uint256 b, uint256 c) internal pure returns (uint256 result) {
assembly {
result := a
if lt(b, result) { result := b }
if lt(c, result) { result := c }
}
}
/// @dev Hook function to trigger state updates when a request is processed
function _fulfillRedeemRequest(uint128 requestId, address controller, uint256 shares, uint256 price)
internal
virtual;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
/**
* @dev Muldiv operation overflow.
*/
error MathOverflowedMulDiv();
enum Rounding {
Floor, // Toward negative infinity
Ceil, // Toward positive infinity
Trunc, // Toward zero
Expand // Away from zero
}
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an overflow flag.
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds towards infinity instead
* of rounding towards zero.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
if (b == 0) {
// Guarantee the same behavior as in a regular Solidity division.
return a / b;
}
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
* denominator == 0.
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
* Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0 = x * y; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
if (denominator <= prod1) {
revert MathOverflowedMulDiv();
}
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator.
// Always >= 1. See https://cs.stackexchange.com/q/138556/92363.
uint256 twos = denominator & (0 - denominator);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
// works in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
* towards zero.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256 of a positive value rounded towards zero.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
}
}
/**
* @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
*/
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
return uint8(rounding) % 2 == 1;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
import {IERC20Metadata} from "./extensions/IERC20Metadata.sol";
import {Context} from "../../utils/Context.sol";
import {IERC20Errors} from "../../interfaces/draft-IERC6093.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
*
* TIP: For a detailed writeup see our guide
* https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* The default value of {decimals} is 18. To change this, you should override
* this function so it returns a different value.
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC20
* applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*/
abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
mapping(address account => uint256) private _balances;
mapping(address account => mapping(address spender => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* All two of these values are immutable: they can only be set once during
* construction.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the default value returned by this function, unless
* it's overridden.
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual returns (uint8) {
return 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `value`.
*/
function transfer(address to, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_transfer(owner, to, value);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `value` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, value);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `value`.
* - the caller must have allowance for ``from``'s tokens of at least
* `value`.
*/
function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, value);
_transfer(from, to, value);
return true;
}
/**
* @dev Moves a `value` amount of tokens from `from` to `to`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _transfer(address from, address to, uint256 value) internal {
if (from == address(0)) {
revert ERC20InvalidSender(address(0));
}
if (to == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(from, to, value);
}
/**
* @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
* (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
* this function.
*
* Emits a {Transfer} event.
*/
function _update(address from, address to, uint256 value) internal virtual {
if (from == address(0)) {
// Overflow check required: The rest of the code assumes that totalSupply never overflows
_totalSupply += value;
} else {
uint256 fromBalance = _balances[from];
if (fromBalance < value) {
revert ERC20InsufficientBalance(from, fromBalance, value);
}
unchecked {
// Overflow not possible: value <= fromBalance <= totalSupply.
_balances[from] = fromBalance - value;
}
}
if (to == address(0)) {
unchecked {
// Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
_totalSupply -= value;
}
} else {
unchecked {
// Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
_balances[to] += value;
}
}
emit Transfer(from, to, value);
}
/**
* @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).
* Relies on the `_update` mechanism
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _mint(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(address(0), account, value);
}
/**
* @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.
* Relies on the `_update` mechanism.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead
*/
function _burn(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidSender(address(0));
}
_update(account, address(0), value);
}
/**
* @dev Sets `value` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*
* Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
*/
function _approve(address owner, address spender, uint256 value) internal {
_approve(owner, spender, value, true);
}
/**
* @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.
*
* By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by
* `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any
* `Approval` event during `transferFrom` operations.
*
* Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to
* true using the following override:
* ```
* function _approve(address owner, address spender, uint256 value, bool) internal virtual override {
* super._approve(owner, spender, value, true);
* }
* ```
*
* Requirements are the same as {_approve}.
*/
function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
if (owner == address(0)) {
revert ERC20InvalidApprover(address(0));
}
if (spender == address(0)) {
revert ERC20InvalidSpender(address(0));
}
_allowances[owner][spender] = value;
if (emitEvent) {
emit Approval(owner, spender, value);
}
}
/**
* @dev Updates `owner` s allowance for `spender` based on spent `value`.
*
* Does not update the allowance value in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Does not emit an {Approval} event.
*/
function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
if (currentAllowance < value) {
revert ERC20InsufficientAllowance(spender, currentAllowance, value);
}
unchecked {
_approve(owner, spender, currentAllowance - value, false);
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC4626.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../token/ERC20/IERC20.sol";
import {IERC20Metadata} from "../token/ERC20/extensions/IERC20Metadata.sol";
/**
* @dev Interface of the ERC4626 "Tokenized Vault Standard", as defined in
* https://eips.ethereum.org/EIPS/eip-4626[ERC-4626].
*/
interface IERC4626 is IERC20, IERC20Metadata {
event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);
event Withdraw(
address indexed sender,
address indexed receiver,
address indexed owner,
uint256 assets,
uint256 shares
);
/**
* @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.
*
* - MUST be an ERC-20 token contract.
* - MUST NOT revert.
*/
function asset() external view returns (address assetTokenAddress);
/**
* @dev Returns the total amount of the underlying asset that is “managed” by Vault.
*
* - SHOULD include any compounding that occurs from yield.
* - MUST be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT revert.
*/
function totalAssets() external view returns (uint256 totalManagedAssets);
/**
* @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal
* scenario where all the conditions are met.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToShares(uint256 assets) external view returns (uint256 shares);
/**
* @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal
* scenario where all the conditions are met.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToAssets(uint256 shares) external view returns (uint256 assets);
/**
* @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,
* through a deposit call.
*
* - MUST return a limited value if receiver is subject to some deposit limit.
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.
* - MUST NOT revert.
*/
function maxDeposit(address receiver) external view returns (uint256 maxAssets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit
* call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called
* in the same transaction.
* - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the
* deposit would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewDeposit(uint256 assets) external view returns (uint256 shares);
/**
* @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.
*
* - MUST emit the Deposit event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* deposit execution, and are accounted for during deposit.
* - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not
* approving enough underlying tokens to the Vault contract, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
*/
function deposit(uint256 assets, address receiver) external returns (uint256 shares);
/**
* @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.
* - MUST return a limited value if receiver is subject to some mint limit.
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.
* - MUST NOT revert.
*/
function maxMint(address receiver) external view returns (uint256 maxShares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call
* in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the
* same transaction.
* - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint
* would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by minting.
*/
function previewMint(uint256 shares) external view returns (uint256 assets);
/**
* @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.
*
* - MUST emit the Deposit event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint
* execution, and are accounted for during mint.
* - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not
* approving enough underlying tokens to the Vault contract, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
*/
function mint(uint256 shares, address receiver) external returns (uint256 assets);
/**
* @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the
* Vault, through a withdraw call.
*
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
* - MUST NOT revert.
*/
function maxWithdraw(address owner) external view returns (uint256 maxAssets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw
* call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if
* called
* in the same transaction.
* - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though
* the withdrawal would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewWithdraw(uint256 assets) external view returns (uint256 shares);
/**
* @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.
*
* - MUST emit the Withdraw event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* withdraw execution, and are accounted for during withdraw.
* - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner
* not having enough shares, etc).
*
* Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
* Those methods should be performed separately.
*/
function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);
/**
* @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,
* through a redeem call.
*
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
* - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.
* - MUST NOT revert.
*/
function maxRedeem(address owner) external view returns (uint256 maxShares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call
* in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the
* same transaction.
* - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the
* redemption would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by redeeming.
*/
function previewRedeem(uint256 shares) external view returns (uint256 assets);
/**
* @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.
*
* - MUST emit the Withdraw event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* redeem execution, and are accounted for during redeem.
* - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner
* not having enough shares, etc).
*
* NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
* Those methods should be performed separately.
*/
function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*/
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: GPL-2.0-or-later
pragma solidity ^0.8.20;
import {IAccess, PermissionLevel} from "../interfaces/IAccess.sol";
import {Whitelistable} from "./Whitelistable.sol";
import {Authorizable} from "./Authorizable.sol";
/// @title AccessBase - A base contract for access control extending Whitelistable and Authorizable
/// @notice This contract is used to gate access to callable/interactable contracts
/// @dev See IAccess for detailed interface documentation
/// @custom:security-contact [email protected]
abstract contract AccessBase is IAccess, Whitelistable, Authorizable {
/// @inheritdoc IAccess
PermissionLevel public permissionLevel;
/// @notice Constructor
/// @param permissionLevel_ The permission level for the contract
constructor(PermissionLevel permissionLevel_) {
permissionLevel = permissionLevel_;
}
function _isVerified(address account, bytes calldata msgData) internal returns (bool) {
PermissionLevel _permission = permissionLevel;
if (_permission == PermissionLevel.KYC) return _verify(account, msgData);
if (_permission == PermissionLevel.Whitelist) return allowed[account];
return true;
}
function _areVerified(address[] memory accounts, bytes calldata msgData) internal returns (bool) {
PermissionLevel _permission = permissionLevel;
if (_permission == PermissionLevel.KYC) return _verifyMany(accounts, msgData);
if (_permission == PermissionLevel.Whitelist) return allowedMany(accounts);
return true;
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.20;
import "../constants/Errors.sol";
import {IAuthorizable, TxAuthData, VerifyManyData} from "../interfaces/IAccess.sol";
import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol";
import {SignatureChecker} from "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol";
/// @title Authorizable - A signature based transaction authorization mechanism
/// @notice This contract is used to authorize transactions using a signature
/// @dev See IAuthorizable for detailed interface documentation
/// @custom:security-contact [email protected]
abstract contract Authorizable is IAuthorizable, EIP712 {
/// @notice EIP-712 typehash for TxAuthData
bytes32 private constant _TXAUTH_TYPEHASH = keccak256(
"TxAuthData(bytes functionCallData,address contractAddress,address account,uint256 nonce,uint256 blockExpiration)"
);
constructor() EIP712("Authorizable", "1") {}
/// @notice These are used to decompose msgData
uint256 private constant _BYTES_32_LENGTH = 32;
/// @notice This is the length for the expected signature
uint256 private constant _SIGNATURE_LENGTH = 65;
/// @notice The offset for the extra data in the calldata
uint256 private constant _EXTRA_DATA_LENGTH = _SIGNATURE_LENGTH + _BYTES_32_LENGTH;
/// @notice The address of the off-chain signer
address public signer;
/// @notice Mapping to track the nonces to prevent replay attacks
/// @dev Maps a user address to their current nonce
mapping(address user => uint256 nonce) public nonces;
/// @inheritdoc IAuthorizable
function setSigner(address signer_) public virtual {
if (signer_ == address(0)) revert ZeroAddress();
_setSigner(signer_);
}
/// @inheritdoc IAuthorizable
function getMessageHash(TxAuthData calldata txAuthData) public view returns (bytes32) {
return _getTypedDataHash(txAuthData);
}
/// @dev Verify transaction authentication data
/// @param account The account that is being verified
/// @param msgData The message data of the transaction
/// @return True if the transaction authentication data is valid, reverts otherwise
function _verify(address account, bytes calldata msgData) internal returns (bool) {
address signer_ = signer;
if (account == address(0)) revert ZeroAddress();
if (signer_ == address(0)) revert InvalidSigner();
if (msgData.length < _EXTRA_DATA_LENGTH) revert InvalidMsgDataLength();
bytes calldata argsWithSelector = msgData[:msgData.length - _EXTRA_DATA_LENGTH];
uint256 blockExpiration =
uint256(bytes32(msgData[msgData.length - _EXTRA_DATA_LENGTH:msgData.length - _SIGNATURE_LENGTH]));
bytes calldata signature = msgData[msgData.length - _SIGNATURE_LENGTH:];
if (block.number >= blockExpiration) revert InvalidBlockExpiration();
uint256 nonce = nonces[account]++;
TxAuthData memory txAuthData = TxAuthData({
functionCallData: argsWithSelector,
contractAddress: address(this),
account: account,
nonce: nonce,
blockExpiration: blockExpiration
});
bytes32 digest = _getTypedDataHash(txAuthData);
emit TxAuthDataVerified(block.chainid, nonce, blockExpiration, address(this), account, argsWithSelector);
if (!SignatureChecker.isValidSignatureNow(signer_, digest, signature)) revert InvalidSignature();
return true;
}
/// @dev Verify transaction authentication data for multiple accounts
/// @param accounts Array of accounts that are being verified in the transaction
/// @param msgData [functionCallData][blockExpiration][signature1][signature2]...[signatureN][length]
/// @return True if all transaction authentication data is valid, false otherwise
function _verifyMany(address[] memory accounts, bytes calldata msgData) internal returns (bool) {
address signer_ = signer;
if (signer_ == address(0)) revert InvalidSigner();
if (accounts.length == 0) revert EmptyAccountsArray();
if (msgData.length < _EXTRA_DATA_LENGTH) revert InvalidMsgDataLength();
VerifyManyData memory data = _parseVerifyManyData(accounts, msgData);
if (block.number >= data.blockExpiration) revert InvalidBlockExpiration();
for (uint256 i = 0; i < accounts.length; i++) {
if (accounts[i] == address(0)) revert ZeroAddress();
if (!_verifySingle(signer_, accounts[i], data, i, msgData)) {
revert InvalidSignature();
}
}
return true;
}
/// @dev Parse msgData for _verifyMany function
function _parseVerifyManyData(address[] memory accounts, bytes calldata msgData)
private
pure
returns (VerifyManyData memory data)
{
data.numSignatures = uint256(bytes32(msgData[msgData.length - _BYTES_32_LENGTH:]));
if (data.numSignatures != accounts.length) revert ArrayLengthMismatch();
uint256 extraDataLength = _BYTES_32_LENGTH + (data.numSignatures * _SIGNATURE_LENGTH) + _BYTES_32_LENGTH;
if (msgData.length < extraDataLength) revert InvalidMsgDataLength();
data.argsWithSelector = msgData[:msgData.length - extraDataLength];
uint256 blockExpirationStart = msgData.length - extraDataLength;
data.blockExpiration = uint256(bytes32(msgData[blockExpirationStart:blockExpirationStart + _BYTES_32_LENGTH]));
data.signaturesStart = blockExpirationStart + _BYTES_32_LENGTH;
}
/// @dev Verify a single signature within verifyMany
function _verifySingle(address signer_, address account, VerifyManyData memory data, uint256 index, bytes calldata msgData)
private
returns (bool)
{
uint256 nonce = nonces[account]++;
bytes32 digest = _getTypedDataHash(
TxAuthData({
functionCallData: data.argsWithSelector,
contractAddress: address(this),
account: account,
nonce: nonce,
blockExpiration: data.blockExpiration
})
);
emit TxAuthDataVerified(
block.chainid, nonce, data.blockExpiration, address(this), account, data.argsWithSelector
);
bytes calldata signature = msgData[
data.signaturesStart + (index * _SIGNATURE_LENGTH):data.signaturesStart + ((index + 1) * _SIGNATURE_LENGTH)
];
return SignatureChecker.isValidSignatureNow(signer_, digest, signature);
}
/// @dev Compute EIP-712 typed data digest for TxAuthData
function _getTypedDataHash(TxAuthData memory txAuthData) internal view returns (bytes32) {
bytes32 structHash = keccak256(
abi.encode(
_TXAUTH_TYPEHASH,
keccak256(txAuthData.functionCallData),
txAuthData.contractAddress,
txAuthData.account,
txAuthData.nonce,
txAuthData.blockExpiration
)
);
return _hashTypedDataV4(structHash);
}
/// @dev Sets the signer address
function _setSigner(address signer_) internal {
address oldSigner = signer;
signer = signer_;
emit SignerChanged(oldSigner, signer_);
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.20;
import {IWhitelistable} from "../interfaces/IAccess.sol";
import {ArrayLengthMismatch} from "../constants/Errors.sol";
/// @title Whitelistable - A contract that allows whitelisting of accounts
/// @notice This contract is used to allow/disallow account access
/// @dev See IWhitelistable for detailed interface documentation
/// @custom:security-contact [email protected]
abstract contract Whitelistable is IWhitelistable {
/// @notice Mapping to track the allowed status of accounts
/// @dev Maps an account address to its allowed status
mapping(address account => bool allowed) public allowed;
/// @inheritdoc IWhitelistable
function setAllowed(address[] calldata accounts, bool[] calldata statuses) public virtual {
if (accounts.length != statuses.length) revert ArrayLengthMismatch();
for (uint256 i = 0; i < accounts.length;) {
allowed[accounts[i]] = statuses[i];
emit AllowedSet(accounts[i], statuses[i]);
unchecked {
++i;
}
}
}
function allowedMany(address[] memory accounts) public view returns (bool) {
for (uint256 i = 0; i < accounts.length;) {
if (!allowed[accounts[i]]) return false;
unchecked {
++i;
}
}
return true;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../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 An operation with an ERC20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @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.encodeCall(token.transfer, (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.encodeCall(token.transferFrom, (from, to, 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);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @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.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @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);
if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @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(token).code.length > 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @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 Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard ERC20 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens.
*/
interface IERC20Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC20InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC20InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
* @param spender Address that may be allowed to operate on tokens without being their owner.
* @param allowance Amount of tokens a `spender` is allowed to operate with.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC20InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `spender` to be approved. Used in approvals.
* @param spender Address that may be allowed to operate on tokens without being their owner.
*/
error ERC20InvalidSpender(address spender);
}
/**
* @dev Standard ERC721 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens.
*/
interface IERC721Errors {
/**
* @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20.
* Used in balance queries.
* @param owner Address of the current owner of a token.
*/
error ERC721InvalidOwner(address owner);
/**
* @dev Indicates a `tokenId` whose `owner` is the zero address.
* @param tokenId Identifier number of a token.
*/
error ERC721NonexistentToken(uint256 tokenId);
/**
* @dev Indicates an error related to the ownership over a particular token. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param tokenId Identifier number of a token.
* @param owner Address of the current owner of a token.
*/
error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC721InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC721InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param tokenId Identifier number of a token.
*/
error ERC721InsufficientApproval(address operator, uint256 tokenId);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC721InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC721InvalidOperator(address operator);
}
/**
* @dev Standard ERC1155 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens.
*/
interface IERC1155Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
* @param tokenId Identifier number of a token.
*/
error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC1155InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC1155InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param owner Address of the current owner of a token.
*/
error ERC1155MissingApprovalForAll(address operator, address owner);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC1155InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC1155InvalidOperator(address operator);
/**
* @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
* Used in batch transfers.
* @param idsLength Length of the array of token identifiers
* @param valuesLength Length of the array of token amounts
*/
error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/EIP712.sol)
pragma solidity ^0.8.20;
import {MessageHashUtils} from "./MessageHashUtils.sol";
import {ShortStrings, ShortString} from "../ShortStrings.sol";
import {IERC5267} from "../../interfaces/IERC5267.sol";
/**
* @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
*
* The encoding scheme specified in the EIP requires a domain separator and a hash of the typed structured data, whose
* encoding is very generic and therefore its implementation in Solidity is not feasible, thus this contract
* does not implement the encoding itself. Protocols need to implement the type-specific encoding they need in order to
* produce the hash of their typed data using a combination of `abi.encode` and `keccak256`.
*
* This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
* scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
* ({_hashTypedDataV4}).
*
* The implementation of the domain separator was designed to be as efficient as possible while still properly updating
* the chain id to protect against replay attacks on an eventual fork of the chain.
*
* NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
* https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
*
* NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain
* separator of the implementation contract. This will cause the {_domainSeparatorV4} function to always rebuild the
* separator from the immutable values, which is cheaper than accessing a cached version in cold storage.
*
* @custom:oz-upgrades-unsafe-allow state-variable-immutable
*/
abstract contract EIP712 is IERC5267 {
using ShortStrings for *;
bytes32 private constant TYPE_HASH =
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
// Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
// invalidate the cached domain separator if the chain id changes.
bytes32 private immutable _cachedDomainSeparator;
uint256 private immutable _cachedChainId;
address private immutable _cachedThis;
bytes32 private immutable _hashedName;
bytes32 private immutable _hashedVersion;
ShortString private immutable _name;
ShortString private immutable _version;
string private _nameFallback;
string private _versionFallback;
/**
* @dev Initializes the domain separator and parameter caches.
*
* The meaning of `name` and `version` is specified in
* https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
*
* - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
* - `version`: the current major version of the signing domain.
*
* NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
* contract upgrade].
*/
constructor(string memory name, string memory version) {
_name = name.toShortStringWithFallback(_nameFallback);
_version = version.toShortStringWithFallback(_versionFallback);
_hashedName = keccak256(bytes(name));
_hashedVersion = keccak256(bytes(version));
_cachedChainId = block.chainid;
_cachedDomainSeparator = _buildDomainSeparator();
_cachedThis = address(this);
}
/**
* @dev Returns the domain separator for the current chain.
*/
function _domainSeparatorV4() internal view returns (bytes32) {
if (address(this) == _cachedThis && block.chainid == _cachedChainId) {
return _cachedDomainSeparator;
} else {
return _buildDomainSeparator();
}
}
function _buildDomainSeparator() private view returns (bytes32) {
return keccak256(abi.encode(TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this)));
}
/**
* @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
* function returns the hash of the fully encoded EIP712 message for this domain.
*
* This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
*
* ```solidity
* bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
* keccak256("Mail(address to,string contents)"),
* mailTo,
* keccak256(bytes(mailContents))
* )));
* address signer = ECDSA.recover(digest, signature);
* ```
*/
function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
return MessageHashUtils.toTypedDataHash(_domainSeparatorV4(), structHash);
}
/**
* @dev See {IERC-5267}.
*/
function eip712Domain()
public
view
virtual
returns (
bytes1 fields,
string memory name,
string memory version,
uint256 chainId,
address verifyingContract,
bytes32 salt,
uint256[] memory extensions
)
{
return (
hex"0f", // 01111
_EIP712Name(),
_EIP712Version(),
block.chainid,
address(this),
bytes32(0),
new uint256[](0)
);
}
/**
* @dev The name parameter for the EIP712 domain.
*
* NOTE: By default this function reads _name which is an immutable value.
* It only reads from storage if necessary (in case the value is too large to fit in a ShortString).
*/
// solhint-disable-next-line func-name-mixedcase
function _EIP712Name() internal view returns (string memory) {
return _name.toStringWithFallback(_nameFallback);
}
/**
* @dev The version parameter for the EIP712 domain.
*
* NOTE: By default this function reads _version which is an immutable value.
* It only reads from storage if necessary (in case the value is too large to fit in a ShortString).
*/
// solhint-disable-next-line func-name-mixedcase
function _EIP712Version() internal view returns (string memory) {
return _version.toStringWithFallback(_versionFallback);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/SignatureChecker.sol)
pragma solidity ^0.8.20;
import {ECDSA} from "./ECDSA.sol";
import {IERC1271} from "../../interfaces/IERC1271.sol";
/**
* @dev Signature verification helper that can be used instead of `ECDSA.recover` to seamlessly support both ECDSA
* signatures from externally owned accounts (EOAs) as well as ERC1271 signatures from smart contract wallets like
* Argent and Safe Wallet (previously Gnosis Safe).
*/
library SignatureChecker {
/**
* @dev Checks if a signature is valid for a given signer and data hash. If the signer is a smart contract, the
* signature is validated against that smart contract using ERC1271, otherwise it's validated using `ECDSA.recover`.
*
* NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus
* change through time. It could return true at block N and false at block N+1 (or the opposite).
*/
function isValidSignatureNow(address signer, bytes32 hash, bytes memory signature) internal view returns (bool) {
(address recovered, ECDSA.RecoverError error, ) = ECDSA.tryRecover(hash, signature);
return
(error == ECDSA.RecoverError.NoError && recovered == signer) ||
isValidERC1271SignatureNow(signer, hash, signature);
}
/**
* @dev Checks if a signature is valid for a given signer and data hash. The signature is validated
* against the signer smart contract using ERC1271.
*
* NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus
* change through time. It could return true at block N and false at block N+1 (or the opposite).
*/
function isValidERC1271SignatureNow(
address signer,
bytes32 hash,
bytes memory signature
) internal view returns (bool) {
(bool success, bytes memory result) = signer.staticcall(
abi.encodeCall(IERC1271.isValidSignature, (hash, signature))
);
return (success &&
result.length >= 32 &&
abi.decode(result, (bytes32)) == bytes32(IERC1271.isValidSignature.selector));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.20;
/**
* @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.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
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].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error AddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedInnerCall();
/**
* @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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
/**
* @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 or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {FailedInnerCall} error.
*
* 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.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @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`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
* unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {FailedInnerCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
*/
function _revert(bytes memory returndata) 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 FailedInnerCall();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MessageHashUtils.sol)
pragma solidity ^0.8.20;
import {Strings} from "../Strings.sol";
/**
* @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing.
*
* The library provides methods for generating a hash of a message that conforms to the
* https://eips.ethereum.org/EIPS/eip-191[EIP 191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712]
* specifications.
*/
library MessageHashUtils {
/**
* @dev Returns the keccak256 digest of an EIP-191 signed data with version
* `0x45` (`personal_sign` messages).
*
* The digest is calculated by prefixing a bytes32 `messageHash` with
* `"\x19Ethereum Signed Message:\n32"` and hashing the result. It corresponds with the
* hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
*
* NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with
* keccak256, although any bytes32 value can be safely used because the final digest will
* be re-hashed.
*
* See {ECDSA-recover}.
*/
function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, "\x19Ethereum Signed Message:\n32") // 32 is the bytes-length of messageHash
mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix
digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20)
}
}
/**
* @dev Returns the keccak256 digest of an EIP-191 signed data with version
* `0x45` (`personal_sign` messages).
*
* The digest is calculated by prefixing an arbitrary `message` with
* `"\x19Ethereum Signed Message:\n" + len(message)` and hashing the result. It corresponds with the
* hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
*
* See {ECDSA-recover}.
*/
function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) {
return
keccak256(bytes.concat("\x19Ethereum Signed Message:\n", bytes(Strings.toString(message.length)), message));
}
/**
* @dev Returns the keccak256 digest of an EIP-191 signed data with version
* `0x00` (data with intended validator).
*
* The digest is calculated by prefixing an arbitrary `data` with `"\x19\x00"` and the intended
* `validator` address. Then hashing the result.
*
* See {ECDSA-recover}.
*/
function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(hex"19_00", validator, data));
}
/**
* @dev Returns the keccak256 digest of an EIP-712 typed data (EIP-191 version `0x01`).
*
* The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with
* `\x19\x01` and hashing the result. It corresponds to the hash signed by the
* https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712.
*
* See {ECDSA-recover}.
*/
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40)
mstore(ptr, hex"19_01")
mstore(add(ptr, 0x02), domainSeparator)
mstore(add(ptr, 0x22), structHash)
digest := keccak256(ptr, 0x42)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ShortStrings.sol)
pragma solidity ^0.8.20;
import {StorageSlot} from "./StorageSlot.sol";
// | string | 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA |
// | length | 0x BB |
type ShortString is bytes32;
/**
* @dev This library provides functions to convert short memory strings
* into a `ShortString` type that can be used as an immutable variable.
*
* Strings of arbitrary length can be optimized using this library if
* they are short enough (up to 31 bytes) by packing them with their
* length (1 byte) in a single EVM word (32 bytes). Additionally, a
* fallback mechanism can be used for every other case.
*
* Usage example:
*
* ```solidity
* contract Named {
* using ShortStrings for *;
*
* ShortString private immutable _name;
* string private _nameFallback;
*
* constructor(string memory contractName) {
* _name = contractName.toShortStringWithFallback(_nameFallback);
* }
*
* function name() external view returns (string memory) {
* return _name.toStringWithFallback(_nameFallback);
* }
* }
* ```
*/
library ShortStrings {
// Used as an identifier for strings longer than 31 bytes.
bytes32 private constant FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF;
error StringTooLong(string str);
error InvalidShortString();
/**
* @dev Encode a string of at most 31 chars into a `ShortString`.
*
* This will trigger a `StringTooLong` error is the input string is too long.
*/
function toShortString(string memory str) internal pure returns (ShortString) {
bytes memory bstr = bytes(str);
if (bstr.length > 31) {
revert StringTooLong(str);
}
return ShortString.wrap(bytes32(uint256(bytes32(bstr)) | bstr.length));
}
/**
* @dev Decode a `ShortString` back to a "normal" string.
*/
function toString(ShortString sstr) internal pure returns (string memory) {
uint256 len = byteLength(sstr);
// using `new string(len)` would work locally but is not memory safe.
string memory str = new string(32);
/// @solidity memory-safe-assembly
assembly {
mstore(str, len)
mstore(add(str, 0x20), sstr)
}
return str;
}
/**
* @dev Return the length of a `ShortString`.
*/
function byteLength(ShortString sstr) internal pure returns (uint256) {
uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF;
if (result > 31) {
revert InvalidShortString();
}
return result;
}
/**
* @dev Encode a string into a `ShortString`, or write it to storage if it is too long.
*/
function toShortStringWithFallback(string memory value, string storage store) internal returns (ShortString) {
if (bytes(value).length < 32) {
return toShortString(value);
} else {
StorageSlot.getStringSlot(store).value = value;
return ShortString.wrap(FALLBACK_SENTINEL);
}
}
/**
* @dev Decode a string that was encoded to `ShortString` or written to storage using {setWithFallback}.
*/
function toStringWithFallback(ShortString value, string storage store) internal pure returns (string memory) {
if (ShortString.unwrap(value) != FALLBACK_SENTINEL) {
return toString(value);
} else {
return store;
}
}
/**
* @dev Return the length of a string that was encoded to `ShortString` or written to storage using
* {setWithFallback}.
*
* WARNING: This will return the "byte length" of the string. This may not reflect the actual length in terms of
* actual characters as the UTF-8 encoding of a single character can span over multiple bytes.
*/
function byteLengthWithFallback(ShortString value, string storage store) internal view returns (uint256) {
if (ShortString.unwrap(value) != FALLBACK_SENTINEL) {
return byteLength(value);
} else {
return bytes(store).length;
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5267.sol)
pragma solidity ^0.8.20;
interface IERC5267 {
/**
* @dev MAY be emitted to signal that the domain could have changed.
*/
event EIP712DomainChanged();
/**
* @dev returns the fields and values that describe the domain separator used by this contract for EIP-712
* signature.
*/
function eip712Domain()
external
view
returns (
bytes1 fields,
string memory name,
string memory version,
uint256 chainId,
address verifyingContract,
bytes32 salt,
uint256[] memory extensions
);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/ECDSA.sol)
pragma solidity ^0.8.20;
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*/
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS
}
/**
* @dev The signature derives the `address(0)`.
*/
error ECDSAInvalidSignature();
/**
* @dev The signature has an invalid length.
*/
error ECDSAInvalidSignatureLength(uint256 length);
/**
* @dev The signature has an S value that is in the upper half order.
*/
error ECDSAInvalidSignatureS(bytes32 s);
/**
* @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not
* return address(0) without also returning an error description. Errors are documented using an enum (error type)
* and a bytes32 providing additional information about the error.
*
* If no error is returned, then the address can be used for verification purposes.
*
* The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
*
* Documentation for signature generation:
* - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
* - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
*/
function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError, bytes32) {
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
/// @solidity memory-safe-assembly
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else {
return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
*
* See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
*/
function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError, bytes32) {
unchecked {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
// We do not check for an overflow here since the shift operation results in 0 or 1.
uint8 v = uint8((uint256(vs) >> 255) + 27);
return tryRecover(hash, v, r, s);
}
}
/**
* @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
*/
function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function tryRecover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address, RecoverError, bytes32) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS, s);
}
// If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature, bytes32(0));
}
return (signer, RecoverError.NoError, bytes32(0));
}
/**
* @dev Overload of {ECDSA-recover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.
*/
function _throwError(RecoverError error, bytes32 errorArg) private pure {
if (error == RecoverError.NoError) {
return; // no error: do nothing
} else if (error == RecoverError.InvalidSignature) {
revert ECDSAInvalidSignature();
} else if (error == RecoverError.InvalidSignatureLength) {
revert ECDSAInvalidSignatureLength(uint256(errorArg));
} else if (error == RecoverError.InvalidSignatureS) {
revert ECDSAInvalidSignatureS(errorArg);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1271.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC1271 standard signature validation method for
* contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271].
*/
interface IERC1271 {
/**
* @dev Should return whether the signature provided is valid for the provided data
* @param hash Hash of the data to be signed
* @param signature Signature byte array associated with _data
*/
function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)
pragma solidity ^0.8.20;
import {Math} from "./math/Math.sol";
import {SignedMath} from "./math/SignedMath.sol";
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant HEX_DIGITS = "0123456789abcdef";
uint8 private constant ADDRESS_LENGTH = 20;
/**
* @dev The `value` string doesn't fit in the specified `length`.
*/
error StringsInsufficientHexLength(uint256 value, uint256 length);
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toStringSigned(int256 value) internal pure returns (string memory) {
return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value)));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
uint256 localValue = value;
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = HEX_DIGITS[localValue & 0xf];
localValue >>= 4;
}
if (localValue != 0) {
revert StringsInsufficientHexLength(value, length);
}
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal
* representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity ^0.8.20;
/**
* @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:
* ```solidity
* 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(newImplementation.code.length > 0);
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes 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
}
}
/**
* @dev Returns an `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` representation of the string storage pointer `store`.
*/
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
/**
* @dev Returns an `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
*/
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMath {
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// must be unchecked in order to support `n = type(int256).min`
return uint256(n >= 0 ? n : -n);
}
}
}{
"remappings": [
"@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"ds-test/=lib/openzeppelin-contracts-upgradeable/lib/forge-std/lib/ds-test/src/",
"erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
"forge-std/=lib/forge-std/src/",
"murky/=lib/murky/src/",
"openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"openzeppelin-foundry-upgrades/=lib/openzeppelin-foundry-upgrades/src/",
"solidity-stringutils/=lib/openzeppelin-foundry-upgrades/lib/solidity-stringutils/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": true
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract IERC20","name":"asset_","type":"address"},{"internalType":"address","name":"strategy_","type":"address"},{"internalType":"bool","name":"sharesTransferable_","type":"bool"},{"internalType":"enum PermissionLevel","name":"permissionLevel_","type":"uint8"},{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"},{"internalType":"uint256","name":"precision_","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"ArrayLengthMismatch","type":"error"},{"inputs":[],"name":"CancelRedeemRequestFailed","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"allowance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC20InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC20InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC20InvalidSender","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"}],"name":"ERC20InvalidSpender","type":"error"},{"inputs":[],"name":"EmptyAccountsArray","type":"error"},{"inputs":[],"name":"ExceedsMaxRedeem","type":"error"},{"inputs":[],"name":"ExceedsRedeemLimit","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"InsufficientAmount","type":"error"},{"inputs":[],"name":"InsufficientLiquidity","type":"error"},{"inputs":[],"name":"InsufficientShares","type":"error"},{"inputs":[],"name":"InvalidBlockExpiration","type":"error"},{"inputs":[],"name":"InvalidController","type":"error"},{"inputs":[],"name":"InvalidMsgDataLength","type":"error"},{"inputs":[],"name":"InvalidOperator","type":"error"},{"inputs":[],"name":"InvalidRange","type":"error"},{"inputs":[],"name":"InvalidShortString","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"InvalidSigner","type":"error"},{"inputs":[],"name":"MathOverflowedMulDiv","type":"error"},{"inputs":[],"name":"NoPendingRedeemRequest","type":"error"},{"inputs":[],"name":"NoQueueRequest","type":"error"},{"inputs":[],"name":"NoRedeemRequest","type":"error"},{"inputs":[],"name":"OutOfBounds","type":"error"},{"inputs":[],"name":"PermissionLevelMismatch","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"SharesNotTransferable","type":"error"},{"inputs":[{"internalType":"string","name":"str","type":"string"}],"name":"StringTooLong","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"bool","name":"allowed","type":"bool"}],"name":"AllowedSet","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":"controller","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":false,"internalType":"address","name":"sender","type":"address"}],"name":"CancelRedeemRequest","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":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[],"name":"EIP712DomainChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"}],"name":"LockAssets","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"controller","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"OperatorSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"controller","type":"address"},{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"RedeemClaimable","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"controller","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"}],"name":"RedeemRequest","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"}],"name":"ReleaseAssets","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"oldStatus","type":"bool"},{"indexed":false,"internalType":"bool","name":"newStatus","type":"bool"}],"name":"SharesTransferableSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldSigner","type":"address"},{"indexed":true,"internalType":"address","name":"newSigner","type":"address"}],"name":"SignerChanged","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":false,"internalType":"uint256","name":"chainID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"blockExpiration","type":"uint256"},{"indexed":true,"internalType":"address","name":"contractAddress","type":"address"},{"indexed":true,"internalType":"address","name":"userAddress","type":"address"},{"indexed":false,"internalType":"bytes","name":"functionCallData","type":"bytes"}],"name":"TxAuthDataVerified","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":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"MIN_AMOUNT_WEI","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"allowed","outputs":[{"internalType":"bool","name":"allowed","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"}],"name":"allowedMany","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"asset","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"assetShareRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"sender","type":"address"}],"name":"burnShares","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"controller","type":"address"},{"internalType":"address","name":"receiver","type":"address"}],"name":"cancelRedeemRequest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"controller","type":"address"}],"name":"claimableRedeemRequest","outputs":[{"internalType":"uint256","name":"claimableShares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"convertToAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"convertToShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"controller","type":"address"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"eip712Domain","outputs":[{"internalType":"bytes1","name":"fields","type":"bytes1"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"verifyingContract","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256[]","name":"extensions","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"forceTransferShares","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"controller","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"fulfillRedeemRequest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"functionCallData","type":"bytes"},{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"blockExpiration","type":"uint256"}],"internalType":"struct TxAuthData","name":"txAuthData","type":"tuple"}],"name":"getMessageHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"controller","type":"address"}],"name":"getState","outputs":[{"components":[{"internalType":"uint256","name":"maxMint","type":"uint256"},{"internalType":"uint256","name":"maxWithdraw","type":"uint256"},{"internalType":"uint256","name":"depositAssets","type":"uint256"},{"internalType":"uint256","name":"redeemShares","type":"uint256"},{"internalType":"uint256","name":"depositPrice","type":"uint256"},{"internalType":"uint256","name":"mintPrice","type":"uint256"},{"internalType":"uint256","name":"redeemPrice","type":"uint256"},{"internalType":"uint256","name":"withdrawPrice","type":"uint256"},{"internalType":"uint256","name":"pendingDepositRequest","type":"uint256"},{"internalType":"uint256","name":"pendingRedeemRequest","type":"uint256"}],"internalType":"struct VaultState","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"isOperator","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"sender","type":"address"}],"name":"lockAssets","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"controller","type":"address"}],"name":"maxDeposit","outputs":[{"internalType":"uint256","name":"maxAssets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"controller","type":"address"}],"name":"maxMint","outputs":[{"internalType":"uint256","name":"maxShares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"controller","type":"address"}],"name":"maxRedeem","outputs":[{"internalType":"uint256","name":"maxShares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"controller","type":"address"}],"name":"maxWithdraw","outputs":[{"internalType":"uint256","name":"maxAssets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"controller","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"mintShares","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"nonce","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"controller","type":"address"}],"name":"pendingRedeemRequest","outputs":[{"internalType":"uint256","name":"pendingShares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"permissionLevel","outputs":[{"internalType":"enum PermissionLevel","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"precision","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewDeposit","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxAssets","type":"uint256"}],"name":"previewMaxRequestId","outputs":[{"internalType":"uint256","name":"maxRequestId","type":"uint256"},{"internalType":"uint256","name":"assetsUsed","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewMint","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"previewRedeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxAssets","type":"uint256"}],"name":"previewRequiredShares","outputs":[{"internalType":"uint256","name":"processedShares","type":"uint256"},{"internalType":"uint256","name":"assetsUsed","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"previewWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxRequestId","type":"uint256"}],"name":"processUpToRequestId","outputs":[{"internalType":"uint256","name":"processedShares","type":"uint256"},{"internalType":"uint256","name":"assetsUsed","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxShares","type":"uint256"}],"name":"processUpToShares","outputs":[{"internalType":"uint256","name":"assetsUsed","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"queue","outputs":[{"internalType":"uint128","name":"nextRequestId","type":"uint128"},{"internalType":"uint128","name":"lastRequestId","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"controller","type":"address"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"releaseAssets","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"controller","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"requestRedeem","outputs":[{"internalType":"uint256","name":"requestId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"reservedLiquidity","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"bool[]","name":"statuses","type":"bool[]"}],"name":"setAllowed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setOperator","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"sharesTransferable_","type":"bool"}],"name":"setSharesTransferable","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"signer_","type":"address"}],"name":"setSigner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"share","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sharePrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"signer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"strategy","outputs":[{"internalType":"contract IStrategyVaultHooks","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalQueuedShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":[],"name":"transferableShares","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"controller","type":"address"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"controller","type":"address"}],"name":"withdrawalRequest","outputs":[{"components":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"controller","type":"address"}],"internalType":"struct WithdrawalRequest","name":"request","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint128","name":"start","type":"uint128"},{"internalType":"uint128","name":"end","type":"uint128"}],"name":"withdrawalRequests","outputs":[{"components":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"controller","type":"address"}],"internalType":"struct WithdrawalRequest[]","name":"requests","type":"tuple[]"}],"stateMutability":"view","type":"function"}]Contract Creation Code
6101a0806040523461052b57614be0803803809161001d828561052f565b833981019060e08183031261052b5780516001600160a01b038116810361052b5760208201516001600160a01b0381169081900361052b5760408301519182151580930361052b576060840151600381101561052b5760808501516001600160401b03811161052b578661009291870161056d565b60a08601519096906001600160401b03811161052b5760c0916100b691880161056d565b9501519460409687516100c9898261052f565b600c815260208101906b417574686f72697a61626c6560a01b82528951936100f18b8661052f565b6001808652603160f81b602087019081525f8c905581546001600160801b0319168217909155845190946001600160401b03821161042e5760095490600182811c92168015610521575b60208310146104105781601f8493116104b3575b50602090601f831160011461044d575f92610442575b50508160011b915f199060031b1c1916176009555b8051906001600160401b03821161042e57600a5490600182811c92168015610424575b60208310146104105781601f8493116103a2575b50602090601f831160011461033c575f92610331575b50508160011b915f199060031b1c191617600a555b6101e581610656565b610120526101f2846107dd565b61014052519020918260e05251902080610100524660a05287519060208201927f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f84528983015260608201524660808201523060a082015260a0815261025960c08261052f565b5190206080523060c05260ff80196010541691161760105561027a816105b3565b9015610329575b6101805261016052801561031a5760018060a01b0319601354161760135560ff801960165416911617601655601455516142ca9081610916823960805181614068015260a05181614125015260c05181614032015260e051816140b7015261010051816140dd01526101205181611076015261014051816110a0015261016051818181611a980152612fc701526101805181611b940152f35b63d92e233d60e01b5f5260045ffd5b506012610281565b015190505f806101c7565b600a5f9081528281209350601f198516905b81811061038a5750908460019594939210610372575b505050811b01600a556101dc565b01515f1960f88460031b161c191690555f8080610364565b9293602060018192878601518155019501930161034e565b600a5f529091507fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a8601f840160051c81019160208510610406575b90601f859493920160051c01905b8181106103f857506101b1565b5f81558493506001016103eb565b90915081906103dd565b634e487b7160e01b5f52602260045260245ffd5b91607f169161019d565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610165565b60095f9081528281209350601f198516905b81811061049b5750908460019594939210610483575b505050811b0160095561017a565b01515f1960f88460031b161c191690555f8080610475565b9293602060018192878601518155019501930161045f565b60095f529091507f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af601f840160051c81019160208510610517575b90601f859493920160051c01905b818110610509575061014f565b5f81558493506001016104fc565b90915081906104ee565b91607f169161013b565b5f80fd5b601f909101601f19168101906001600160401b0382119082101761042e57604052565b6001600160401b03811161042e57601f01601f191660200190565b81601f8201121561052b5780519061058482610552565b92610592604051948561052f565b8284526020838301011161052b57815f9260208093018386015e8301015290565b5f8091604051602081019063313ce56760e01b8252600481526105d760248261052f565b51916001600160a01b03165afa3d1561064e573d906105f582610552565b91610603604051938461052f565b82523d5f602084013e5b80610642575b61061f575b505f905f90565b60208180518101031261052b576020015160ff8111610618579060ff6001921690565b50602081511015610613565b60609061060d565b908151602081105f146106d0575090601f815111610690576020815191015160208210610681571790565b5f198260200360031b1b161790565b604460209160405192839163305a27a960e01b83528160048401528051918291826024860152018484015e5f828201840152601f01601f19168101030190fd5b6001600160401b03811161042e57600c54600181811c911680156107d3575b602082101461041057601f81116107a0575b50602092601f821160011461073f57928192935f92610734575b50508160011b915f199060031b1c191617600c5560ff90565b015190505f8061071b565b601f19821693600c5f52805f20915f5b8681106107885750836001959610610770575b505050811b01600c5560ff90565b01515f1960f88460031b161c191690555f8080610762565b9192602060018192868501518155019401920161074f565b600c5f52601f60205f20910160051c810190601f830160051c015b8181106107c85750610701565b5f81556001016107bb565b90607f16906106ef565b908151602081105f14610808575090601f815111610690576020815191015160208210610681571790565b6001600160401b03811161042e57600d54600181811c9116801561090b575b602082101461041057601f81116108d8575b50602092601f821160011461087757928192935f9261086c575b50508160011b915f199060031b1c191617600d5560ff90565b015190505f80610853565b601f19821693600d5f52805f20915f5b8681106108c057508360019596106108a8575b505050811b01600d5560ff90565b01515f1960f88460031b161c191690555f808061089a565b91926020600181928685015181550194019201610887565b600d5f52601f60205f20910160051c810190601f830160051c015b8181106109005750610839565b5f81556001016108f3565b90607f169061082756fe6080806040526004361015610012575f80fd5b5f905f3560e01c90816301e1d1141461273b5750806301ffc9a71461262d57806306fdde031461256357806307a2d13a1461253957806308f45aff146123d7578063095ea7b31461232f5780630a28a4771461189757806317ee5d931461229357806318160ddd146122755780631bab58f51461213e5780631ef44e68146120b75780632246ced114612019578063238ac93314611ff057806323b872dd14611e8f57806324a16c6114611e1657806326535a8114611db95780632d0777d814611bd25780632e2d298414611bb8578063313ce56714611b7a57806335c1e48414611ac757806338d52e0f14611a825780633991998114611a655780633abb0604146118fd5780633d7849b7146118bb578063402d267d1461189c5780634cdad50614611897578063558a7297146117ed57806359c615d6146117ca578063623f50331461179e5780636c19e783146116d75780636e553f65146116ae57806370a0823114611675578063788cf2de146115aa5780637d41c86e146111915780637ecebe001461115857806384b0196e1461105c5780638726972914611041578063883fcc5614610e3b57806394bf804d14610e1257806395d89b4114610d2b57806399167fb414610cf25780639d81be4314610c7f5780639f30851214610c61578063a6bddd6314610af0578063a8c62e7614610ac7578063a8d5fd6514610aac578063a9059cbb146109e6578063b3d7f6b9146109bb578063b460af941461085c578063b6363cf214610804578063ba08765214610640578063bf919763146105f0578063c63d75b6146105b7578063c6e6f59214610407578063ce96cb7714610593578063d3b5dc3b14610575578063d63a8e1114610536578063d905777e14610517578063da39b3e7146104fd578063dc20c8ff146104df578063dd62ed3e1461048c578063e10d29ee1461045d578063eaed1d0714610439578063ef8b30f714610407578063f2b3c18f146103bd578063f5a23d8d146103805763fb53db6d146102ff575f80fd5b3461037d57604036600319011261037d5760043561031b61278f565b6013546001600160a01b0316330361036f5760208161035b847f48e891cea1a36b8bc4f1fb9fb7ae5508bf0edfee67aaeb354f1cfb8f62d68c8294613b53565b6040519384526001600160a01b031692a280f35b6282b42960e81b8352600483fd5b80fd5b503461037d57604036600319011261037d576020906009906040906001600160a01b036103ab61278f565b16815260128452200154604051908152f35b503461037d57604036600319011261037d576103d761278f565b6013546001600160a01b031633036103f9576103f690600435906135a9565b80f35b6282b42960e81b8252600482fd5b503461037d57602036600319011261037d576020610431610426612ce5565b6014546004356138f4565b604051908152f35b503461037d57604036600319011261037d57602061043161045861278f565b612d4c565b503461037d578060031936011261037d5760406001548151906001600160801b038116825260801c6020820152f35b503461037d57604036600319011261037d5760406104a8612779565b916104b161278f565b9260018060a01b031681526007602052209060018060a01b03165f52602052602060405f2054604051908152f35b503461037d578060031936011261037d576020600454604051908152f35b503461037d5760206104316105113661289a565b91612d6f565b503461037d57602036600319011261037d576020610431610458612779565b503461037d57602036600319011261037d5760209060ff906040906001600160a01b03610561612779565b168152600b84522054166040519015158152f35b503461037d578060031936011261037d576020601454604051908152f35b503461037d57602036600319011261037d5760206104316105b2612779565b612d22565b503461037d57602036600319011261037d5760206104316105de6105d9612779565b612c43565b6105e6612ce5565b90601454906138f4565b503461037d57602036600319011261037d576013546001600160a01b031633036106325760206104316106216136e6565b610629612ce5565b90600435613ba6565b6282b42960e81b8152600490fd5b503461037d5761064f3661289a565b9092916001600160a01b038281169290851691908284036107b85761067436826132ee565b156107aa575b61068382613590565b61068c8161347c565b61069581612d4c565b821161079b578385526012602052604085206006810154956106c56014546106be818a886138f4565b98866138ff565b6013549093906001600160a01b0316803b15610797576107019183918b8360405180968195829463d34cf33560e01b84528d3060048601612bc8565b03925af1801561078c57610777575b505060209661072f848061073e958a809661072a82613aad565b613acf565b6107398430613a27565b613b53565b60405190848252858201527ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db60403392a4604051908152f35b610782828092612862565b61037d5780610710565b6040513d84823e3d90fd5b8280fd5b63708a336b60e11b8552600485fd5b6282b42960e81b8552600485fd5b6107f26040516107c9606082612862565b600281526040366020830137846107df82612a00565b52856107ea82612a21565b523690612fed565b61067a576282b42960e81b8552600485fd5b503461037d57604036600319011261037d576040610820612779565b9161082961278f565b9260018060a01b031681526015602052209060018060a01b03165f52602052602060ff60405f2054166040519015158152f35b503461037d5761086b3661289a565b9092916001600160a01b038281169290851691908284036109985761089036826132ee565b156107aa575b61089f82613590565b6108a88161347c565b6108b181612d22565b821161079b578385526012602052604085206007810154956108db601454976106be818a886138f4565b6013549093906001600160a01b0316803b15610797576109179183918b836040518096819582946364a0366360e01b84528d3060048601612bc8565b03925af1801561078c57610983575b505060209661094061094a93888680809661072a82613aad565b6107398730613a27565b60405190815283858201527ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db60403392a4604051908152f35b61098e828092612862565b61037d5780610926565b6109a96040516107c9606082612862565b610896576282b42960e81b8552600485fd5b503461037d57602036600319011261037d5760206104316109da612ce5565b601454906004356138ff565b503461037d57604036600319011261037d57610a00612779565b6024359060ff6016541615610a9d57610a1936826132ee565b1561036f576013546001600160a01b0316803b15610a9957836040518092630987df0360e01b8252818381610a5489893330600486016129bd565b03925af18015610a8e57610a79575b610a6e838333612eb6565b602060405160018152f35b610a84848092612862565b6107975782610a63565b6040513d86823e3d90fd5b8380fd5b636dbb04b560e01b8352600483fd5b503461037d578060031936011261037d576020604051308152f35b503461037d578060031936011261037d576013546040516001600160a01b039091168152602090f35b503461037d57602036600319011261037d57610b0a612ce5565b6004358280815492600154946001600160801b0386169560801c96600454905b83151580610c58575b80610c45575b15610c34576001600160801b0388169485875260026020526040872095610b86898660405199610b688b6127fc565b8054808c526001909101546001600160a01b031660208c0152613cf9565b92868411610bcf57505081610ba2610bb09493610ba893612cd8565b95612cb7565b945190612cb7565b966001600160801b03610bc288612e99565b9716909790939293610b2a565b9895919760409b508693919a50859750610bf5959450508082105f14610c2d5750613cf9565b9182610c0f575b5050509091505b82519182526020820152f35b610c239450610c1d92613cf9565b90612cd8565b81905f8080610bfc565b9050613cf9565b965050505091505060409250610c03565b50886001600160801b0389161115610b39565b50811515610b33565b503461037d578060031936011261037d576020600554604051908152f35b503461037d57604036600319011261037d57610c99612779565b60135460243591906001600160a01b0316330361036f576001600160a01b038116835260036020526040832054610cee929190610ce9906001600160801b03168383610ce3612ce5565b9261393d565b6134c9565b5080f35b503461037d57604036600319011261037d57610d0c61278f565b6013546001600160a01b031633036103f9576103f69060043590613a27565b503461037d578060031936011261037d576040519080600a5490610d4e82612904565b8085529160018116908115610deb5750600114610d8e575b610d8a84610d7681860382612862565b604051918291602083526020830190612755565b0390f35b600a81527fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a8939250905b808210610dd157509091508101602001610d7682610d66565b919260018160209254838588010152019101909291610db8565b60ff191660208087019190915292151560051b85019092019250610d769150839050610d66565b503461037d57604036600319011261037d576020610431610e3161278f565b3390600435612d6f565b503461037d57604036600319011261037d576004356001600160801b03811680910361103d576024356001600160801b0381168091036107975781158015611034575b6110255760015460801c8111611016578190036001600160801b038111611002576001600160801b0360019116016001600160801b038111611002576001600160801b0316610ecc81612883565b610ed96040519182612862565b818152601f19610ee883612883565b01845b818110610fdf575050835b6001600160801b03811683811015610f84578085016001600160801b038111610f705791610f686001926001600160801b03809516895260026020526040892060405190610f43826127fc565b8054825285808060a01b03910154166020820152610f618288612a31565b5285612a31565b500116610ef6565b634e487b7160e01b87526011600452602487fd5b8286604051918291602083016020845282518091526020604085019301915b818110610fb1575050500390f35b8251805185526020908101516001600160a01b03168186015286955060409094019390920191600101610fa3565b602090604051610fee816127fc565b5f81525f8382015282828601015201610eeb565b634e487b7160e01b83526011600452602483fd5b632d0483c560e21b8352600483fd5b63561ce9bb60e01b8352600483fd5b50808211610e7e565b5080fd5b503461037d578060031936011261037d576020610431612ce5565b503461037d578060031936011261037d576110fc9061109a7f0000000000000000000000000000000000000000000000000000000000000000613e58565b906110c47f0000000000000000000000000000000000000000000000000000000000000000613eb8565b90602061110a604051936110d88386612862565b8385525f368137604051968796600f60f81b885260e08589015260e0880190612755565b908682036040880152612755565b904660608601523060808601528260a086015284820360c08601528080855193848152019401925b82811061114157505050500390f35b835185528695509381019392810192600101611132565b503461037d57602036600319011261037d576020906040906001600160a01b03611180612779565b168152600f83522054604051908152f35b503461037d576111a03661289a565b9092916001600160a01b03808316929085169190838303611566576111c536876132ee565b156107aa575b3384141580611543575b611534576111e28661347c565b6111eb82613590565b838552600660205281604086205410801561152c575b61151d57604081869785611252985260126020526009838a2001611226868254612cd8565b905560018060a01b036013541690898451809a8195829463716f6e8d60e11b84528a3060048601612bc8565b03925af194851561151257869087966114cd575b50156113c85785948387526012602052604087206009810191825480156113b95785116113aa5760145461129a91866138f4565b916112a36136e6565b831161139b57847f1fdc681a13d8c5da54e301c7ce6542dcde4581e4725043fdab2db12ddc5745069460209a887f4dd5187225a2ae5f5ea35ca7b1732180f848cc4b6f7dce34b4c5e9f384d77dec6040888e9d9c9b9860076113616113789a6113116113909e600554612cd8565b60055560018401611323868254612cd8565b80915560038501916113368d8454612cd8565b8093556113448d8254612cb7565b90556113538260145483613cf9565b6006860155601454906138ff565b91015581519081528f8790820152a35b3090612eb6565b60408051338152602081019290925290918291820190565b0390a4604051908152f35b63bb55fd2760e01b8952600489fd5b632ca2f52b60e11b8952600489fd5b634ef1d5c560e01b8a5260048afd5b92919093507f1fdc681a13d8c5da54e301c7ce6542dcde4581e4725043fdab2db12ddc574506611390856113786001600160801b038960209a5086815260038b528160408220541680155f146114af5750600154600161142a8260801c612e99565b848116928580198360801b1691161782559289815260038e5260408120838619825416179055604080519161145e836127fc565b8883528f8301948c865281528f600290522090518155019060018060a01b039051166bffffffffffffffffffffffff60a01b8254161790555b6114a384600454612cd8565b60045516978897611371565b9060409082815260028d52206114c6858254612cd8565b9055611497565b9550506040853d60401161150a575b816114e960409383612862565b810103126115065760206114fc86612a8d565b950151945f611266565b8580fd5b3d91506114dc565b6040513d88823e3d90fd5b633999656760e01b8552600485fd5b508115611201565b63ccea9e6f60e01b8552600485fd5b50838552601560209081526040808720335f908152925290205460ff16156111d5565b611598604051611577606082612862565b6002815260403660208301378561158d82612a00565b52846107ea82612a21565b6111cb576282b42960e81b8552600485fd5b503461037d578060031936011261037d57600854601354604051638304ff8f60e01b8152306004820152919290602090839060249082906001600160a01b03165afa918215611668578192611630575b5050816116105750506020601454604051908152f35b60209161162261162b92601154612cb7565b601454906138f4565b610431565b9091506020813d602011611660575b8161164c60209383612862565b8101031261165c5751905f6115fa565b5f80fd5b3d915061163f565b50604051903d90823e3d90fd5b503461037d57602036600319011261037d576020906040906001600160a01b0361169d612779565b168152600683522054604051908152f35b503461037d57604036600319011261037d5760206104316116cd61278f565b3390600435612a9a565b503461037d57602036600319011261037d576116f1612779565b6013546001600160a01b031633036103f95760ff60105416600381101561178a5760010361177b576001600160a01b0316801561176c57600e80546001600160a01b0319811683179091556001600160a01b03167feeb293e1f8f3a9db91ade748726387ed1352ca78f5430c5f06fe3d1e1ad505798380a380f35b63d92e233d60e01b8252600482fd5b63fb61026d60e01b8252600482fd5b634e487b7160e01b83526021600452602483fd5b503461037d578060031936011261037d5760ff6010541660405190600381101561178a57602092508152f35b503461037d578060031936011261037d57602060ff601654166040519015158152f35b503461037d57604036600319011261037d57611807612779565b60243580151591828203610a99576001600160a01b0316923384146118885790604061185192338152601560205220845f5260205260405f209060ff801983541691151516179055565b6040519081527fceb576d9f15e4e200fdb5096d64d5dfd667e16def20c1eefd14256d8e3faa26760203392a3602060405160018152f35b63ccea9e6f60e01b8152600490fd5b6127b9565b503461037d57602036600319011261037d5760206104316105d9612779565b503461037d57602036600319011261037d576013546001600160a01b03163303610632576040610c036118ec6136e6565b6118f4612ce5565b90600435613776565b503461037d57604036600319011261037d576004356001600160401b03811161103d5761192e9036906004016128d4565b6024356001600160401b038111610a995761194d9036906004016128d4565b601354919290916001600160a01b031633036107aa5760ff601054166003811015611a5157600203611a4257818103611a3357845b81811061198d578580f35b806119dc6119a66119a160019487896136b5565b6136c5565b838060a01b036119bf6119ba85888c6136b5565b6136d2565b168952600b602052604089209060ff801983541691151516179055565b6119ea6119ba8285896136b5565b7fc5217903bd71390e046be1c1ee589f3af533c8fe5b67ee0a7dade2f8a853badd6020611a1b6119a185898b6136b5565b926040519315158452858060a01b031692a201611982565b63512509d360e11b8552600485fd5b63fb61026d60e01b8552600485fd5b634e487b7160e01b86526021600452602486fd5b503461037d578060031936011261037d5760206040516127108152f35b503461037d578060031936011261037d576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b503461037d57602036600319011261037d576004356001600160401b03811161103d5760a0600319823603011261103d5760405191611b0583612847565b81600401356001600160401b03811161103d578201903660238301121561037d57602061043185608486611b4136600489013560248a01612c0d565b8352611b4f602482016127a5565b85840152611b5f604482016127a5565b60408401526064810135606084015201356080820152613607565b503461037d578060031936011261037d57602060405160ff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b503461037d576020610431611bcc3661289a565b91612a9a565b503461037d57604036600319011261037d57611bec612779565b611bf461278f565b6001600160a01b03818116929081169190838303611d9657611c1636826132ee565b156107aa575b611c258161347c565b828552601260205260096040862001805415611d875760135460405163014f3df960e71b81523060048201526001600160a01b0384811660248301529091602091839160449183918c91165af1908115611d7c578791611d3e575b5015611d2f57611cb291610ce9879286845260036020526001600160801b036040852054169581549485925530612eb6565b5060135484906001600160a01b0316803b1561103d5781809160046040518094819363a022985f60e01b83525af1611d1a575b505060407f91f628e8c7a6f75792ac4b71145861594f59fa4439e803548a394011b6c6bc2b918151908152336020820152a380f35b81611d2491612862565b610a9957835f611ce5565b6331a852bb60e01b8652600486fd5b90506020813d602011611d74575b81611d5960209383612862565b81010312611d7057611d6a90612a8d565b5f611c80565b8680fd5b3d9150611d4c565b6040513d89823e3d90fd5b636040212f60e11b8652600486fd5b611da7604051611577606082612862565b611c1c576282b42960e81b8552600485fd5b503461037d57604036600319011261037d57600435611dd661278f565b6013546001600160a01b0316330361036f5760208161035b847f8dd4664ff532261941b00d8312d1764002e0de40af594821e7a4c08e4f0b8c7094612f76565b503461037d57602036600319011261037d5760043580151580910361103d576013546001600160a01b031633036103f95760407f304c943633ec0da73778a23e6ffc08756b2e7a7e606e52ff88cf83933d95342f916016549060ff811660ff1983161760165560ff83519216151582526020820152a180f35b503461037d57611e9e366127c2565b9160ff6016541615611fe157611eb436836132ee565b15611fd35760135484906001600160a01b0316803b1561103d57816040518092630987df0360e01b8252818381611ef18b8b8b30600486016129bd565b03925af1801561078c57611fbe575b50506001600160a01b038116808552600760209081526040808720335f90815292529020549060018201611f3b575b5050610a6e9350612eb6565b848210611fa3578015611f8f573315611f7b5785604091610a6e975260076020522060018060a01b0333165f526020528360405f20910390555f80611f2f565b634a1406b160e11b86526004869052602486fd5b63e602df0560e01b86526004869052602486fd5b6064868684637dc7a0d960e11b835233600452602452604452fd5b81611fc891612862565b610a9957835f611f00565b6282b42960e81b8452600484fd5b636dbb04b560e01b8452600484fd5b503461037d578060031936011261037d57600e546040516001600160a01b039091168152602090f35b503461037d57602036600319011261037d57600435906001600160401b03821161037d573660238301121561037d57816004013561205681612883565b906120646040519283612862565b8082526024602083019160051b8501019236841161037d5750602460209401905b8382106120a0578461209684612a45565b6040519015158152f35b8480916120ac846127a5565b815201910190612085565b503461037d57602036600319011261037d57604080916120d5612779565b6120dd6129e8565b506001600160a01b0316815260036020908152828220546001600160801b031682526002905220815190612110826127fc565b80548083526001909101546001600160a01b0390811660209384019081528451928352511691810191909152f35b503461037d57602036600319011261037d5760406101409161215e612779565b81610120845161216d8161282b565b82815282602082015282868201528260608201528260808201528260a08201528260c08201528260e082015282610100820152015260018060a01b031681526012602052206040516121be8161282b565b81549182825260018101546020830190815260028201546040840190815260038301546060850190815260048401546080860190815260058501549160a0870192835260068601549360c0880194855260078701549560e08901968752610120600960088a0154996101008c019a8b5201549901988952604051998a525160208a01525160408901525160608801525160808701525160a08601525160c08501525160e08401525161010083015251610120820152f35b503461037d578060031936011261037d576020600854604051908152f35b503461165c576122a2366127c2565b6013549293929091906001600160a01b03163381900361232157803b1561165c575f6040518092630987df0360e01b82528183816122e689898d30600486016129bd565b03925af1801561231657612300575b506103f69293612eb6565b6103f693505f61230f91612862565b5f926122f5565b6040513d5f823e3d90fd5b6282b42960e81b5f5260045ffd5b3461165c57604036600319011261165c57612348612779565b6024359033156123c4576001600160a01b03169081156123b157335f52600760205260405f20825f526020528060405f20556040519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b634a1406b160e11b5f525f60045260245ffd5b63e602df0560e01b5f525f60045260245ffd5b3461165c57602036600319011261165c576123f0612ce5565b600435905f905f925f5493600154926001600160801b0384169360801c94600454905b84151580612530575b8061251d575b1561250d576001600160801b0386165f52600260205260405f209161246d89856040519561244f876127fc565b80548088526001909101546001600160a01b03166020880152613cf9565b918683116124b3579161249e816124986124a4946124906124aa97895190612cd8565b975190612cb7565b97612cd8565b96612cb7565b95612e99565b94939290612413565b9750508793955082946124d5939250604098918082105f14610c2d5750613cf9565b91826124eb575b50505082519182526020820152f35b90610c1d916124ff84612505969597612cd8565b95613cf9565b8380806124dc565b9550505091505060409250610c03565b50866001600160801b0387161115612422565b5081151561241c565b3461165c57602036600319011261165c576020610431612557612ce5565b601454906004356138f4565b3461165c575f36600319011261165c576040515f60095461258381612904565b808452906001811690811561260957506001146125ab575b610d8a83610d7681850382612862565b60095f9081527f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af939250905b8082106125ef57509091508101602001610d7661259b565b9192600181602092548385880101520191019092916125d7565b60ff191660208086019190915291151560051b84019091019150610d76905061259b565b3461165c57602036600319011261165c5760043563ffffffff60e01b811680910361165c57806020911590811561272a575b8115612719575b8115612708575b81156126f7575b81156126e6575b81156126d5575b81156126c4575b81156126b3575b81156126a2575b506040519015158152f35b63a219a02560e01b14905082612697565b6342fb809b60e11b81149150612690565b6336372b0760e01b81149150612689565b63e3bc4e6560e01b81149150612682565b63043eff2d60e51b8114915061267b565b6364ec41f760e01b81149150612674565b6305a0eefb60e31b8114915061266d565b631883ba3960e21b81149150612666565b6301ffc9a760e01b8114915061265f565b3461165c575f36600319011261165c576020906011548152f35b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b600435906001600160a01b038216820361165c57565b602435906001600160a01b038216820361165c57565b35906001600160a01b038216820361165c57565b3461165c575f80fd5b606090600319011261165c576004356001600160a01b038116810361165c57906024356001600160a01b038116810361165c579060443590565b604081019081106001600160401b0382111761281757604052565b634e487b7160e01b5f52604160045260245ffd5b61014081019081106001600160401b0382111761281757604052565b60a081019081106001600160401b0382111761281757604052565b90601f801991011681019081106001600160401b0382111761281757604052565b6001600160401b0381116128175760051b60200190565b606090600319011261165c57600435906024356001600160a01b038116810361165c57906044356001600160a01b038116810361165c5790565b9181601f8401121561165c578235916001600160401b03831161165c576020808501948460051b01011161165c57565b90600182811c92168015612932575b602083101461291e57565b634e487b7160e01b5f52602260045260245ffd5b91607f1691612913565b5f929181549161294b83612904565b80835292600181169081156129a0575060011461296757505050565b5f9081526020812093945091925b838310612986575060209250010190565b600181602092949394548385870101520191019190612975565b915050602093945060ff929192191683830152151560051b010190565b6001600160a01b03918216815291811660208301529091166040820152606081019190915260800190565b604051906129f5826127fc565b5f6020838281520152565b805115612a0d5760200190565b634e487b7160e01b5f52603260045260245ffd5b805160011015612a0d5760400190565b8051821015612a0d5760209160051b010190565b5f5b8151811015612a86576001600160a01b03612a628284612a31565b51165f52600b60205260ff60405f20541615612a8057600101612a47565b50505f90565b5050600190565b5190811515820361165c57565b90916001600160a01b03808416929082169190838303612ba557612abe36836132ee565b15612321575b612acd81613590565b612ad68261347c565b601354604051632fab172760e11b81529060209082906001600160a01b0316815f81612b08898d8a3060048601612bc8565b03925af1908115612316575f91612b6f575b5090612b60817fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d794612b5b612b54604096601454856138f4565b809a6135a9565b612f76565b8151908152856020820152a390565b9190506020823d602011612b9d575b81612b8b60209383612862565b8101031261165c579051612b60612b1a565b3d9150612b7e565b612bb6604051611577606082612862565b612ac4576282b42960e81b5f5260045ffd5b6001600160a01b039182168152602081019290925291821660408201529116606082015260800190565b6001600160401b03811161281757601f01601f191660200190565b929192612c1982612bf2565b91612c276040519384612862565b82948184528183011161165c578281602093845f960137010152565b601354604051630760168760e41b81523060048201526001600160a01b0392831660248201529160209183916044918391165afa908115612316575f91612c88575090565b90506020813d602011612caf575b81612ca360209383612862565b8101031261165c575190565b3d9150612c96565b91908203918211612cc457565b634e487b7160e01b5f52601160045260245ffd5b91908201809211612cc457565b601354604051639b9b942160e01b815230600482015290602090829060249082906001600160a01b03165afa908115612316575f91612c88575090565b60018060a01b03165f52601260205260405f20906003600183015492015415612d4757565b5f9150565b6001600160a01b03165f90815260126020526040902060030154908115612d4757565b916001600160a01b03828116929082169190838303612e7a57612d9236836132ee565b1561232157612ddd915b612da586613590565b612dae8161347c565b60208160018060a01b0360135416845f8a604051988995869485936309daab9960e11b85523060048601612bc8565b03925af180156123165786935f91612e42575b506040927fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d79492612b5b612e2b612e339460145490876138ff565b998a936135a9565b8151908682526020820152a390565b9350506020833d602011612e72575b81612e5e60209383612862565b8101031261165c5791518592906040612df0565b3d9150612e51565b612e8b604051611577606082612862565b1561232157612ddd91612d9c565b6001600160801b03166001600160801b038114612cc45760010190565b6001600160a01b0316908115612f63576001600160a01b0316918215612f5057815f52600660205260405f2054818110612f3757817fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92602092855f52600684520360405f2055845f526006825260405f20818154019055604051908152a3565b8263391434e360e21b5f5260045260245260445260645ffd5b63ec442f0560e01b5f525f60045260245ffd5b634b637e8f60e11b5f525f60045260245ffd5b612feb91612f8681601154612cd8565b6011556040516323b872dd60e01b60208201526001600160a01b0390921660248301523060448301526064808301919091528152612fc5608482612862565b7f0000000000000000000000000000000000000000000000000000000000000000613eef565b565b60105460ff165f60038210156132da576001821461302257600292935050146130165750600190565b61301f90612a45565b90565b5050600e546001600160a01b03169081156132cb578051156132bc576061831061329e5760405192608084018481106001600160401b03821117612817576040526060845260208401915f835260408501945f865260608101915f8352601f19840192848411612cc457602093358082528251036132ad5751604181029080820460411490151715612cc45780840190818511612cc457604001809111612cc45780851061329e576130d48186612cb7565b9085821161165c576130eb6130f39236905f612c0d565b845285612cb7565b83810190818111612cc45785821161165c573586528752845143101561328f575f5b8151811015613282576001600160a01b036131308284612a31565b511615613273576001600160a01b036131498284612a31565b5116805f52600f855260405f209081549161316383613daa565b9055613196855189516040519161317983612847565b825230898301528360408301528460608301526080820152613607565b917fe551f1469c2895fdd376c4517ff8a4cadba06443acbd1980104b6e27e2e11646895191875192604051914683528a830152604082015260806060820152806131e530946080830190612755565b0390a388516041830283810460411484151715612cc45761320591612cd8565b90895160018401808511612cc457604181029080820460411490151715612cc45761322f91612cd8565b80831161165c5787811161165c578280613250926132579550033691612c0d565b9089613f62565b1561326457600101613115565b638baa579f60e01b5f5260045ffd5b63d92e233d60e01b5f5260045ffd5b5050505050505050600190565b63b7ca31cd60e01b5f5260045ffd5b636cf4aa4f60e11b5f5260045ffd5b63512509d360e11b5f5260045ffd5b630b6e0c5f60e11b5f5260045ffd5b632057875960e21b5f5260045ffd5b634e487b7160e01b5f52602160045260245ffd5b5f9160ff601054169060038210156132da57600182146133325750600214613317575050600190565b6001600160a01b03168152600b602052604090205460ff1690565b600e546001600160a01b03938416945090921691905082156132735781156132cb576061811061329e5760618103818111612cc45781811161165c57818111612cc4576040198201828111612cc45780821161165c576133988284036040190183613d8e565b92811161165c578243101561328f578461346c92613472965f52600f6020527fe551f1469c2895fdd376c4517ff8a4cadba06443acbd1980104b6e27e2e1164660405f208054906133e882613daa565b90556134236040516133f981612847565b61340436865f612c0d565b8152306020820152856040820152826060820152886080820152613607565b96604051914683526020830152604082015260806060820152826080820152825f60a08301375f60a0848301015260a0813094601f80199101168101030190a360413691612c0d565b91613f62565b1561326457600190565b60018060a01b03163381141590816134a5575b5061349657565b6336abb4df60e11b5f5260045ffd5b5f90815260156020908152604080832033845290915281205460ff1615915061348f565b6001600160a01b03165f818152600360205260409020549192916001600160801b0316801561358157805f52600260205260405f20548085118015613579575b61356a5761351a8561352392612cb7565b94600454612cb7565b60045583613559575f5260026020525f60016040822082815501555f52600360205260405f206001600160801b03198154169055565b90505f5260026020528160405f2055565b633999656760e01b5f5260045ffd5b508015613509565b6333618a9160e21b5f5260045ffd5b6127101161359a57565b632ca2f52b60e11b5f5260045ffd5b6001600160a01b0316908115612f50577fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef6020826135ea5f94600854612cd8565b6008558484526006825260408420818154019055604051908152a3565b6042908051602081519101209060018060a01b036020820151169060018060a01b036040820151169060806060820151910151916040519360208501957fb78a071cab05828812909bd43bd7019c31f7c50fbdf8657efd4932bbe287e16d875260408601526060850152608084015260a083015260c082015260c0815261368f60e082612862565b51902061369a61402f565b906040519161190160f01b8352600283015260228201522090565b9190811015612a0d5760051b0190565b35801515810361165c5790565b356001600160a01b038116810361165c5790565b601354604051638304ff8f60e01b815230600482015290602090829060249082906001600160a01b03165afa8015612316575f90613742575b61372d915060055490612cd8565b6011549080821115612a805761301f91612cb7565b506020813d60201161376e575b8161375c60209383612862565b8101031261165c5761372d905161371f565b3d915061374f565b91925f5f9460045490851580156138ec575b6138df575f54600154966001600160801b0388169760801c908181115f146138d3575096979395975b6001600160801b0381168881116138bb575f52600260205260405f206137ff8385878d604051956137e1876127fc565b80548752600101546001600160a01b03166020870190815295613db8565b999092821561387e5792613830836138369361382b8a859761383c9960018060a01b039051168b61393d565b612cd8565b98612cd8565b9a612cb7565b96156138575761384b90612e99565b965b96979395976137b1565b939796505050506001600160801b039192505b166001600160801b03196001541617600155565b509a9594939297989150509794976138a35750505050506001600160801b039061386a565b90919295946138b59098949798612e99565b9661384d565b509396505050506001600160801b039192945061386a565b905096979395976137b1565b505050925050505f905f90565b508115613788565b9061301f9291613cf9565b919061390c828285613cf9565b928215613929570961391b5790565b60018101809111612cc45790565b634e487b7160e01b5f52601260045260245ffd5b92919060018060a01b031691825f52601260205260405f2090600982019081548015613a1857841161359a5760145461397691856138f4565b9461397f6136e6565b8611613a09577f4dd5187225a2ae5f5ea35ca7b1732180f848cc4b6f7dce34b4c5e9f384d77dec9360409360076139f76001600160801b03956139c48b600554612cd8565b600555600184016139d68c8254612cd8565b80915560038501916139e9878454612cd8565b809355611344878254612cb7565b910155835196875260208701521693a3565b63bb55fd2760e01b5f5260045ffd5b634ef1d5c560e01b5f5260045ffd5b9091906001600160a01b03168015612f6357805f52600660205260405f2054838110613a93576020845f94957fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef93858752600684520360408620558060085403600855604051908152a3565b915063391434e360e21b5f5260045260245260445260645ffd5b6005549081811015613ac757613ac291612cb7565b600555565b50505f600555565b9291936001840194600386549501948086549411613b3b57839180821115613b4a57613afa91612cb7565b935b84875511613b3b5780821115613b3357613b1591612cb7565b825515613b2b575b5415613b265750565b5f9055565b5f8155613b1d565b50505f613b15565b632206bead60e21b5f5260045ffd5b50505f93613afc565b90612fc5612feb92613b6783601154612cb7565b60115560405163a9059cbb60e01b60208201526001600160a01b039091166024820152604481019290925281606481015b03601f198101835282612862565b919290925f9083158015613cef575b613ce6575f949193945493600154946001600160801b0386169560801c955b87151580613cd3575b15613cbd576001600160801b0381165f52600260205260405f20613c0b83868b89604051956137e1876127fc565b959091928315613c845791613c3881613c3e9361382b8b88613c44999860018060a01b039051168b61393d565b98612cb7565b99612cb7565b9215613c5f57613c5390612e99565b955b9596939196613bd4565b9396505050506001600160801b03919250166001600160801b03196001541617600155565b509895949150509791909497613ca957505050506001600160801b039192935061386a565b9091929593613cb790612e99565b95613c55565b9350509450506001600160801b0391925061386a565b50866001600160801b0382161115613bdd565b50509150505f90565b5060045415613bb5565b9091828202915f1984820993838086109503948086039514613d805784831115613d7157829109815f0382168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b63227bc15360e01b5f5260045ffd5b505080925015613929570490565b359060208110613d9c575090565b5f199060200360031b1b1690565b5f198114612cc45760010190565b939491909294602085019360018060a01b0385511615613e3f578682613ddd92613cf9565b91855192838110613e37575b50828110613e2f575b508115613e225790613e09613e1f92829783613cf9565b94519351938114936001600160a01b03166134c9565b50565b505f945084935083925050565b91505f613df2565b92505f613de9565b505f9550859450600193505050565b600411156132da57565b60ff8114613e9e5760ff811690601f8211613e8f5760405191613e7c604084612862565b6020808452838101919036833783525290565b632cd44ac360e21b5f5260045ffd5b5060405161301f81613eb181600c61293c565b0382612862565b60ff8114613edc5760ff811690601f8211613e8f5760405191613e7c604084612862565b5060405161301f81613eb181600d61293c565b5f80613f179260018060a01b03169360208151910182865af1613f10614185565b9083614236565b8051908115159182613f3f575b5050613f2d5750565b635274afe760e01b5f5260045260245ffd5b819250906020918101031261165c576020613f5a9101612a8d565b155f80613f24565b90613f6d838261414b565b50909390613f7a81613e4e565b159384614019575b508315613f90575b50505090565b5f935090613b98613fc88594936040519283916020830195630b135d3f60e11b87526024840152604060448401526064830190612755565b51915afa613fd4614185565b8161400b575b81613fe9575b505f8080613f8a565b905060208180518101031261165c5760200151630b135d3f60e11b145f613fe0565b905060208151101590613fda565b6001600160a01b0384811691161493505f613f82565b307f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03161480614122575b1561408a577f000000000000000000000000000000000000000000000000000000000000000090565b60405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f000000000000000000000000000000000000000000000000000000000000000060408201527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a082015260a0815261411c60c082612862565b51902090565b507f00000000000000000000000000000000000000000000000000000000000000004614614061565b815191906041830361417b576141749250602082015190606060408401519301515f1a906141b4565b9192909190565b50505f9160029190565b3d156141af573d9061419682612bf2565b916141a46040519384612862565b82523d5f602084013e565b606090565b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841161422b579160209360809260ff5f9560405194855216868401526040830152606082015282805260015afa15612316575f516001600160a01b0381161561422157905f905f90565b505f906001905f90565b5050505f9160039190565b9061425a575080511561424b57805190602001fd5b630a12f52160e11b5f5260045ffd5b8151158061428b575b61426b575090565b639996b31560e01b5f9081526001600160a01b0391909116600452602490fd5b50803b1561426356fea2646970667358221220e39e9ad2cb2fbd0b267a0000e0e1432ec3ada7e1a021a8bb5287c20e41c3612264736f6c634300081b0033000000000000000000000000754704bc059f8c67012fed69bc8a327a5aafb603000000000000000000000000d0943c76ee287793559c1df82e5b2b858dd01ef30000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000c097ce7bc90715b34b9f1000000000000000000000000000000000000000000000000000000000000000000000001d48797065726974686d2044656c7461204e65757472616c205661756c7400000000000000000000000000000000000000000000000000000000000000000000066148595045520000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x6080806040526004361015610012575f80fd5b5f905f3560e01c90816301e1d1141461273b5750806301ffc9a71461262d57806306fdde031461256357806307a2d13a1461253957806308f45aff146123d7578063095ea7b31461232f5780630a28a4771461189757806317ee5d931461229357806318160ddd146122755780631bab58f51461213e5780631ef44e68146120b75780632246ced114612019578063238ac93314611ff057806323b872dd14611e8f57806324a16c6114611e1657806326535a8114611db95780632d0777d814611bd25780632e2d298414611bb8578063313ce56714611b7a57806335c1e48414611ac757806338d52e0f14611a825780633991998114611a655780633abb0604146118fd5780633d7849b7146118bb578063402d267d1461189c5780634cdad50614611897578063558a7297146117ed57806359c615d6146117ca578063623f50331461179e5780636c19e783146116d75780636e553f65146116ae57806370a0823114611675578063788cf2de146115aa5780637d41c86e146111915780637ecebe001461115857806384b0196e1461105c5780638726972914611041578063883fcc5614610e3b57806394bf804d14610e1257806395d89b4114610d2b57806399167fb414610cf25780639d81be4314610c7f5780639f30851214610c61578063a6bddd6314610af0578063a8c62e7614610ac7578063a8d5fd6514610aac578063a9059cbb146109e6578063b3d7f6b9146109bb578063b460af941461085c578063b6363cf214610804578063ba08765214610640578063bf919763146105f0578063c63d75b6146105b7578063c6e6f59214610407578063ce96cb7714610593578063d3b5dc3b14610575578063d63a8e1114610536578063d905777e14610517578063da39b3e7146104fd578063dc20c8ff146104df578063dd62ed3e1461048c578063e10d29ee1461045d578063eaed1d0714610439578063ef8b30f714610407578063f2b3c18f146103bd578063f5a23d8d146103805763fb53db6d146102ff575f80fd5b3461037d57604036600319011261037d5760043561031b61278f565b6013546001600160a01b0316330361036f5760208161035b847f48e891cea1a36b8bc4f1fb9fb7ae5508bf0edfee67aaeb354f1cfb8f62d68c8294613b53565b6040519384526001600160a01b031692a280f35b6282b42960e81b8352600483fd5b80fd5b503461037d57604036600319011261037d576020906009906040906001600160a01b036103ab61278f565b16815260128452200154604051908152f35b503461037d57604036600319011261037d576103d761278f565b6013546001600160a01b031633036103f9576103f690600435906135a9565b80f35b6282b42960e81b8252600482fd5b503461037d57602036600319011261037d576020610431610426612ce5565b6014546004356138f4565b604051908152f35b503461037d57604036600319011261037d57602061043161045861278f565b612d4c565b503461037d578060031936011261037d5760406001548151906001600160801b038116825260801c6020820152f35b503461037d57604036600319011261037d5760406104a8612779565b916104b161278f565b9260018060a01b031681526007602052209060018060a01b03165f52602052602060405f2054604051908152f35b503461037d578060031936011261037d576020600454604051908152f35b503461037d5760206104316105113661289a565b91612d6f565b503461037d57602036600319011261037d576020610431610458612779565b503461037d57602036600319011261037d5760209060ff906040906001600160a01b03610561612779565b168152600b84522054166040519015158152f35b503461037d578060031936011261037d576020601454604051908152f35b503461037d57602036600319011261037d5760206104316105b2612779565b612d22565b503461037d57602036600319011261037d5760206104316105de6105d9612779565b612c43565b6105e6612ce5565b90601454906138f4565b503461037d57602036600319011261037d576013546001600160a01b031633036106325760206104316106216136e6565b610629612ce5565b90600435613ba6565b6282b42960e81b8152600490fd5b503461037d5761064f3661289a565b9092916001600160a01b038281169290851691908284036107b85761067436826132ee565b156107aa575b61068382613590565b61068c8161347c565b61069581612d4c565b821161079b578385526012602052604085206006810154956106c56014546106be818a886138f4565b98866138ff565b6013549093906001600160a01b0316803b15610797576107019183918b8360405180968195829463d34cf33560e01b84528d3060048601612bc8565b03925af1801561078c57610777575b505060209661072f848061073e958a809661072a82613aad565b613acf565b6107398430613a27565b613b53565b60405190848252858201527ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db60403392a4604051908152f35b610782828092612862565b61037d5780610710565b6040513d84823e3d90fd5b8280fd5b63708a336b60e11b8552600485fd5b6282b42960e81b8552600485fd5b6107f26040516107c9606082612862565b600281526040366020830137846107df82612a00565b52856107ea82612a21565b523690612fed565b61067a576282b42960e81b8552600485fd5b503461037d57604036600319011261037d576040610820612779565b9161082961278f565b9260018060a01b031681526015602052209060018060a01b03165f52602052602060ff60405f2054166040519015158152f35b503461037d5761086b3661289a565b9092916001600160a01b038281169290851691908284036109985761089036826132ee565b156107aa575b61089f82613590565b6108a88161347c565b6108b181612d22565b821161079b578385526012602052604085206007810154956108db601454976106be818a886138f4565b6013549093906001600160a01b0316803b15610797576109179183918b836040518096819582946364a0366360e01b84528d3060048601612bc8565b03925af1801561078c57610983575b505060209661094061094a93888680809661072a82613aad565b6107398730613a27565b60405190815283858201527ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db60403392a4604051908152f35b61098e828092612862565b61037d5780610926565b6109a96040516107c9606082612862565b610896576282b42960e81b8552600485fd5b503461037d57602036600319011261037d5760206104316109da612ce5565b601454906004356138ff565b503461037d57604036600319011261037d57610a00612779565b6024359060ff6016541615610a9d57610a1936826132ee565b1561036f576013546001600160a01b0316803b15610a9957836040518092630987df0360e01b8252818381610a5489893330600486016129bd565b03925af18015610a8e57610a79575b610a6e838333612eb6565b602060405160018152f35b610a84848092612862565b6107975782610a63565b6040513d86823e3d90fd5b8380fd5b636dbb04b560e01b8352600483fd5b503461037d578060031936011261037d576020604051308152f35b503461037d578060031936011261037d576013546040516001600160a01b039091168152602090f35b503461037d57602036600319011261037d57610b0a612ce5565b6004358280815492600154946001600160801b0386169560801c96600454905b83151580610c58575b80610c45575b15610c34576001600160801b0388169485875260026020526040872095610b86898660405199610b688b6127fc565b8054808c526001909101546001600160a01b031660208c0152613cf9565b92868411610bcf57505081610ba2610bb09493610ba893612cd8565b95612cb7565b945190612cb7565b966001600160801b03610bc288612e99565b9716909790939293610b2a565b9895919760409b508693919a50859750610bf5959450508082105f14610c2d5750613cf9565b9182610c0f575b5050509091505b82519182526020820152f35b610c239450610c1d92613cf9565b90612cd8565b81905f8080610bfc565b9050613cf9565b965050505091505060409250610c03565b50886001600160801b0389161115610b39565b50811515610b33565b503461037d578060031936011261037d576020600554604051908152f35b503461037d57604036600319011261037d57610c99612779565b60135460243591906001600160a01b0316330361036f576001600160a01b038116835260036020526040832054610cee929190610ce9906001600160801b03168383610ce3612ce5565b9261393d565b6134c9565b5080f35b503461037d57604036600319011261037d57610d0c61278f565b6013546001600160a01b031633036103f9576103f69060043590613a27565b503461037d578060031936011261037d576040519080600a5490610d4e82612904565b8085529160018116908115610deb5750600114610d8e575b610d8a84610d7681860382612862565b604051918291602083526020830190612755565b0390f35b600a81527fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a8939250905b808210610dd157509091508101602001610d7682610d66565b919260018160209254838588010152019101909291610db8565b60ff191660208087019190915292151560051b85019092019250610d769150839050610d66565b503461037d57604036600319011261037d576020610431610e3161278f565b3390600435612d6f565b503461037d57604036600319011261037d576004356001600160801b03811680910361103d576024356001600160801b0381168091036107975781158015611034575b6110255760015460801c8111611016578190036001600160801b038111611002576001600160801b0360019116016001600160801b038111611002576001600160801b0316610ecc81612883565b610ed96040519182612862565b818152601f19610ee883612883565b01845b818110610fdf575050835b6001600160801b03811683811015610f84578085016001600160801b038111610f705791610f686001926001600160801b03809516895260026020526040892060405190610f43826127fc565b8054825285808060a01b03910154166020820152610f618288612a31565b5285612a31565b500116610ef6565b634e487b7160e01b87526011600452602487fd5b8286604051918291602083016020845282518091526020604085019301915b818110610fb1575050500390f35b8251805185526020908101516001600160a01b03168186015286955060409094019390920191600101610fa3565b602090604051610fee816127fc565b5f81525f8382015282828601015201610eeb565b634e487b7160e01b83526011600452602483fd5b632d0483c560e21b8352600483fd5b63561ce9bb60e01b8352600483fd5b50808211610e7e565b5080fd5b503461037d578060031936011261037d576020610431612ce5565b503461037d578060031936011261037d576110fc9061109a7f417574686f72697a61626c65000000000000000000000000000000000000000c613e58565b906110c47f3100000000000000000000000000000000000000000000000000000000000001613eb8565b90602061110a604051936110d88386612862565b8385525f368137604051968796600f60f81b885260e08589015260e0880190612755565b908682036040880152612755565b904660608601523060808601528260a086015284820360c08601528080855193848152019401925b82811061114157505050500390f35b835185528695509381019392810192600101611132565b503461037d57602036600319011261037d576020906040906001600160a01b03611180612779565b168152600f83522054604051908152f35b503461037d576111a03661289a565b9092916001600160a01b03808316929085169190838303611566576111c536876132ee565b156107aa575b3384141580611543575b611534576111e28661347c565b6111eb82613590565b838552600660205281604086205410801561152c575b61151d57604081869785611252985260126020526009838a2001611226868254612cd8565b905560018060a01b036013541690898451809a8195829463716f6e8d60e11b84528a3060048601612bc8565b03925af194851561151257869087966114cd575b50156113c85785948387526012602052604087206009810191825480156113b95785116113aa5760145461129a91866138f4565b916112a36136e6565b831161139b57847f1fdc681a13d8c5da54e301c7ce6542dcde4581e4725043fdab2db12ddc5745069460209a887f4dd5187225a2ae5f5ea35ca7b1732180f848cc4b6f7dce34b4c5e9f384d77dec6040888e9d9c9b9860076113616113789a6113116113909e600554612cd8565b60055560018401611323868254612cd8565b80915560038501916113368d8454612cd8565b8093556113448d8254612cb7565b90556113538260145483613cf9565b6006860155601454906138ff565b91015581519081528f8790820152a35b3090612eb6565b60408051338152602081019290925290918291820190565b0390a4604051908152f35b63bb55fd2760e01b8952600489fd5b632ca2f52b60e11b8952600489fd5b634ef1d5c560e01b8a5260048afd5b92919093507f1fdc681a13d8c5da54e301c7ce6542dcde4581e4725043fdab2db12ddc574506611390856113786001600160801b038960209a5086815260038b528160408220541680155f146114af5750600154600161142a8260801c612e99565b848116928580198360801b1691161782559289815260038e5260408120838619825416179055604080519161145e836127fc565b8883528f8301948c865281528f600290522090518155019060018060a01b039051166bffffffffffffffffffffffff60a01b8254161790555b6114a384600454612cd8565b60045516978897611371565b9060409082815260028d52206114c6858254612cd8565b9055611497565b9550506040853d60401161150a575b816114e960409383612862565b810103126115065760206114fc86612a8d565b950151945f611266565b8580fd5b3d91506114dc565b6040513d88823e3d90fd5b633999656760e01b8552600485fd5b508115611201565b63ccea9e6f60e01b8552600485fd5b50838552601560209081526040808720335f908152925290205460ff16156111d5565b611598604051611577606082612862565b6002815260403660208301378561158d82612a00565b52846107ea82612a21565b6111cb576282b42960e81b8552600485fd5b503461037d578060031936011261037d57600854601354604051638304ff8f60e01b8152306004820152919290602090839060249082906001600160a01b03165afa918215611668578192611630575b5050816116105750506020601454604051908152f35b60209161162261162b92601154612cb7565b601454906138f4565b610431565b9091506020813d602011611660575b8161164c60209383612862565b8101031261165c5751905f6115fa565b5f80fd5b3d915061163f565b50604051903d90823e3d90fd5b503461037d57602036600319011261037d576020906040906001600160a01b0361169d612779565b168152600683522054604051908152f35b503461037d57604036600319011261037d5760206104316116cd61278f565b3390600435612a9a565b503461037d57602036600319011261037d576116f1612779565b6013546001600160a01b031633036103f95760ff60105416600381101561178a5760010361177b576001600160a01b0316801561176c57600e80546001600160a01b0319811683179091556001600160a01b03167feeb293e1f8f3a9db91ade748726387ed1352ca78f5430c5f06fe3d1e1ad505798380a380f35b63d92e233d60e01b8252600482fd5b63fb61026d60e01b8252600482fd5b634e487b7160e01b83526021600452602483fd5b503461037d578060031936011261037d5760ff6010541660405190600381101561178a57602092508152f35b503461037d578060031936011261037d57602060ff601654166040519015158152f35b503461037d57604036600319011261037d57611807612779565b60243580151591828203610a99576001600160a01b0316923384146118885790604061185192338152601560205220845f5260205260405f209060ff801983541691151516179055565b6040519081527fceb576d9f15e4e200fdb5096d64d5dfd667e16def20c1eefd14256d8e3faa26760203392a3602060405160018152f35b63ccea9e6f60e01b8152600490fd5b6127b9565b503461037d57602036600319011261037d5760206104316105d9612779565b503461037d57602036600319011261037d576013546001600160a01b03163303610632576040610c036118ec6136e6565b6118f4612ce5565b90600435613776565b503461037d57604036600319011261037d576004356001600160401b03811161103d5761192e9036906004016128d4565b6024356001600160401b038111610a995761194d9036906004016128d4565b601354919290916001600160a01b031633036107aa5760ff601054166003811015611a5157600203611a4257818103611a3357845b81811061198d578580f35b806119dc6119a66119a160019487896136b5565b6136c5565b838060a01b036119bf6119ba85888c6136b5565b6136d2565b168952600b602052604089209060ff801983541691151516179055565b6119ea6119ba8285896136b5565b7fc5217903bd71390e046be1c1ee589f3af533c8fe5b67ee0a7dade2f8a853badd6020611a1b6119a185898b6136b5565b926040519315158452858060a01b031692a201611982565b63512509d360e11b8552600485fd5b63fb61026d60e01b8552600485fd5b634e487b7160e01b86526021600452602486fd5b503461037d578060031936011261037d5760206040516127108152f35b503461037d578060031936011261037d576040517f000000000000000000000000754704bc059f8c67012fed69bc8a327a5aafb6036001600160a01b03168152602090f35b503461037d57602036600319011261037d576004356001600160401b03811161103d5760a0600319823603011261103d5760405191611b0583612847565b81600401356001600160401b03811161103d578201903660238301121561037d57602061043185608486611b4136600489013560248a01612c0d565b8352611b4f602482016127a5565b85840152611b5f604482016127a5565b60408401526064810135606084015201356080820152613607565b503461037d578060031936011261037d57602060405160ff7f0000000000000000000000000000000000000000000000000000000000000006168152f35b503461037d576020610431611bcc3661289a565b91612a9a565b503461037d57604036600319011261037d57611bec612779565b611bf461278f565b6001600160a01b03818116929081169190838303611d9657611c1636826132ee565b156107aa575b611c258161347c565b828552601260205260096040862001805415611d875760135460405163014f3df960e71b81523060048201526001600160a01b0384811660248301529091602091839160449183918c91165af1908115611d7c578791611d3e575b5015611d2f57611cb291610ce9879286845260036020526001600160801b036040852054169581549485925530612eb6565b5060135484906001600160a01b0316803b1561103d5781809160046040518094819363a022985f60e01b83525af1611d1a575b505060407f91f628e8c7a6f75792ac4b71145861594f59fa4439e803548a394011b6c6bc2b918151908152336020820152a380f35b81611d2491612862565b610a9957835f611ce5565b6331a852bb60e01b8652600486fd5b90506020813d602011611d74575b81611d5960209383612862565b81010312611d7057611d6a90612a8d565b5f611c80565b8680fd5b3d9150611d4c565b6040513d89823e3d90fd5b636040212f60e11b8652600486fd5b611da7604051611577606082612862565b611c1c576282b42960e81b8552600485fd5b503461037d57604036600319011261037d57600435611dd661278f565b6013546001600160a01b0316330361036f5760208161035b847f8dd4664ff532261941b00d8312d1764002e0de40af594821e7a4c08e4f0b8c7094612f76565b503461037d57602036600319011261037d5760043580151580910361103d576013546001600160a01b031633036103f95760407f304c943633ec0da73778a23e6ffc08756b2e7a7e606e52ff88cf83933d95342f916016549060ff811660ff1983161760165560ff83519216151582526020820152a180f35b503461037d57611e9e366127c2565b9160ff6016541615611fe157611eb436836132ee565b15611fd35760135484906001600160a01b0316803b1561103d57816040518092630987df0360e01b8252818381611ef18b8b8b30600486016129bd565b03925af1801561078c57611fbe575b50506001600160a01b038116808552600760209081526040808720335f90815292529020549060018201611f3b575b5050610a6e9350612eb6565b848210611fa3578015611f8f573315611f7b5785604091610a6e975260076020522060018060a01b0333165f526020528360405f20910390555f80611f2f565b634a1406b160e11b86526004869052602486fd5b63e602df0560e01b86526004869052602486fd5b6064868684637dc7a0d960e11b835233600452602452604452fd5b81611fc891612862565b610a9957835f611f00565b6282b42960e81b8452600484fd5b636dbb04b560e01b8452600484fd5b503461037d578060031936011261037d57600e546040516001600160a01b039091168152602090f35b503461037d57602036600319011261037d57600435906001600160401b03821161037d573660238301121561037d57816004013561205681612883565b906120646040519283612862565b8082526024602083019160051b8501019236841161037d5750602460209401905b8382106120a0578461209684612a45565b6040519015158152f35b8480916120ac846127a5565b815201910190612085565b503461037d57602036600319011261037d57604080916120d5612779565b6120dd6129e8565b506001600160a01b0316815260036020908152828220546001600160801b031682526002905220815190612110826127fc565b80548083526001909101546001600160a01b0390811660209384019081528451928352511691810191909152f35b503461037d57602036600319011261037d5760406101409161215e612779565b81610120845161216d8161282b565b82815282602082015282868201528260608201528260808201528260a08201528260c08201528260e082015282610100820152015260018060a01b031681526012602052206040516121be8161282b565b81549182825260018101546020830190815260028201546040840190815260038301546060850190815260048401546080860190815260058501549160a0870192835260068601549360c0880194855260078701549560e08901968752610120600960088a0154996101008c019a8b5201549901988952604051998a525160208a01525160408901525160608801525160808701525160a08601525160c08501525160e08401525161010083015251610120820152f35b503461037d578060031936011261037d576020600854604051908152f35b503461165c576122a2366127c2565b6013549293929091906001600160a01b03163381900361232157803b1561165c575f6040518092630987df0360e01b82528183816122e689898d30600486016129bd565b03925af1801561231657612300575b506103f69293612eb6565b6103f693505f61230f91612862565b5f926122f5565b6040513d5f823e3d90fd5b6282b42960e81b5f5260045ffd5b3461165c57604036600319011261165c57612348612779565b6024359033156123c4576001600160a01b03169081156123b157335f52600760205260405f20825f526020528060405f20556040519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b634a1406b160e11b5f525f60045260245ffd5b63e602df0560e01b5f525f60045260245ffd5b3461165c57602036600319011261165c576123f0612ce5565b600435905f905f925f5493600154926001600160801b0384169360801c94600454905b84151580612530575b8061251d575b1561250d576001600160801b0386165f52600260205260405f209161246d89856040519561244f876127fc565b80548088526001909101546001600160a01b03166020880152613cf9565b918683116124b3579161249e816124986124a4946124906124aa97895190612cd8565b975190612cb7565b97612cd8565b96612cb7565b95612e99565b94939290612413565b9750508793955082946124d5939250604098918082105f14610c2d5750613cf9565b91826124eb575b50505082519182526020820152f35b90610c1d916124ff84612505969597612cd8565b95613cf9565b8380806124dc565b9550505091505060409250610c03565b50866001600160801b0387161115612422565b5081151561241c565b3461165c57602036600319011261165c576020610431612557612ce5565b601454906004356138f4565b3461165c575f36600319011261165c576040515f60095461258381612904565b808452906001811690811561260957506001146125ab575b610d8a83610d7681850382612862565b60095f9081527f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af939250905b8082106125ef57509091508101602001610d7661259b565b9192600181602092548385880101520191019092916125d7565b60ff191660208086019190915291151560051b84019091019150610d76905061259b565b3461165c57602036600319011261165c5760043563ffffffff60e01b811680910361165c57806020911590811561272a575b8115612719575b8115612708575b81156126f7575b81156126e6575b81156126d5575b81156126c4575b81156126b3575b81156126a2575b506040519015158152f35b63a219a02560e01b14905082612697565b6342fb809b60e11b81149150612690565b6336372b0760e01b81149150612689565b63e3bc4e6560e01b81149150612682565b63043eff2d60e51b8114915061267b565b6364ec41f760e01b81149150612674565b6305a0eefb60e31b8114915061266d565b631883ba3960e21b81149150612666565b6301ffc9a760e01b8114915061265f565b3461165c575f36600319011261165c576020906011548152f35b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b600435906001600160a01b038216820361165c57565b602435906001600160a01b038216820361165c57565b35906001600160a01b038216820361165c57565b3461165c575f80fd5b606090600319011261165c576004356001600160a01b038116810361165c57906024356001600160a01b038116810361165c579060443590565b604081019081106001600160401b0382111761281757604052565b634e487b7160e01b5f52604160045260245ffd5b61014081019081106001600160401b0382111761281757604052565b60a081019081106001600160401b0382111761281757604052565b90601f801991011681019081106001600160401b0382111761281757604052565b6001600160401b0381116128175760051b60200190565b606090600319011261165c57600435906024356001600160a01b038116810361165c57906044356001600160a01b038116810361165c5790565b9181601f8401121561165c578235916001600160401b03831161165c576020808501948460051b01011161165c57565b90600182811c92168015612932575b602083101461291e57565b634e487b7160e01b5f52602260045260245ffd5b91607f1691612913565b5f929181549161294b83612904565b80835292600181169081156129a0575060011461296757505050565b5f9081526020812093945091925b838310612986575060209250010190565b600181602092949394548385870101520191019190612975565b915050602093945060ff929192191683830152151560051b010190565b6001600160a01b03918216815291811660208301529091166040820152606081019190915260800190565b604051906129f5826127fc565b5f6020838281520152565b805115612a0d5760200190565b634e487b7160e01b5f52603260045260245ffd5b805160011015612a0d5760400190565b8051821015612a0d5760209160051b010190565b5f5b8151811015612a86576001600160a01b03612a628284612a31565b51165f52600b60205260ff60405f20541615612a8057600101612a47565b50505f90565b5050600190565b5190811515820361165c57565b90916001600160a01b03808416929082169190838303612ba557612abe36836132ee565b15612321575b612acd81613590565b612ad68261347c565b601354604051632fab172760e11b81529060209082906001600160a01b0316815f81612b08898d8a3060048601612bc8565b03925af1908115612316575f91612b6f575b5090612b60817fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d794612b5b612b54604096601454856138f4565b809a6135a9565b612f76565b8151908152856020820152a390565b9190506020823d602011612b9d575b81612b8b60209383612862565b8101031261165c579051612b60612b1a565b3d9150612b7e565b612bb6604051611577606082612862565b612ac4576282b42960e81b5f5260045ffd5b6001600160a01b039182168152602081019290925291821660408201529116606082015260800190565b6001600160401b03811161281757601f01601f191660200190565b929192612c1982612bf2565b91612c276040519384612862565b82948184528183011161165c578281602093845f960137010152565b601354604051630760168760e41b81523060048201526001600160a01b0392831660248201529160209183916044918391165afa908115612316575f91612c88575090565b90506020813d602011612caf575b81612ca360209383612862565b8101031261165c575190565b3d9150612c96565b91908203918211612cc457565b634e487b7160e01b5f52601160045260245ffd5b91908201809211612cc457565b601354604051639b9b942160e01b815230600482015290602090829060249082906001600160a01b03165afa908115612316575f91612c88575090565b60018060a01b03165f52601260205260405f20906003600183015492015415612d4757565b5f9150565b6001600160a01b03165f90815260126020526040902060030154908115612d4757565b916001600160a01b03828116929082169190838303612e7a57612d9236836132ee565b1561232157612ddd915b612da586613590565b612dae8161347c565b60208160018060a01b0360135416845f8a604051988995869485936309daab9960e11b85523060048601612bc8565b03925af180156123165786935f91612e42575b506040927fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d79492612b5b612e2b612e339460145490876138ff565b998a936135a9565b8151908682526020820152a390565b9350506020833d602011612e72575b81612e5e60209383612862565b8101031261165c5791518592906040612df0565b3d9150612e51565b612e8b604051611577606082612862565b1561232157612ddd91612d9c565b6001600160801b03166001600160801b038114612cc45760010190565b6001600160a01b0316908115612f63576001600160a01b0316918215612f5057815f52600660205260405f2054818110612f3757817fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92602092855f52600684520360405f2055845f526006825260405f20818154019055604051908152a3565b8263391434e360e21b5f5260045260245260445260645ffd5b63ec442f0560e01b5f525f60045260245ffd5b634b637e8f60e11b5f525f60045260245ffd5b612feb91612f8681601154612cd8565b6011556040516323b872dd60e01b60208201526001600160a01b0390921660248301523060448301526064808301919091528152612fc5608482612862565b7f000000000000000000000000754704bc059f8c67012fed69bc8a327a5aafb603613eef565b565b60105460ff165f60038210156132da576001821461302257600292935050146130165750600190565b61301f90612a45565b90565b5050600e546001600160a01b03169081156132cb578051156132bc576061831061329e5760405192608084018481106001600160401b03821117612817576040526060845260208401915f835260408501945f865260608101915f8352601f19840192848411612cc457602093358082528251036132ad5751604181029080820460411490151715612cc45780840190818511612cc457604001809111612cc45780851061329e576130d48186612cb7565b9085821161165c576130eb6130f39236905f612c0d565b845285612cb7565b83810190818111612cc45785821161165c573586528752845143101561328f575f5b8151811015613282576001600160a01b036131308284612a31565b511615613273576001600160a01b036131498284612a31565b5116805f52600f855260405f209081549161316383613daa565b9055613196855189516040519161317983612847565b825230898301528360408301528460608301526080820152613607565b917fe551f1469c2895fdd376c4517ff8a4cadba06443acbd1980104b6e27e2e11646895191875192604051914683528a830152604082015260806060820152806131e530946080830190612755565b0390a388516041830283810460411484151715612cc45761320591612cd8565b90895160018401808511612cc457604181029080820460411490151715612cc45761322f91612cd8565b80831161165c5787811161165c578280613250926132579550033691612c0d565b9089613f62565b1561326457600101613115565b638baa579f60e01b5f5260045ffd5b63d92e233d60e01b5f5260045ffd5b5050505050505050600190565b63b7ca31cd60e01b5f5260045ffd5b636cf4aa4f60e11b5f5260045ffd5b63512509d360e11b5f5260045ffd5b630b6e0c5f60e11b5f5260045ffd5b632057875960e21b5f5260045ffd5b634e487b7160e01b5f52602160045260245ffd5b5f9160ff601054169060038210156132da57600182146133325750600214613317575050600190565b6001600160a01b03168152600b602052604090205460ff1690565b600e546001600160a01b03938416945090921691905082156132735781156132cb576061811061329e5760618103818111612cc45781811161165c57818111612cc4576040198201828111612cc45780821161165c576133988284036040190183613d8e565b92811161165c578243101561328f578461346c92613472965f52600f6020527fe551f1469c2895fdd376c4517ff8a4cadba06443acbd1980104b6e27e2e1164660405f208054906133e882613daa565b90556134236040516133f981612847565b61340436865f612c0d565b8152306020820152856040820152826060820152886080820152613607565b96604051914683526020830152604082015260806060820152826080820152825f60a08301375f60a0848301015260a0813094601f80199101168101030190a360413691612c0d565b91613f62565b1561326457600190565b60018060a01b03163381141590816134a5575b5061349657565b6336abb4df60e11b5f5260045ffd5b5f90815260156020908152604080832033845290915281205460ff1615915061348f565b6001600160a01b03165f818152600360205260409020549192916001600160801b0316801561358157805f52600260205260405f20548085118015613579575b61356a5761351a8561352392612cb7565b94600454612cb7565b60045583613559575f5260026020525f60016040822082815501555f52600360205260405f206001600160801b03198154169055565b90505f5260026020528160405f2055565b633999656760e01b5f5260045ffd5b508015613509565b6333618a9160e21b5f5260045ffd5b6127101161359a57565b632ca2f52b60e11b5f5260045ffd5b6001600160a01b0316908115612f50577fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef6020826135ea5f94600854612cd8565b6008558484526006825260408420818154019055604051908152a3565b6042908051602081519101209060018060a01b036020820151169060018060a01b036040820151169060806060820151910151916040519360208501957fb78a071cab05828812909bd43bd7019c31f7c50fbdf8657efd4932bbe287e16d875260408601526060850152608084015260a083015260c082015260c0815261368f60e082612862565b51902061369a61402f565b906040519161190160f01b8352600283015260228201522090565b9190811015612a0d5760051b0190565b35801515810361165c5790565b356001600160a01b038116810361165c5790565b601354604051638304ff8f60e01b815230600482015290602090829060249082906001600160a01b03165afa8015612316575f90613742575b61372d915060055490612cd8565b6011549080821115612a805761301f91612cb7565b506020813d60201161376e575b8161375c60209383612862565b8101031261165c5761372d905161371f565b3d915061374f565b91925f5f9460045490851580156138ec575b6138df575f54600154966001600160801b0388169760801c908181115f146138d3575096979395975b6001600160801b0381168881116138bb575f52600260205260405f206137ff8385878d604051956137e1876127fc565b80548752600101546001600160a01b03166020870190815295613db8565b999092821561387e5792613830836138369361382b8a859761383c9960018060a01b039051168b61393d565b612cd8565b98612cd8565b9a612cb7565b96156138575761384b90612e99565b965b96979395976137b1565b939796505050506001600160801b039192505b166001600160801b03196001541617600155565b509a9594939297989150509794976138a35750505050506001600160801b039061386a565b90919295946138b59098949798612e99565b9661384d565b509396505050506001600160801b039192945061386a565b905096979395976137b1565b505050925050505f905f90565b508115613788565b9061301f9291613cf9565b919061390c828285613cf9565b928215613929570961391b5790565b60018101809111612cc45790565b634e487b7160e01b5f52601260045260245ffd5b92919060018060a01b031691825f52601260205260405f2090600982019081548015613a1857841161359a5760145461397691856138f4565b9461397f6136e6565b8611613a09577f4dd5187225a2ae5f5ea35ca7b1732180f848cc4b6f7dce34b4c5e9f384d77dec9360409360076139f76001600160801b03956139c48b600554612cd8565b600555600184016139d68c8254612cd8565b80915560038501916139e9878454612cd8565b809355611344878254612cb7565b910155835196875260208701521693a3565b63bb55fd2760e01b5f5260045ffd5b634ef1d5c560e01b5f5260045ffd5b9091906001600160a01b03168015612f6357805f52600660205260405f2054838110613a93576020845f94957fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef93858752600684520360408620558060085403600855604051908152a3565b915063391434e360e21b5f5260045260245260445260645ffd5b6005549081811015613ac757613ac291612cb7565b600555565b50505f600555565b9291936001840194600386549501948086549411613b3b57839180821115613b4a57613afa91612cb7565b935b84875511613b3b5780821115613b3357613b1591612cb7565b825515613b2b575b5415613b265750565b5f9055565b5f8155613b1d565b50505f613b15565b632206bead60e21b5f5260045ffd5b50505f93613afc565b90612fc5612feb92613b6783601154612cb7565b60115560405163a9059cbb60e01b60208201526001600160a01b039091166024820152604481019290925281606481015b03601f198101835282612862565b919290925f9083158015613cef575b613ce6575f949193945493600154946001600160801b0386169560801c955b87151580613cd3575b15613cbd576001600160801b0381165f52600260205260405f20613c0b83868b89604051956137e1876127fc565b959091928315613c845791613c3881613c3e9361382b8b88613c44999860018060a01b039051168b61393d565b98612cb7565b99612cb7565b9215613c5f57613c5390612e99565b955b9596939196613bd4565b9396505050506001600160801b03919250166001600160801b03196001541617600155565b509895949150509791909497613ca957505050506001600160801b039192935061386a565b9091929593613cb790612e99565b95613c55565b9350509450506001600160801b0391925061386a565b50866001600160801b0382161115613bdd565b50509150505f90565b5060045415613bb5565b9091828202915f1984820993838086109503948086039514613d805784831115613d7157829109815f0382168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b63227bc15360e01b5f5260045ffd5b505080925015613929570490565b359060208110613d9c575090565b5f199060200360031b1b1690565b5f198114612cc45760010190565b939491909294602085019360018060a01b0385511615613e3f578682613ddd92613cf9565b91855192838110613e37575b50828110613e2f575b508115613e225790613e09613e1f92829783613cf9565b94519351938114936001600160a01b03166134c9565b50565b505f945084935083925050565b91505f613df2565b92505f613de9565b505f9550859450600193505050565b600411156132da57565b60ff8114613e9e5760ff811690601f8211613e8f5760405191613e7c604084612862565b6020808452838101919036833783525290565b632cd44ac360e21b5f5260045ffd5b5060405161301f81613eb181600c61293c565b0382612862565b60ff8114613edc5760ff811690601f8211613e8f5760405191613e7c604084612862565b5060405161301f81613eb181600d61293c565b5f80613f179260018060a01b03169360208151910182865af1613f10614185565b9083614236565b8051908115159182613f3f575b5050613f2d5750565b635274afe760e01b5f5260045260245ffd5b819250906020918101031261165c576020613f5a9101612a8d565b155f80613f24565b90613f6d838261414b565b50909390613f7a81613e4e565b159384614019575b508315613f90575b50505090565b5f935090613b98613fc88594936040519283916020830195630b135d3f60e11b87526024840152604060448401526064830190612755565b51915afa613fd4614185565b8161400b575b81613fe9575b505f8080613f8a565b905060208180518101031261165c5760200151630b135d3f60e11b145f613fe0565b905060208151101590613fda565b6001600160a01b0384811691161493505f613f82565b307f0000000000000000000000007cd231120a60f500887444a9baf5e1bd753a5e596001600160a01b03161480614122575b1561408a577fdee778d2742d603008a5f5713568867ab87512af4c52b600cf6c5beed41aee3e90565b60405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527ff667a733ae93d1eed7f6346974ef74641f1bc18159f9cf208fa8e710699fc3a460408201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260a0815261411c60c082612862565b51902090565b507f000000000000000000000000000000000000000000000000000000000000008f4614614061565b815191906041830361417b576141749250602082015190606060408401519301515f1a906141b4565b9192909190565b50505f9160029190565b3d156141af573d9061419682612bf2565b916141a46040519384612862565b82523d5f602084013e565b606090565b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841161422b579160209360809260ff5f9560405194855216868401526040830152606082015282805260015afa15612316575f516001600160a01b0381161561422157905f905f90565b505f906001905f90565b5050505f9160039190565b9061425a575080511561424b57805190602001fd5b630a12f52160e11b5f5260045ffd5b8151158061428b575b61426b575090565b639996b31560e01b5f9081526001600160a01b0391909116600452602490fd5b50803b1561426356fea2646970667358221220e39e9ad2cb2fbd0b267a0000e0e1432ec3ada7e1a021a8bb5287c20e41c3612264736f6c634300081b0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000754704bc059f8c67012fed69bc8a327a5aafb603000000000000000000000000d0943c76ee287793559c1df82e5b2b858dd01ef30000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000c097ce7bc90715b34b9f1000000000000000000000000000000000000000000000000000000000000000000000001d48797065726974686d2044656c7461204e65757472616c205661756c7400000000000000000000000000000000000000000000000000000000000000000000066148595045520000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : asset_ (address): 0x754704Bc059F8C67012fEd69BC8A327a5aafb603
Arg [1] : strategy_ (address): 0xD0943c76ee287793559c1dF82E5B2B858Dd01Ef3
Arg [2] : sharesTransferable_ (bool): True
Arg [3] : permissionLevel_ (uint8): 0
Arg [4] : name_ (string): Hyperithm Delta Neutral Vault
Arg [5] : symbol_ (string): aHYPER
Arg [6] : precision_ (uint256): 1000000000000000000000000000000000000
-----Encoded View---------------
11 Constructor Arguments found :
Arg [0] : 000000000000000000000000754704bc059f8c67012fed69bc8a327a5aafb603
Arg [1] : 000000000000000000000000d0943c76ee287793559c1df82e5b2b858dd01ef3
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [4] : 00000000000000000000000000000000000000000000000000000000000000e0
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000120
Arg [6] : 0000000000000000000000000000000000c097ce7bc90715b34b9f1000000000
Arg [7] : 000000000000000000000000000000000000000000000000000000000000001d
Arg [8] : 48797065726974686d2044656c7461204e65757472616c205661756c74000000
Arg [9] : 0000000000000000000000000000000000000000000000000000000000000006
Arg [10] : 6148595045520000000000000000000000000000000000000000000000000000
Deployed Bytecode Sourcemap
1428:13276:31:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1428:13276:31;;;;;;;;:::i;:::-;2354:8:32;1428:13276:31;-1:-1:-1;;;;;1428:13276:31;2332:10:32;:31;2328:83;;1428:13276:31;7648:6:32;;;7670:31;7648:6;;:::i;:::-;1428:13276:31;;;;;-1:-1:-1;;;;;1428:13276:31;;7670:31:32;1428:13276:31;;2328:83:32;-1:-1:-1;;;2386:14:32;;1428:13276:31;2386:14:32;;1428:13276:31;;;;;;;;;;-1:-1:-1;;1428:13276:31;;;;;;5238:45;;1428:13276;;-1:-1:-1;;;;;1428:13276:31;;:::i;:::-;;;;5238:12;1428:13276;;;5238:45;1428:13276;;;;;;;;;;;;;;-1:-1:-1;;1428:13276:31;;;;;;:::i;:::-;2354:8:32;1428:13276:31;-1:-1:-1;;;;;1428:13276:31;2332:10:32;:31;2328:83;;7852:6;1428:13276:31;;;7852:6:32;;:::i;:::-;1428:13276:31;;2328:83:32;-1:-1:-1;;;2386:14:32;;1428:13276:31;2386:14:32;;1428:13276:31;;;;;;;-1:-1:-1;;1428:13276:31;;;;;6799:41:32;5674:12;;:::i;:::-;6813:9;1428:13276:31;;;6799:41:32;:::i;:::-;1428:13276:31;;;;;;;;;;;;;-1:-1:-1;;1428:13276:31;;;;;5464:21;1428:13276;;:::i;:::-;5464:21;:::i;1428:13276::-;;;;;;;;;;;;;;1569:6:33;1428:13276:31;;;;-1:-1:-1;;;;;1428:13276:31;;;;;;;;;;;;;;;;;;-1:-1:-1;;1428:13276:31;;;;;;;:::i;:::-;;;;:::i;:::-;;;;;;;;;;3952:11:4;1428:13276:31;;;3952:27:4;1428:13276:31;;;;;;-1:-1:-1;1428:13276:31;;;;;-1:-1:-1;1428:13276:31;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3486:14;1428:13276;;;:::i;:::-;3486:14;;:::i;1428:13276::-;;;;;;;-1:-1:-1;;1428:13276:31;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;1428:13276:31;;;;;;;;;;-1:-1:-1;;;;;1428:13276:31;;:::i;:::-;;;;636:55:23;1428:13276:31;;;;;;;;;;;;;;;;;;;;;;;;;;;1963:24:32;1428:13276:31;;;;;;;;;;;;;;-1:-1:-1;;1428:13276:31;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;-1:-1:-1;;1428:13276:31;;;;;6799:41:32;12471:22:31;1428:13276;;:::i;:::-;12471:22;:::i;:::-;12495:12;;:::i;:::-;1428:13276;6813:9:32;1428:13276:31;6799:41:32;;:::i;1428:13276:31:-;;;;;;;-1:-1:-1;;1428:13276:31;;;;2354:8:32;1428:13276:31;-1:-1:-1;;;;;1428:13276:31;2332:10:32;:31;2328:83;;1428:13276:31;9726:57;9756:12;;:::i;:::-;9770;;:::i;:::-;1428:13276;;;9726:57;:::i;2328:83:32:-;-1:-1:-1;;;2386:14:32;;1428:13276:31;;2386:14:32;1428:13276:31;;;;;;;;:::i;:::-;;;;-1:-1:-1;;;;;1428:13276:31;;;;;;;;;2585:27:32;;;1428:13276:31;;2633:33:32;1428:13276:31;2633:33:32;;:::i;:::-;2632:34;2628:61;;2581:348;5714:6:31;;;:::i;:::-;5748:10;;;:::i;:::-;5782:21;;;:::i;:::-;5773:30;;5769:61;;1428:13276;;;5868:12;1428:13276;;;;;5924:17;;;1428:13276;;6503:41:32;6524:9;1428:13276:31;6503:41:32;;;;;:::i;:::-;;;;:::i;:::-;6115:8:31;1428:13276;;;;-1:-1:-1;;;;;1428:13276:31;6115:62;;;;;;1428:13276;;;;;;;;;;;;;;;;6115:62;;6141:4;;1428:13276;6115:62;;;:::i;:::-;;;;;;;;;;;2581:348:32;6213:6:31;;1428:13276;6213:6;6282;6213;;6358;6213;;;;;;;:::i;:::-;6282;:::i;:::-;6321;6141:4;;6321:6;:::i;:::-;6358;:::i;:::-;1428:13276;;;;;;;;;;6381:58;1428:13276;6390:10;6381:58;;1428:13276;;;;;;6115:62;;;;;;:::i;:::-;1428:13276;;6115:62;;;;1428:13276;;;;;;;;;6115:62;1428:13276;;;5769:61;-1:-1:-1;;;5812:18:31;;1428:13276;6770:18;5812;2628:61:32;-1:-1:-1;;;2675:14:32;;1428:13276:31;2386:14:32;2675;2581:348;2863:32;1428:13276:31;;;;;;:::i;:::-;2762:1:32;1428:13276:31;;;;;;;;2778:27:32;;;;:::i;:::-;1428:13276:31;2819:24:32;;;;:::i;:::-;1428:13276:31;;2863:32:32;;:::i;:::-;2581:348;2858:60;-1:-1:-1;;;2904:14:32;;1428:13276:31;2386:14:32;2904;1428:13276:31;;;;;;;-1:-1:-1;;1428:13276:31;;;;;;;:::i;:::-;;;;:::i;:::-;;;;;;;;;;2065:62:32;1428:13276:31;;;2065:62:32;1428:13276:31;;;;;;-1:-1:-1;1428:13276:31;;;;;;-1:-1:-1;1428:13276:31;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;;;;1428:13276:31;;;;;;;;;2585:27:32;;;1428:13276:31;;2633:33:32;1428:13276:31;2633:33:32;;:::i;:::-;2632:34;2628:61;;2581:348;6670:6:31;;;:::i;:::-;6704:10;;;:::i;:::-;6738:23;;;:::i;:::-;6729:32;;6725:63;;1428:13276;;;6826:12;1428:13276;;;;;6884:19;;;1428:13276;;6799:41:32;6813:9;1428:13276:31;6799:41:32;;;;;;:::i;:::-;7081:8:31;1428:13276;;;;-1:-1:-1;;;;;1428:13276:31;7081:64;;;;;;1428:13276;;;;;;;;;;;;;;;;7081:64;;7109:4;;1428:13276;7081:64;;;:::i;:::-;;;;;;;;;;;2581:348:32;7181:6:31;;1428:13276;7181:6;7248:8;7326:6;7181;;;;;;;;;:::i;7248:8::-;7289:6;7109:4;;7289:6;:::i;7326:::-;1428:13276;;;;;;;;;;7349:58;1428:13276;7358:10;7349:58;;1428:13276;;;;;;7081:64;;;;;;:::i;:::-;1428:13276;;7081:64;;;2581:348:32;2863:32;1428:13276:31;;;;;;:::i;2863:32:32:-;2581:348;2858:60;-1:-1:-1;;;2904:14:32;;1428:13276:31;2386:14:32;2904;1428:13276:31;;;;;;;-1:-1:-1;;1428:13276:31;;;;;6503:41:32;13555:12:31;;:::i;:::-;6524:9:32;1428:13276:31;;;;6503:41:32;:::i;1428:13276:31:-;;;;;;;-1:-1:-1;;1428:13276:31;;;;;;:::i;:::-;;;;;5406:18:32;1428:13276:31;;5405:19:32;5401:55;;5471:25;1428:13276:31;5471:25:32;;:::i;:::-;5470:26;5466:53;;4781:8;1428:13276:31;-1:-1:-1;;;;;1428:13276:31;4781:58:32;;;;;1428:13276:31;;;;;;;;4781:58:32;;4756:10;;;4781:58;4756:10;;;4809:4;1428:13276:31;4781:58:32;;;:::i;:::-;;;;;;;;;;;1428:13276:31;3754:5:4;4756:10:32;;;3754:5:4;:::i;:::-;1428:13276:31;;;;;;;4781:58:32;;;;;;:::i;:::-;1428:13276:31;;4781:58:32;;;;1428:13276:31;;;;;;;;;4781:58:32;1428:13276:31;;;5401:55:32;-1:-1:-1;;;5433:23:32;;1428:13276:31;5433:23:32;;1428:13276:31;;;;;;;;;;;;;;;;7117:4:32;1428:13276:31;;;;;;;;;;;;;;;;1872:35:32;1428:13276:31;;;-1:-1:-1;;;;;1428:13276:31;;;;;;;;;;;;;;;-1:-1:-1;;1428:13276:31;;;;10640:12;;:::i;:::-;1428:13276;;9048:20:33;9070:18;1428:13276:31;;;;;;-1:-1:-1;;;;;1428:13276:31;;;;;;;;9310:862:33;;9317:13;;;:36;;;9310:862;9317:72;;;9310:862;9317:72;;;-1:-1:-1;;;;;1428:13276:31;;;;;;9441:15:33;1428:13276:31;;;;;;9510:48:33;1428:13276:31;;;;;;;;:::i;:::-;;;;;;;;;;;-1:-1:-1;;;;;1428:13276:31;;;;;9510:48:33;:::i;:::-;9577:25;;;;9573:412;;9999:27;;;;10081:34;9999:27;;10040:26;9999:27;;:::i;:::-;10040:26;;:::i;:::-;1428:13276:31;;10081:34:33;;:::i;:::-;10145:16;-1:-1:-1;;;;;10145:16:33;;;:::i;:::-;1428:13276:31;;9310:862:33;;;;;;;;9573:412;2641:13:19;;;;1428:13276:31;2641:13:19;;;;;;;;;;9717:45:33;2641:13:19;;;:5;;;;:13;:5;;;:13;9717:45:33;:::i;:::-;9785:13;;9781:167;;2641:13:19;9965:5:33;;;;;;9310:862;1428:13276:31;;;;;;;;;;9781:167:33;9873:56;9822:29;;9887:42;9822:29;9887:42;:::i;:::-;9873:56;;:::i;:::-;9781:167;;;;;;;2641:13:19;;;9717:45:33;:::i;9317:72::-;;;;;;;;;1428:13276:31;9317:72:33;;;;;1428:13276:31;;-1:-1:-1;;;;;1428:13276:31;;9357:32:33;;9317:72;;:36;9334:19;;;;9317:36;;1428:13276:31;;;;;;;;;;;;;;1239:32:33;1428:13276:31;;;;;;;;;;;;;;-1:-1:-1;;1428:13276:31;;;;;;:::i;:::-;2354:8:32;1428:13276:31;;;;;-1:-1:-1;;;;;1428:13276:31;2332:10:32;:31;2328:83;;-1:-1:-1;;;;;1428:13276:31;;;;9452:11;1428:13276;;;;;;9520:27;;1428:13276;;9497:12;;-1:-1:-1;;;;;1428:13276:31;;;9497:12;;:::i;:::-;;;:::i;:::-;9520:27;:::i;:::-;;1428:13276;;;;;;;;;-1:-1:-1;;1428:13276:31;;;;;;:::i;:::-;2354:8:32;1428:13276:31;-1:-1:-1;;;;;1428:13276:31;2332:10:32;:31;2328:83;;8006:6;1428:13276:31;;;8006:6:32;;:::i;1428:13276:31:-;;;;;;;;;;;;;;;;;2355:7:4;1428:13276:31;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;;;;;2355:7:4;1428:13276:31;;;;;-1:-1:-1;1428:13276:31;;;;;;;-1:-1:-1;1428:13276:31;;-1:-1:-1;1428:13276:31;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1428:13276:31;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1428:13276:31;;-1:-1:-1;1428:13276:31;;-1:-1:-1;1428:13276:31;;;;;;;;;-1:-1:-1;;1428:13276:31;;;;;3486:14;1428:13276;;:::i;:::-;4040:10;1428:13276;;;3486:14;:::i;1428:13276::-;;;;;;;-1:-1:-1;;1428:13276:31;;;;;;-1:-1:-1;;;;;1428:13276:31;;;;;;;;;-1:-1:-1;;;;;1428:13276:31;;;;;;;2056:10:33;;:25;;;;1428:13276:31;2052:52:33;;2124:6;1428:13276:31;;;2118:26:33;;2114:52;;1428:13276:31;;;-1:-1:-1;;;;;1428:13276:31;;;;-1:-1:-1;;;;;2124:6:33;2191:15;1428:13276:31;;-1:-1:-1;;;;;1428:13276:31;;;;-1:-1:-1;;;;;1428:13276:31;;;;:::i;:::-;;;;;;;:::i;:::-;;;;-1:-1:-1;;1428:13276:31;;;:::i;:::-;;;;;;;;;2271:13:33;;;;-1:-1:-1;;;;;1428:13276:31;;2286:7:33;;;;;;1428:13276:31;;;-1:-1:-1;;;;;1428:13276:31;;;;;2310:40:33;2124:6;1428:13276:31;-1:-1:-1;;;;;1428:13276:31;;;;;2324:15:33;1428:13276:31;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;2310:40:33;;;;:::i;:::-;;;;:::i;:::-;;1428:13276:31;;2271:13:33;;1428:13276:31;-1:-1:-1;;;1428:13276:31;;;;;;;;2286:7:33;;;1428:13276:31;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1428:13276:31;;;;;;;-1:-1:-1;1428:13276:31;;;;;;;;;2124:6:33;1428:13276:31;;;;;;;;;;;:::i;:::-;-1:-1:-1;1428:13276:31;;-1:-1:-1;1428:13276:31;;;;;;;;;;;;;;-1:-1:-1;;;1428:13276:31;;;;;;;;2114:52:33;-1:-1:-1;;;2153:13:33;;1428:13276:31;2153:13:33;;2052:52;-1:-1:-1;;;2090:14:33;;1428:13276:31;2090:14:33;;2056:25;2070:11;;;;2056:25;;1428:13276:31;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;6099:5:15;:41;:5;:41;:::i;:::-;6554:8;:47;:8;:47;:::i;:::-;1428:13276:31;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;:::i;:::-;5590:13:15;;1428:13276:31;;;;5625:4:15;1428:13276:31;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1428:13276:31;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1428:13276:31;;;;;;;;-1:-1:-1;;;;;1428:13276:31;;:::i;:::-;;;;1577:52:22;1428:13276:31;;;;;;;;;;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;;;;1428:13276:31;;;;;;;;;2585:27:32;;;1428:13276:31;;2633:33:32;1428:13276:31;2633:33:32;;:::i;:::-;2632:34;2628:61;;2581:348;9851:10;9842:19;;;:53;;;2581:348;9838:108;;4320:10:31;;;:::i;:::-;4357:6;;;:::i;:::-;1428:13276;;;3390:9:4;1428:13276:31;;;;;;;10543:25:32;:40;;;;2581:348;10539:98;;1428:13276:31;;;;;4556:66;1428:13276;;4439:12;1428:13276;;4474:26;1428:13276;;;4474:26;:36;1428:13276;;;4474:36;:::i;:::-;1428:13276;;;;;;;4556:8;1428:13276;;;;;;;;;;;;;;;4556:66;;4589:4;;1428:13276;4556:66;;;:::i;:::-;;;;;;;;;;;1428:13276;;4556:66;;;2581:348:32;-1:-1:-1;4632:221:31;;;4662:30;1428:13276;;;;4439:12;1428:13276;;;;;4474:26;11288;;1428:13276;;;11329:26;;11325:56;;11395:30;-1:-1:-1;11391:63:31;;6524:9:32;1428:13276:31;6503:41:32;;;;:::i;:::-;11557:12:31;;;:::i;:::-;11548:21;;11544:57;;1428:13276;5000:63;1428:13276;;;;12051:54;1428:13276;;;;;;;11856:19;11878:75;4895:6;1428:13276;11612:27;5000:63;1428:13276;11612:27;1428:13276;11612:27;:::i;:::-;;1428:13276;11649:17;;;:27;1428:13276;;;11649:27;:::i;:::-;1428:13276;;;11686:18;;;1428:13276;11686:28;1428:13276;;;11686:28;:::i;:::-;1428:13276;;;11724:36;1428:13276;;;11724:36;:::i;:::-;1428:13276;;11791:55;1428:13276;6524:9:32;1428:13276:31;11791:55;;:::i;:::-;3390:9:4;11771:17:31;;1428:13276;6524:9:32;1428:13276:31;11878:75;;:::i;:::-;11856:19;;1428:13276;;;;;;;;;;;;12051:54;4632:221;4589:4;4895:6;;:::i;:::-;1428:13276;;;9851:10:32;1428:13276:31;;1624:1;;;1428:13276;;;;;;;;1624:1;;;;5000:63;;;;1428:13276;;;;;;11544:57;-1:-1:-1;;;11578:23:31;;1428:13276;11578:23;;11391:63;-1:-1:-1;;;11434:20:31;;1428:13276;11434:20;;11325:56;-1:-1:-1;;;11364:17:31;;1428:13276;11364:17;;4632:221;4817:25;;;;;5000:63;;4817:25;4895:6;-1:-1:-1;;;;;4817:25:31;1428:13276;4817:25;2559:17:33;1428:13276:31;;;2609:11:33;1428:13276:31;;;;;;;;2646:15:33;;2642:321;1428:13276:31;;;;2691:6:33;1428:13276:31;2691:6:33;2689:22;1428:13276:31;;;2689:22:33;:::i;:::-;1428:13276:31;;;;;;;;;;;;;;;;;;;;2609:11:33;1428:13276:31;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;2804:37:33;;;1428:13276:31;;;;;;;2775:15:33;1428:13276:31;;;;;;;;;;;;;;;;;;;;;;;;;;2642:321:33;2973:27;1428:13276:31;;;2973:27:33;:::i;:::-;1428:13276:31;;;4632:221;;;;;2642:321:33;2872:22;1428:13276:31;2872:22:33;;1428:13276:31;;2908:15:33;1428:13276:31;;;2908:44:33;1428:13276:31;;;2908:44:33;:::i;:::-;1428:13276:31;;2642:321:33;;4556:66:31;;;;1428:13276;4556:66;;1428:13276;4556:66;;;;;;1428:13276;4556:66;;;:::i;:::-;;;1428:13276;;;;;;;;:::i;:::-;;;;4556:66;;;;1428:13276;;;;4556:66;;;-1:-1:-1;4556:66:31;;;1428:13276;;;;;;;;;10539:98:32;-1:-1:-1;;;10606:20:32;;1428:13276:31;10606:20:32;;10543:40;10572:11;;;10543:40;;9838:108;-1:-1:-1;;;9918:17:32;;1428:13276:31;3999:17:32;9918;9842:53;-1:-1:-1;1428:13276:31;;;9866:10:32;1428:13276:31;;;;;;;;9851:10:32;-1:-1:-1;1428:13276:31;;;;;;;;;;9865:30:32;9842:53;;2581:348;2863:32;1428:13276:31;;;;;;:::i;:::-;2762:1:32;1428:13276:31;;;;;;;;2778:27:32;;;;:::i;:::-;1428:13276:31;2819:24:32;;;;:::i;2863:32::-;2581:348;2858:60;-1:-1:-1;;;2904:14:32;;1428:13276:31;2386:14:32;2904;1428:13276:31;;;;;;;;;;;;;3222:12:4;1428:13276:31;6094:8:32;1428:13276:31;;;-1:-1:-1;;;6074:58:32;;6126:4;1428:13276:31;6074:58:32;;1428:13276:31;;;;;;;;6074:58:32;;1428:13276:31;;-1:-1:-1;;;;;1428:13276:31;6074:58:32;;;;;;;;;;;1428:13276:31;-1:-1:-1;;6149:11:32;;;1428:13276:31;;;6163:9:32;1428:13276:31;;;;;;;6149:99:32;1428:13276:31;;6176:24:32;6175:73;1428:13276:31;4571:12:32;1428:13276:31;6176:24:32;:::i;:::-;6209:9;1428:13276:31;6175:73:32;;:::i;:::-;6149:99;;6074:58;;;;1428:13276:31;6074:58:32;;1428:13276:31;6074:58:32;;;;;;1428:13276:31;6074:58:32;;;:::i;:::-;;;1428:13276:31;;;;;6074:58:32;;;;1428:13276:31;-1:-1:-1;1428:13276:31;;6074:58:32;;;-1:-1:-1;6074:58:32;;;1428:13276:31;;;;;;;;;;;;;;;;;;-1:-1:-1;;1428:13276:31;;;;;;;;-1:-1:-1;;;;;1428:13276:31;;:::i;:::-;;;;3390:9:4;1428:13276:31;;;;;;;;;;;;;;;;;-1:-1:-1;;1428:13276:31;;;;;2721:14;1428:13276;;:::i;:::-;3285:10;1428:13276;;;2721:14;:::i;1428:13276::-;;;;;;;-1:-1:-1;;1428:13276:31;;;;;;:::i;:::-;2354:8:32;1428:13276:31;-1:-1:-1;;;;;1428:13276:31;2332:10:32;:31;2328:83;;1428:13276:31;8700:15:32;1428:13276:31;;;;;;;;8719:19:32;8700:38;8696:76;;-1:-1:-1;;;;;1428:13276:31;1735:21:22;;1731:47;;7321:6;1428:13276:31;;-1:-1:-1;;;;;;1428:13276:31;;;;;;;-1:-1:-1;;;;;1428:13276:31;7368:33:22;;;;1428:13276:31;;1731:47:22;-1:-1:-1;;;1765:13:22;;1428:13276:31;1765:13:22;;8696:76:32;-1:-1:-1;;;8747:25:32;;1428:13276:31;9084:25:32;8747;1428:13276:31;-1:-1:-1;;;1428:13276:31;;;;;;;;;;;;;;;;;;;;;;644:38:21;1428:13276:31;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2184:30:32;1428:13276:31;;;;;;;;;;;;;;;;;-1:-1:-1;;1428:13276:31;;;;;;:::i;:::-;;;;;;;;;;;;-1:-1:-1;;;;;1428:13276:31;;3954:10:32;:22;;3950:77;;3954:10;1428:13276:31;4036:43:32;3954:10;;1428:13276:31;;4036:10:32;1428:13276:31;;;;-1:-1:-1;1428:13276:31;;;;-1:-1:-1;1428:13276:31;;;;;;;;;;;;;;;;4036:43:32;1428:13276:31;;;;;4094:43:32;1428:13276:31;3954:10:32;4094:43;;1428:13276:31;;;4154:4:32;1428:13276:31;;;3950:77:32;-1:-1:-1;;;3999:17:32;;1428:13276:31;;3999:17:32;1428:13276:31;;:::i;:::-;;;;;;;-1:-1:-1;;1428:13276:31;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;1428:13276:31;;;;2354:8:32;1428:13276:31;-1:-1:-1;;;;;1428:13276:31;2332:10:32;:31;2328:83;;1428:13276:31;10040:63;10076:12;;:::i;:::-;10090;;:::i;:::-;1428:13276;;;10040:63;:::i;1428:13276::-;;;;;;;-1:-1:-1;;1428:13276:31;;;;;;-1:-1:-1;;;;;1428:13276:31;;;;;;;;;;;:::i;:::-;;;-1:-1:-1;;;;;1428:13276:31;;;;;;;;;;;:::i;:::-;2354:8:32;1428:13276:31;;;;;-1:-1:-1;;;;;1428:13276:31;2332:10:32;:31;2328:83;;1428:13276:31;9031:15:32;1428:13276:31;;;;;;;;9050:25:32;9031:44;9027:82;;837:34:23;;;833:68;;917:13;932:19;;;;;;1428:13276:31;;;917:13:23;991:11;968:34;991:11;;1428:13276:31;991:11:23;;;;:::i;:::-;;:::i;:::-;1428:13276:31;;;;;976:11:23;;;;;;:::i;:::-;;:::i;:::-;1428:13276:31;;;968:7:23;1428:13276:31;;;;;;;;;;;;;;;;;;;;968:34:23;1032:11;;;;;;:::i;:::-;1021:36;1428:13276:31;1045:11:23;;;;;;:::i;:::-;1428:13276:31;;;;;;;;;;;;;;1021:36:23;;1428:13276:31;917:13:23;;833:68;-1:-1:-1;;;880:21:23;;1428:13276:31;880:21:23;;9027:82:32;-1:-1:-1;;;9084:25:32;;1428:13276:31;9084:25:32;;1428:13276:31;-1:-1:-1;;;1428:13276:31;;;;;;;;;;;;;;;;;;;;;;;;1780:6:32;1428:13276:31;;;;;;;;;;;;;;;;;;4452:6:32;-1:-1:-1;;;;;1428:13276:31;;;;;;;;;;;;;-1:-1:-1;;1428:13276:31;;;;;;-1:-1:-1;;;;;1428:13276:31;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;-1:-1:-1;;;;;1428:13276:31;;;;;;;;;;;;;;;;1957:29:22;1428:13276:31;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;1957:29:22;:::i;1428:13276:31:-;;;;;;;;;;;;;;;;;4311:19:32;1428:13276:31;;;;;;;;;;2721:14;1428:13276;;;:::i;:::-;2721:14;;:::i;1428:13276::-;;;;;;;-1:-1:-1;;1428:13276:31;;;;;;:::i;:::-;;;:::i;:::-;-1:-1:-1;;;;;1428:13276:31;;;;;;;;;2585:27:32;;;1428:13276:31;;2633:33:32;1428:13276:31;2633:33:32;;:::i;:::-;2632:34;2628:61;;2581:348;8302:10:31;;;:::i;:::-;1428:13276;;;8350:12;1428:13276;;8388:26;1428:13276;;;8388:26;1428:13276;;8388:31;8384:68;;8480:8;1428:13276;;;-1:-1:-1;;;8480:57:31;;8519:4;1428:13276;8480:57;;1428:13276;-1:-1:-1;;;;;1428:13276:31;;;;;;;;;;;;;;;;;8519:4;;1428:13276;8480:57;;;;;;;;;;;2581:348:32;8551:10:31;;8547:50;;8822:34;1428:13276;8798:13;1428:13276;;;;;8628:11;1428:13276;;-1:-1:-1;;;;;1428:13276:31;;;;;;;;;;;;8519:4;8798:13;:::i;8822:34::-;-1:-1:-1;8480:8:31;1428:13276;;;-1:-1:-1;;;;;1428:13276:31;8871:55;;;;;1428:13276;;;;;;;;;;;;;8871:55;;;;;;2581:348:32;1428:13276:31;;;8953:64;1428:13276;;;;;;9006:10;1428:13276;;;;8953:64;1428:13276;;8871:55;;;;;:::i;:::-;1428:13276;;8871:55;;;;8547:50;-1:-1:-1;;;8570:27:31;;1428:13276;8570:27;;8480:57;;;1428:13276;8480:57;;1428:13276;8480:57;;;;;;1428:13276;8480:57;;;:::i;:::-;;;1428:13276;;;;;;;:::i;:::-;8480:57;;;1428:13276;;;;8480:57;;;-1:-1:-1;8480:57:31;;;1428:13276;;;;;;;;;8384:68;-1:-1:-1;;;8428:24:31;;1428:13276;8428:24;;2581:348:32;2863:32;1428:13276:31;;;;;;:::i;2863:32:32:-;2581:348;2858:60;-1:-1:-1;;;2904:14:32;;1428:13276:31;2386:14:32;2904;1428:13276:31;;;;;;;-1:-1:-1;;1428:13276:31;;;;;;;;:::i;:::-;2354:8:32;1428:13276:31;-1:-1:-1;;;;;1428:13276:31;2332:10:32;:31;2328:83;;1428:13276:31;7442:6:32;;;7464:26;7442:6;;:::i;1428:13276:31:-;;;;;;;-1:-1:-1;;1428:13276:31;;;;;;;;;;;;;;2354:8:32;1428:13276:31;-1:-1:-1;;;;;1428:13276:31;2332:10:32;:31;2328:83;;1428:13276:31;8492:53:32;1428:13276:31;8409:18:32;1428:13276:31;;;;;;;;;;8409:18:32;1428:13276:31;;;;;;;;;;;;;;8492:53:32;1428:13276:31;;;;;;;;;;:::i;:::-;;;5406:18:32;1428:13276:31;;5405:19:32;5401:55;;5471:25;1428:13276:31;5471:25:32;;:::i;:::-;5470:26;5466:53;;5128:8;1428:13276:31;;;-1:-1:-1;;;;;1428:13276:31;5128:52:32;;;;;1428:13276:31;;;;;;;;5128:52:32;;5156:4;;;5128:52;5156:4;;;;1428:13276:31;5128:52:32;;;:::i;:::-;;;;;;;;;;;1428:13276:31;-1:-1:-1;;;;;;;1428:13276:31;;;;;3952:11:4;1428:13276:31;;;;;;;;735:10:10;-1:-1:-1;1428:13276:31;;;;;;;;;;10828:37:4;;10824:310;;1428:13276:31;5249:5:4;;;;;;:::i;10824:310::-;10885:24;;;10881:130;;10061:19;;10057:89;;735:10:10;10159:21:4;10155:90;;1428:13276:31;;;5249:5:4;1428:13276:31;;3952:11:4;1428:13276:31;;;;;;;;735:10:10;1428:13276:31;-1:-1:-1;1428:13276:31;;;;;-1:-1:-1;1428:13276:31;;;;;10824:310:4;;;;10155:90;-1:-1:-1;;;10203:31:4;;1428:13276:31;;;;;10203:31:4;;10057:89;-1:-1:-1;;;10103:32:4;;1428:13276:31;;;;;10103:32:4;;10881:130;1428:13276:31;10936:60:4;;;;;;;;735:10:10;1428:13276:31;;;;;;10936:60:4;5128:52:32;;;;;:::i;:::-;1428:13276:31;;5128:52:32;;;;5466:53;-1:-1:-1;;;5505:14:32;;1428:13276:31;2386:14:32;5505;5401:55;-1:-1:-1;;;5433:23:32;;1428:13276:31;5433:23:32;;1428:13276:31;;;;;;;;;;;;;1423:21:22;1428:13276:31;;;-1:-1:-1;;;;;1428:13276:31;;;;;;;;;;;;;;;-1:-1:-1;;1428:13276:31;;;;;;;-1:-1:-1;;;;;1428:13276:31;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;-1:-1:-1;;1428:13276:31;;;;;;;;;:::i;:::-;;;:::i;:::-;-1:-1:-1;;;;;;1428:13276:31;;;1813:11:33;1428:13276:31;;;;;;;;-1:-1:-1;;;;;1428:13276:31;;;1797:15:33;1428:13276:31;;;;;;;;;:::i;:::-;;;;;;;;;;;-1:-1:-1;;;;;1428:13276:31;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1428:13276:31;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7268:12:32;1428:13276:31;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3222:12:4;1428:13276:31;;;;;;;;;;;;;;;:::i;:::-;2354:8:32;1428:13276:31;;;;;;;-1:-1:-1;;;;;1428:13276:31;2332:10:32;:31;;;2328:83;;8165:52;;;;;1428:13276:31;;;;;;;;8165:52:32;;8193:4;;;8165:52;8193:4;;;;1428:13276:31;8165:52:32;;;:::i;:::-;;;;;;;;;;;1428:13276:31;8247:6:32;;;;;:::i;8165:52::-;8247:6;8165:52;;1428:13276:31;8165:52:32;;;:::i;:::-;1428:13276:31;8165:52:32;;;;1428:13276:31;;;;;;;;;2328:83:32;2386:14;;;1428:13276:31;2386:14:32;1428:13276:31;;2386:14:32;1428:13276:31;;;;;;-1:-1:-1;;1428:13276:31;;;;;;:::i;:::-;;;735:10:10;;10061:19:4;10057:89;;-1:-1:-1;;;;;1428:13276:31;;10159:21:4;;10155:90;;735:10:10;1428:13276:31;;10254:11:4;1428:13276:31;;;;;;;;;;;;;;;;;;;;10333:31:4;1428:13276:31;735:10:10;10333:31:4;;1428:13276:31;;;;;;;10155:90:4;10203:31;;;1428:13276:31;10203:31:4;1428:13276:31;;;;;10203:31:4;10057:89;10103:32;;;1428:13276:31;10103:32:4;1428:13276:31;;;;;10103:32:4;1428:13276:31;;;;;;-1:-1:-1;;1428:13276:31;;;;10384:12;;:::i;:::-;1428:13276;;10350:47;1428:13276;7702:18:33;1428:13276:31;;;;;;;;-1:-1:-1;;;;;1428:13276:31;;;;;;;;7940:890:33;;7947:13;;;:36;;;7940:890;7947:70;;;7940:890;7947:70;;;-1:-1:-1;;;;;1428:13276:31;;;;8069:15:33;1428:13276:31;;;;;;8137:48:33;1428:13276:31;;;;;;;;:::i;:::-;;;;;;;;;;;-1:-1:-1;;;;;1428:13276:31;;;;;8137:48:33;:::i;:::-;8204:25;;;;8200:411;;1428:13276:31;8722:27:33;1428:13276:31;8673:34:33;8763:26;1428:13276:31;8625:34:33;8804:15;1428:13276:31;;;8625:34:33;;:::i;:::-;1428:13276:31;;8673:34:33;;:::i;:::-;8722:27;;:::i;:::-;8763:26;;:::i;:::-;8804:15;;:::i;:::-;7940:890;;;;;;8200:411;2641:13:19;;;;;;;;;8344:45:33;2641:13:19;;;1428:13276:31;2641:13:19;;:5;;;:13;:5;;;:13;8344:45:33;:::i;:::-;8412:13;;8408:166;;2641:13:19;8591:5:33;;;1428:13276:31;;;;;;;;;;8408:166:33;8449:28;8513:42;8449:28;;;8499:56;8449:28;;;;:::i;:::-;8513:42;;:::i;8499:56::-;8408:166;;;;;7947:70;;;;;;;;1428:13276:31;7947:70:33;;;;;1428:13276:31;;-1:-1:-1;;;;;1428:13276:31;;7987:30:33;;7947:70;;:36;7964:19;;;;7947:36;;1428:13276:31;;;;;;-1:-1:-1;;1428:13276:31;;;;;6503:41:32;5863:12;;:::i;:::-;6524:9;1428:13276:31;;;;6503:41:32;:::i;1428:13276:31:-;;;;;;-1:-1:-1;;1428:13276:31;;;;;;;2151:5:4;1428:13276:31;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;2151:5:4;1428:13276:31;;;;;;;-1:-1:-1;1428:13276:31;;;;;;;-1:-1:-1;1428:13276:31;;-1:-1:-1;1428:13276:31;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1428:13276:31;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1428:13276:31;;-1:-1:-1;1428:13276:31;;;;;;;;-1:-1:-1;;1428:13276:31;;;;;;;;;;;;;;;;14113:61;1428:13276;14113:61;;:105;;;;;1428:13276;14113:166;;;;1428:13276;14113:221;;;;1428:13276;14113:287;;;;1428:13276;14113:332;;;;1428:13276;14113:400;;;;1428:13276;14113:443;;;;1428:13276;14113:519;;;;1428:13276;14113:582;;;;1428:13276;;;;;;;;;;14113:582;-1:-1:-1;;;14648:47:31;;-1:-1:-1;14113:582:31;;;:519;-1:-1:-1;;;14572:60:31;;;-1:-1:-1;14113:519:31;;:443;-1:-1:-1;;;14517:39:31;;;-1:-1:-1;14113:443:31;;:400;-1:-1:-1;;;14461:52:31;;;-1:-1:-1;14113:400:31;;:332;-1:-1:-1;;;14404:41:31;;;-1:-1:-1;14113:332:31;;:287;-1:-1:-1;;;14350:50:31;;;-1:-1:-1;14113:287:31;;:221;-1:-1:-1;;;14283:51:31;;;-1:-1:-1;14113:221:31;;:166;-1:-1:-1;;;14234:45:31;;;-1:-1:-1;14113:166:31;;:105;-1:-1:-1;;;14178:40:31;;;-1:-1:-1;14113:105:31;;1428:13276;;;;;;-1:-1:-1;;1428:13276:31;;;;;;4571:12:32;1428:13276:31;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1428:13276:31;;;;;;;;-1:-1:-1;;1428:13276:31;;;;:::o;:::-;;;;-1:-1:-1;;;;;1428:13276:31;;;;;;:::o;:::-;;;;-1:-1:-1;;;;;1428:13276:31;;;;;;:::o;:::-;;;-1:-1:-1;;;;;1428:13276:31;;;;;;:::o;:::-;;;;-1:-1:-1;1428:13276:31;;;;;;;;;;;;;-1:-1:-1;;;;;1428:13276:31;;;;;;;;;-1:-1:-1;;;;;1428:13276:31;;;;;;;;;;:::o;:::-;;;;;;;-1:-1:-1;;;;;1428:13276:31;;;;;;;:::o;:::-;;;;-1:-1:-1;1428:13276:31;;;;;-1:-1:-1;1428:13276:31;;;;;;;;-1:-1:-1;;;;;1428:13276:31;;;;;;;:::o;:::-;;;;;;;-1:-1:-1;;;;;1428:13276:31;;;;;;;:::o;:::-;;;;;;;;;;;;;-1:-1:-1;;;;;1428:13276:31;;;;;;;:::o;:::-;-1:-1:-1;;;;;1428:13276:31;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;-1:-1:-1;;;;;1428:13276:31;;;;;;;;;-1:-1:-1;;;;;1428:13276:31;;;;;;;:::o;:::-;;;;;;;;;;;;;-1:-1:-1;;;;;1428:13276:31;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;:::o;:::-;-1:-1:-1;1428:13276:31;;;;;;;;-1:-1:-1;1428:13276:31;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;-1:-1:-1;;;;;1428:13276:31;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;:::i;:::-;-1:-1:-1;1428:13276:31;;;;;;;:::o;:::-;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;2828:1:32;1428:13276:31;;;;;;;:::o;:::-;;;;;;;;;;;;;;;:::o;1139:277:23:-;1428:13276:31;1229:13:23;1428:13276:31;;1244:19:23;;;;;-1:-1:-1;;;;;1293:11:23;;;;:::i;:::-;1428:13276:31;;;;1285:7:23;1428:13276:31;;;;;;;;1284:21:23;1280:39;;1428:13276:31;;1229:13:23;;1280:39;1307:12;;1428:13276:31;1307:12:23;:::o;1244:19::-;;;1428:13276:31;1139:277:23;:::o;1428:13276:31:-;;;;;;;;;;:::o;2510:436:32:-;;;-1:-1:-1;;;;;1428:13276:31;;;;;;;;2510:436:32;2585:27;;;1428:13276:31;;2633:33:32;2657:8;2633:33;;:::i;:::-;2632:34;2628:61;;2581:348;2767:6:31;;;:::i;:::-;2801:10;;;:::i;:::-;2839:8;1428:13276;;;-1:-1:-1;;;2839:63:31;;1428:13276;2839:63;;1428:13276;;-1:-1:-1;;;;;1428:13276:31;;;;2839:63;2866:4;;;;2839:63;;;;:::i;:::-;;;;;;;;;;1428:13276;2839:63;;;2581:348:32;1428:13276:31;;3038:6;1428:13276;3061:45;1428:13276;3000:6;6799:41:32;1428:13276:31;;6813:9:32;1428:13276:31;6799:41:32;;:::i;:::-;3000:6:31;;;:::i;:::-;3038;:::i;:::-;1428:13276;;;;;;2839:63;1428:13276;;;3061:45;2510:436:32;:::o;2839:63:31:-;;;;;;;;;;;;;;1428:13276;2839:63;;;:::i;:::-;;;1428:13276;;;;;;3038:6;2839:63;;;;;-1:-1:-1;2839:63:31;;2581:348:32;2863:32;1428:13276:31;;;;;;:::i;2863:32:32:-;2581:348;2858:60;2386:14;;;1428:13276:31;2904:14:32;;1428:13276:31;2904:14:32;1428:13276:31;-1:-1:-1;;;;;1428:13276:31;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;-1:-1:-1;;;;;1428:13276:31;;;;;;-1:-1:-1;;1428:13276:31;;;;:::o;:::-;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;-1:-1:-1;1428:13276:31;;;;;;:::o;12147:164::-;12258:8;1428:13276;;;-1:-1:-1;;;12258:46:31;;12286:4;12258:46;;;1428:13276;-1:-1:-1;;;;;1428:13276:31;;;;;;;;12258:46;;1428:13276;;;;;;;12258:46;;;;;;;-1:-1:-1;12258:46:31;;;12246:58;12147:164;:::o;12258:46::-;;;;;;;;;;;;;1428:13276;12258:46;;;:::i;:::-;;;1428:13276;;;;;12147:164;:::o;12258:46::-;;;-1:-1:-1;12258:46:31;;1428:13276;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;:::o;6891:110:32:-;6960:8;1428:13276:31;;;-1:-1:-1;;;6960:34:32;;6988:4;6960:34;;;1428:13276:31;;;;;;6960:34:32;;1428:13276:31;;-1:-1:-1;;;;;1428:13276:31;6960:34:32;;;;;;;-1:-1:-1;6960:34:32;;;6953:41;6891:110;:::o;12840:244:31:-;1428:13276;;;;;;-1:-1:-1;1428:13276:31;12967:12;1428:13276;;;-1:-1:-1;1428:13276:31;13013:17;13044:18;13013:17;;;1428:13276;13044:18;;1428:13276;13044:23;13040:37;;12840:244::o;13040:37::-;-1:-1:-1;;;13069:8:31:o;12571:234::-;-1:-1:-1;;;;;1428:13276:31;-1:-1:-1;1428:13276:31;;;12696:12;1428:13276;;;;;12742:18;;1428:13276;;12774:14;;12770:28;;12571:234::o;2510:436:32:-;;-1:-1:-1;;;;;1428:13276:31;;;;;;;;2510:436:32;2585:27;;;1428:13276:31;;2633:33:32;2657:8;2633:33;;:::i;:::-;2632:34;2628:61;;3604:60:31;2581:348:32;;3532:6:31;;;:::i;:::-;3566:10;;;:::i;:::-;3604:60;1428:13276;;;;;;3604:8;1428:13276;;;;;;;;;;;;;;;;;3604:60;;3628:4;3604:60;;;;:::i;:::-;;;;;;;;;;;1428:13276;3604:60;;;2581:348:32;1428:13276:31;;;3822:45;1428:13276;;3761:6;6503:41:32;3799:6:31;1428:13276;6524:9:32;1428:13276:31;6503:41:32;;;:::i;:::-;3761:6:31;;;;:::i;3799:::-;1428:13276;;;;;;3604:60;1428:13276;;;3822:45;2510:436:32;:::o;3604:60:31:-;;;;;;;;;;;;;;1428:13276;3604:60;;;:::i;:::-;;;1428:13276;;;;;;;;;;3604:60;;;;;-1:-1:-1;3604:60:31;;2581:348:32;2863:32;1428:13276:31;;;;;;:::i;2863:32:32:-;2862:33;2858:60;;3604::31;2581:348:32;;;1428:13276:31;-1:-1:-1;;;;;1428:13276:31;-1:-1:-1;;;;;1428:13276:31;;;;;;;:::o;5656:300:4:-;-1:-1:-1;;;;;1428:13276:31;;5739:18:4;;5735:86;;-1:-1:-1;;;;;1428:13276:31;;5834:16:4;;5830:86;;1428:13276:31;5755:1:4;1428:13276:31;6570:9:4;1428:13276:31;;;5755:1:4;1428:13276:31;;6603:19:4;;;6599:115;;1428:13276:31;7346:25:4;1428:13276:31;;;;5755:1:4;1428:13276:31;6570:9:4;1428:13276:31;;;;5755:1:4;1428:13276:31;;;5755:1:4;1428:13276:31;7284:9:4;1428:13276:31;;;5755:1:4;1428:13276:31;;;;;;;;;;;;7346:25:4;5656:300::o;6599:115::-;6649:50;;;;5755:1;6649:50;;1428:13276:31;;;;;;5755:1:4;6649:50;5830:86;5873:32;;;5755:1;5873:32;5755:1;5873:32;1428:13276:31;;5755:1:4;5873:32;5735:86;5780:30;;;5755:1;5780:30;5755:1;5780:30;1428:13276:31;;5755:1:4;5780:30;9238:170:32;1829:53:8;9238:170:32;9315:22;1428:13276:31;9315:22:32;1428:13276:31;9315:22:32;:::i;:::-;;1428:13276:31;;;-1:-1:-1;;;1829:53:8;;;;-1:-1:-1;;;;;1428:13276:31;;;1829:53:8;;;1428:13276:31;9387:4:32;1428:13276:31;;;;;;;;;;;;1829:53:8;;;;1428:13276:31;1829:53:8;:::i;:::-;9347:6:32;1829:53:8;:::i;:::-;9238:170:32:o;1229:354:21:-;1366:15;1428:13276:31;;;;;;;;;;1411:19:21;1396:34;;1392:77;;1499:25;1428:13276:31;;;1484:40:21;;1480:74;;1565:11;1411:19;1229:354;:::o;1480:74::-;1533:21;;;:::i;:::-;1526:28;:::o;1392:77::-;-1:-1:-1;;4057:6:22;1428:13276:31;-1:-1:-1;;;;;1428:13276:31;;4078:21:22;;4074:49;;1428:13276:31;;4137:20:22;4133:53;;1428:13276:31;4200:35:22;;4196:70;;1428:13276:31;;;;;;;;;-1:-1:-1;;;;;1428:13276:31;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5044:37:22;5040:71;;1428:13276:31;1211:2:22;1428:13276:31;;;;;;1211:2:22;1428:13276:31;;;;;;;;;;;;;;;;;;;;;;;5240:32:22;;;5236:67;;5347:32;;;;:::i;:::-;1428:13276:31;;;;;;;5422:32:22;1428:13276:31;;;-1:-1:-1;1428:13276:31;:::i;:::-;5314:66:22;;5422:32;;:::i;:::-;1428:13276:31;;;;;;;;;;;;;;;;;;;;;4360:12:22;:36;;4356:73;;-1:-1:-1;4481:3:22;1428:13276:31;;4460:19:22;;;;;-1:-1:-1;;;;;4504:11:22;;;;:::i;:::-;1428:13276:31;;4504:25:22;4500:51;;-1:-1:-1;;;;;4594:11:22;;;;:::i;:::-;1428:13276:31;;;-1:-1:-1;1428:13276:31;5909:6:22;1428:13276:31;;;-1:-1:-1;1428:13276:31;;;;5909:17:22;;;;:::i;:::-;1428:13276:31;;5954:291:22;6032:21;;1428:13276:31;;;;;;;;:::i;:::-;;;6096:4:22;5985:250;;;1428:13276:31;5985:250:22;1428:13276:31;5985:250:22;;1428:13276:31;5985:250:22;1428:13276:31;5985:250:22;;1428:13276:31;;5985:250:22;;1428:13276:31;5954:291:22;:::i;:::-;1428:13276:31;6261:131:22;1428:13276:31;;6361:21:22;;;1428:13276:31;;;6293:13:22;;1428:13276:31;;;;;;;;;;;;;;;6096:4:22;1428:13276:31;6096:4:22;1428:13276:31;;;;;;:::i;:::-;6261:131:22;;;1428:13276:31;;1211:2:22;1428:13276:31;;;;;1211:2:22;1428:13276:31;;;;;;;6451:50:22;;;:::i;:::-;1428:13276:31;;;1411:19:21;1428:13276:31;;;;;;;1211:2:22;1428:13276:31;;;;;;1211:2:22;1428:13276:31;;;;;;;6502:56:22;;;:::i;:::-;1428:13276:31;;;;;;;;;;;;;;6586:64:22;1428:13276:31;;;;;;:::i;:::-;6586:64:22;;;:::i;:::-;4570:54;4566:118;;1411:19:21;1428:13276:31;4445:13:22;;4566:118;4651:18;;;-1:-1:-1;4651:18:22;;-1:-1:-1;4651:18:22;4500:51;1765:13;;;-1:-1:-1;4538:13:22;;-1:-1:-1;4538:13:22;4460:19;;;;;;;;;1411::21;1432:37;:::o;4356:73:22:-;4405:24;;;-1:-1:-1;4405:24:22;;-1:-1:-1;4405:24:22;5236:67;4244:22;;;-1:-1:-1;5281:22:22;;-1:-1:-1;5281:22:22;5040:71;880:21:23;;;-1:-1:-1;5090:21:22;;-1:-1:-1;5090:21:22;4133:53;4166:20;;;1428:13276:31;4166:20:22;;1428:13276:31;4166:20:22;4074:49;4108:15;;;1428:13276:31;4108:15:22;;1428:13276:31;4108:15:22;1428:13276:31;;;;;;;;;;;;890:333:21;1428:13276:31;970:4:21;1428:13276:31;1016:15:21;1428:13276:31;;;;;;;;;1061:19:21;1046:34;;1042:72;;1428:13276:31;1144:25:21;1129:40;1125:69;;1205:11;;1061:19;890:333;:::o;1125:69::-;-1:-1:-1;;;;;1428:13276:31;;;1178:7:21;1428:13276:31;;;;;;;;;1171:23:21:o;1042:72::-;2366:6:22;1428:13276:31;-1:-1:-1;;;;;1428:13276:31;;;;-1:-1:-1;1428:13276:31;;;;;-1:-1:-1;2387:21:22;;2383:47;;2444:21;;2440:49;;1428:13276:31;2503:35:22;;2499:70;;1428:13276:31;;;;;;;;;;;;;;;;;;-1:-1:-1;;1428:13276:31;;;;;;;;;;;;2716:88:22;1428:13276:31;;;-1:-1:-1;;1428:13276:31;;2716:88:22;:::i;:::-;1428:13276:31;;;;;2902:12:22;;:31;;2898:68;;1428:13276:31;;;3456:64:22;1428:13276:31;-1:-1:-1;1428:13276:31;2993:6:22;1428:13276:31;;3341:99:22;1428:13276:31;-1:-1:-1;1428:13276:31;;;2993:17:22;;;;:::i;:::-;1428:13276:31;;3296:29:22;1428:13276:31;;;;;:::i;:::-;;;;-1:-1:-1;1428:13276:31;:::i;:::-;;;3150:4:22;1428:13276:31;3052:216:22;;1428:13276:31;3052:216:22;1428:13276:31;3052:216:22;;1428:13276:31;3052:216:22;;;;1428:13276:31;3052:216:22;;;;1428:13276:31;3296:29:22;:::i;:::-;1428:13276:31;;;3360:13:22;;1428:13276:31;;;;;;;;;;3052:216:22;;1428:13276:31;;;;3052:216:22;1428:13276:31;;;;-1:-1:-1;1428:13276:31;;;;-1:-1:-1;1428:13276:31;;;;;;;3150:4:22;;1428:13276:31;;;;;;;;;3341:99:22;;;;1428:13276:31;;;;:::i;:::-;3456:64:22;;:::i;:::-;3455:65;3451:96;;1061:19:21;1082:32;:::o;10101:196:32:-;1428:13276:31;;;;;;10189:10:32;10175:24;;;:63;;;;10101:196;10171:120;;;10101:196::o;10171:120::-;10261:19;;;;;;;;10175:63;-1:-1:-1;1428:13276:31;;;10204:10:32;1428:13276:31;;;;;;;;10189:10:32;1428:13276:31;;;;;;;;;;10203:35:32;;-1:-1:-1;10175:63:32;;3080:625:33;-1:-1:-1;;;;;1428:13276:31;-1:-1:-1;1428:13276:31;;;3206:11:33;1428:13276:31;;;;;;3080:625:33;;;-1:-1:-1;;;;;1428:13276:31;3243:14:33;;3239:43;;1428:13276:31;-1:-1:-1;1428:13276:31;3317:15:33;1428:13276:31;;;-1:-1:-1;1428:13276:31;;3364:22:33;;;:44;;;;3080:625;3360:77;;3466:22;;3498:27;3466:22;;:::i;:::-;1428:13276:31;3498:27:33;1428:13276:31;3498:27:33;:::i;:::-;;1428:13276:31;3540:20:33;;;-1:-1:-1;1428:13276:31;3317:15:33;1428:13276:31;;-1:-1:-1;1428:13276:31;;;;;;;;;-1:-1:-1;1428:13276:31;3206:11:33;1428:13276:31;;;-1:-1:-1;1428:13276:31;-1:-1:-1;;;;;1428:13276:31;;;;;;3080:625:33:o;3536:163::-;1428:13276:31;;-1:-1:-1;1428:13276:31;3317:15:33;1428:13276:31;;;;-1:-1:-1;1428:13276:31;;3080:625:33:o;3360:77::-;10606:20:32;;;-1:-1:-1;3417:20:33;;-1:-1:-1;3417:20:33;3364:44;3390:18;;;3364:44;;3239:43;3266:16;;;-1:-1:-1;3266:16:33;;-1:-1:-1;3266:16:33;10718:128:32;1780:6;-1:-1:-1;10783:56:32;;10718:128::o;10783:56::-;11434:20:31;;;10819::32;;;;;7721:208:4;-1:-1:-1;;;;;1428:13276:31;;7791:21:4;;7787:91;;7346:25;1428:13276:31;;6496:21:4;7810:1;1428:13276:31;6496:21:4;1428:13276:31;6496:21:4;:::i;:::-;;1428:13276:31;;;;7284:9:4;1428:13276:31;;;;;;;;;;;;;;;;7346:25:4;7721:208::o;6725:477:22:-;3515:233:16;6725:477:22;6940:27;;1428:13276:31;;;;;6930:38:22;1428:13276:31;;;;;;;6986:26:22;;1428:13276:31;;;;;;;;7030:18:22;;;1428:13276:31;;7066:16:22;7100:26;7066:16;;;1428:13276:31;7100:26:22;;1428:13276:31;;7030:18:22;1428:13276:31;6868:272:22;1428:13276:31;6868:272:22;;1428:13276:31;803:139:22;1428:13276:31;;7030:18:22;803:139;;1428:13276:31;7066:16:22;803:139;;1428:13276:31;7100:26:22;803:139;;1428:13276:31;803:139:22;;;1428:13276:31;803:139:22;;;1428:13276:31;803:139:22;6868:272;;;;;;:::i;:::-;1428:13276:31;6845:305:22;;5053:20:15;;:::i;:::-;3515:233:16;7030:18:22;3515:233:16;;-1:-1:-1;;;3515:233:16;;;;;;;;;;;6725:477:22;:::o;1428:13276:31:-;;;;;;;;;;;;:::o;:::-;;;;;;;;;;:::o;:::-;;-1:-1:-1;;;;;1428:13276:31;;;;;;;:::o;10764:237::-;10853:8;1428:13276;;;-1:-1:-1;;;10853:37:31;;10884:4;10853:37;;;1428:13276;;;;;;10853:37;;1428:13276;;-1:-1:-1;;;;;1428:13276:31;10853:37;;;;;;-1:-1:-1;10853:37:31;;;10764:237;10853:57;1428:13276;;10893:17;1428:13276;10853:57;;:::i;:::-;4571:12:32;1428:13276:31;;10927:30;;;;;;10960;;;:::i;10853:37::-;;1428:13276;10853:37;;1428:13276;10853:37;;;;;;1428:13276;10853:37;;;:::i;:::-;;;1428:13276;;;;10853:57;1428:13276;;10853:37;;;;;-1:-1:-1;10853:37:31;;5252:1357:33;;;1428:13276:31;;;5460:17:33;1428:13276:31;5491:17:33;;;:36;;;;5252:1357;5487:55;;1428:13276:31;;5618:6:33;1428:13276:31;;-1:-1:-1;;;;;1428:13276:31;;;;;5732:59:33;:28;;;:59;:28;;;:59;;;;;;;-1:-1:-1;;;;;1428:13276:31;;5809:35:33;;;;;1428:13276:31;;5896:15:33;1428:13276:31;;;;;6010:74:33;1428:13276:31;;;;;;;;;;:::i;:::-;;;;;5618:6:33;1428:13276:31;;-1:-1:-1;;;;;1428:13276:31;;;;;;;;6010:74:33;:::i;:::-;6103:12;;;;;6099:175;;1428:13276:31;6383:26:33;1428:13276:31;6423:21:33;1428:13276:31;6355:12:33;1428:13276:31;;;6458:20:33;1428:13276:31;;;;;;;;;6355:12:33;;:::i;:::-;6383:26;:::i;:::-;6423:21;;:::i;:::-;6458:20;;:::i;:::-;6497:11;;6493:22;;6530:15;;;:::i;:::-;5802:754;;;;;;;;;6493:22;6510:5;;;;;;;-1:-1:-1;;;;;6510:5:33;;;5802:754;1428:13276:31;-1:-1:-1;;;;;1428:13276:31;5618:6:33;1428:13276:31;;;5618:6:33;1428:13276:31;5252:1357:33:o;6099:175::-;6135:102;;;;;;;;;;;;;;;;6254:5;;;;;-1:-1:-1;;;;;6254:5:33;;;6135:102;6173:15;;;;;;;;;;;;:::i;:::-;6210:8;;;5809:35;;;;;;;;-1:-1:-1;;;;;5809:35:33;;;;;;5732:59;;;;;;;;;;5487:55;5529:13;;;;;;;1428:13276:31;5529:13:33;1428:13276:31;5529:13:33;:::o;5491:36::-;5512:15;;;5491:36;;8051:302:19;;8188:25;8051:302;;8188:25;:::i;8051:302::-;;;8188:25;;;;;:::i;:::-;1428:13276:31;8257:25:19;;;;;8223:101;;8051:302;:::o;8223:101::-;13569:18:31;1428:13276;;;;;;;8051:302:19;:::o;8257:25::-;1428:13276:31;;;-1:-1:-1;1428:13276:31;;;;;-1:-1:-1;1428:13276:31;11046:1066;;;;1428:13276;;;;;;;;-1:-1:-1;1428:13276:31;11222:12;1428:13276;;;-1:-1:-1;1428:13276:31;11288:26;;;;1428:13276;;;11329:26;;11325:56;;11395:30;-1:-1:-1;11391:63:31;;6524:9:32;1428:13276:31;6503:41:32;;;;:::i;:::-;11557:12:31;;;:::i;:::-;11548:21;;11544:57;;12051:54;1428:13276;;;11856:19;11878:75;-1:-1:-1;;;;;1428:13276:31;11612:27;1428:13276;11612:27;1428:13276;11612:27;:::i;:::-;;1428:13276;11649:17;;;:27;1428:13276;;;11649:27;:::i;:::-;1428:13276;;;11686:18;;;1428:13276;11686:28;1428:13276;;;11686:28;:::i;:::-;1428:13276;;;11724:36;1428:13276;;;11724:36;:::i;11878:75::-;11856:19;;1428:13276;;;;;;;;;;;12051:54;;11046:1066::o;11544:57::-;11578:23;;;-1:-1:-1;11578:23:31;;-1:-1:-1;11578:23:31;11325:56;11364:17;;;-1:-1:-1;11364:17:31;;-1:-1:-1;11364:17:31;8247:206:4;;;;-1:-1:-1;;;;;1428:13276:31;8317:21:4;;8313:89;;1428:13276:31;8336:1:4;1428:13276:31;6570:9:4;1428:13276:31;;;8336:1:4;1428:13276:31;;6603:19:4;;;6599:115;;1428:13276:31;;8336:1:4;1428:13276:31;;7346:25:4;1428:13276:31;;;;6570:9:4;1428:13276:31;;;;;;;;7073:21:4;1428:13276:31;;7073:21:4;1428:13276:31;;;;;;7346:25:4;8247:206::o;6599:115::-;6649:50;;;;;8336:1;6649:50;;1428:13276:31;;;;;;8336:1:4;6649:50;10264:155:33;10362:17;1428:13276:31;;10353:26:33;;;;;;10382;;;:::i;:::-;10362:17;1428:13276:31;10264:155:33:o;10353:59::-;;;-1:-1:-1;10362:17:33;1428:13276:31;10264:155:33:o;7420:705:31:-;;;;7629:17;;;1428:13276;7680:18;1428:13276;;7680:18;;1428:13276;;;;7713:21;;7709:54;;7793:53;;:23;;;;;;7819;;;:::i;:::-;7793:53;;1428:13276;;;7861:22;7857:55;;7943:24;;;;;;7970;;;:::i;:::-;1428:13276;;8012:22;8008:50;;7943:55;1428:13276;8072:23;8068:50;;7420:705;:::o;8068:50::-;-1:-1:-1;1428:13276:31;;7420:705::o;8008:50::-;-1:-1:-1;1428:13276:31;;8008:50;;7943:55;;;-1:-1:-1;7943:55:31;;7857;7743:20;;;-1:-1:-1;7892:20:31;;-1:-1:-1;7892:20:31;7793:53;;;-1:-1:-1;7793:53:31;;;9485:156:32;;1412:43:8;;9485:156:32;9565:22;1428:13276:31;9565:22:32;1428:13276:31;9565:22:32;:::i;:::-;;1428:13276:31;;;-1:-1:-1;;;1412:43:8;;;;-1:-1:-1;;;;;1428:13276:31;;;1412:43:8;;;1428:13276:31;1624:1;;;1428:13276;;;;;1624:1;;;1412:43:8;;1428:13276:31;;1412:43:8;;;;;;:::i;4003:1184:33:-;;;;;1428:13276:31;4163:14:33;;;:40;;;;4003:1184;4159:54;;1428:13276:31;;;;;;;4289:6:33;1428:13276:31;;-1:-1:-1;;;;;1428:13276:31;;;;;4374:760:33;;4381:13;;;:47;;;4374:760;4381:47;;;-1:-1:-1;;;;;1428:13276:31;;;;4480:15:33;1428:13276:31;;;;;4595:73:33;1428:13276:31;;;;;;;;;;:::i;4595:73:33:-;4687:12;;;;;;4683:175;;1428:13276:31;4967:21:33;1428:13276:31;5002:20:33;1428:13276:31;4939:12:33;1428:13276:31;;5036:20:33;1428:13276:31;;;;;;;;;;4939:12:33;;:::i;4967:21::-;5002:20;;:::i;:::-;5036;;:::i;:::-;5075:11;;5071:22;;5108:15;;;:::i;:::-;4374:760;;;;;;;;;5071:22;5088:5;;;;;;-1:-1:-1;;;;;5088:5:33;;;1428:13276:31;-1:-1:-1;;;;;1428:13276:31;4289:6:33;1428:13276:31;;;4289:6:33;1428:13276:31;4003:1184:33:o;4683:175::-;4719:102;;;;;;;;;;;;;;4838:5;;;;-1:-1:-1;;;;;4838:5:33;;;;;;4719:102;4757:15;;;;;;;;:::i;:::-;4794:8;;;4381:47;;;;;;;-1:-1:-1;;;;;4381:47:33;;;;;;1428:13276:31;;-1:-1:-1;;;;;1428:13276:31;;4398:30:33;;4381:47;;4159:54;4205:8;;;;;1428:13276:31;4205:8:33;:::o;4163:40::-;1428:13276:31;4181:17:33;1428:13276:31;4181:22:33;4163:40;;3803:4116:19;;;1428:13276:31;;;;-1:-1:-1;;3803:4116:19;;4383:131;;;;;;;;;;;;4595:10;;4591:368;;5065:20;;;;5061:88;;5435:300;;;1428:13276:31;;;5954:31:19;;5999:371;;;6813:1;1428:13276:31;6794:1:19;1428:13276:31;6793:21:19;1428:13276:31;;;6813:1:19;1428:13276:31;;;;;6813:1:19;1428:13276:31;;;;;6813:1:19;1428:13276:31;;;;;6813:1:19;1428:13276:31;;;;;6813:1:19;1428:13276:31;;;;;6813:1:19;1428:13276:31;;5999:371:19;;;;1428:13276:31;5999:371:19;;;5435:300;;;;;;1428:13276:31;5435:300:19;;5999:371;6436:21;1428:13276:31;3803:4116:19;:::o;5061:88::-;5112:22;;;1428:13276:31;5112:22:19;;1428:13276:31;5112:22:19;4591:368;1428:13276:31;;;;;;;;;4918:26:19;:::o;1428:13276:31:-;;;;;;;;;;:::o;:::-;10848:17:4;;1428:13276:31;;;;;;;;:::o;:::-;-1:-1:-1;;1428:13276:31;;;;;;;:::o;6687:778:33:-;;;;;;;6964:18;;;1428:13276:31;;;;;;;;;6964:32:33;6960:57;;7051:41;;;;;:::i;:::-;1428:13276:31;;;7128:46:33;10571:134;;;;;6687:778;10571:134;;;;;;6687:778;7189:20;;;7185:46;;7242:33;7298:47;7414:44;7242:33;;7298:47;;;:::i;:::-;1428:13276:31;;;;7369:33:33;;;;-1:-1:-1;;;;;1428:13276:31;7414:44:33;:::i;:::-;;6687:778::o;7185:46::-;-1:-1:-1;;;;;;;;;;;7211:20:33:o;10571:134::-;;-1:-1:-1;10571:134:33;;;;;-1:-1:-1;10571:134:33;;;6960:57;-1:-1:-1;;;;;;;7012:4:33;;-1:-1:-1;;;6998:19:33:o;1428:13276:31:-;;-1:-1:-1;1428:13276:31;;;:::o;3385:267:11:-;1390:66;3508:46;;1390:66;;;2652:40;;2706:11;2715:2;2706:11;;2702:69;;1428:13276:31;;;;;;;:::i;:::-;2311:2:11;1428:13276:31;;;;;;;;;;;2367:90:11;;;3570:22;:::o;2702:69::-;2740:20;;;-1:-1:-1;2740:20:11;;-1:-1:-1;2740:20:11;3504:142;1428:13276:31;;;1390:66:11;;;;6126:13:15;1390:66:11;:::i;:::-;;;;:::i;3385:267::-;1390:66;3508:46;;1390:66;;;2652:40;;2706:11;2715:2;2706:11;;2702:69;;1428:13276:31;;;;;;;:::i;3504:142:11:-;1428:13276:31;;;1390:66:11;;;;6584:16:15;1390:66:11;:::i;4059:629:8:-;2847:1:9;4059:629:8;3510:55:9;4059:629:8;1428:13276:31;;;;;;3462:31:9;;;;;;;;;;;;:::i;:::-;3510:55;;;:::i;:::-;1428:13276:31;;4551:22:8;;;;:57;;;;4059:629;4547:135;;;;4059:629;:::o;4547:135::-;4631:40;;;2847:1:9;4631:40:8;;1428:13276:31;;2847:1:9;4631:40:8;4551:57;4578:30;;;;3462:31:9;4578:30:8;;;1428:13276:31;;;;3462:31:9;1428:13276:31;4578:30:8;;1428:13276:31;:::i;:::-;4577:31:8;4551:57;;;;1039:368:17;;1211:33;;;;:::i;:::-;-1:-1:-1;1428:13276:31;;;;;;:::i;:::-;1274:35:17;:58;;;;1039:368;1273:127;;;;;1039:368;1254:146;;;1039:368;:::o;1273:127::-;1283:26;1428:13276:31;;;;2041:60:17;1428:13276:31;;;;;2041:60:17;;;;;;;;;;;;;;;1428:13276:31;;;;;;;;;;;:::i;2041:60:17:-;2010:101;;;;;;:::i;:::-;2129:42;;;1273:127;2129:134;;;1273:127;;;;;;;2129:134;1428:13276:31;;2041:60:17;1428:13276:31;;;2187:29:17;;1428:13276:31;;;;2041:60:17;2187:29;1428:13276:31;-1:-1:-1;;;2187:76:17;2129:134;;;:42;1428:13276:31;;2041:60:17;1428:13276:31;;2152:19:17;;2129:42;;;1274:58;-1:-1:-1;;;;;1428:13276:31;;;;;1313:19:17;;-1:-1:-1;1274:58:17;;;3845:262:15;3929:4;3938:11;-1:-1:-1;;;;;1428:13276:31;3921:28:15;;:63;;3845:262;3917:184;;;4007:22;4000:29;:::o;3917:184::-;1428:13276:31;;4204:80:15;;;1428:13276:31;2079:95:15;1428:13276:31;;4226:11:15;1428:13276:31;2079:95:15;;1428:13276:31;4239:14:15;2079:95;;;1428:13276:31;4255:13:15;2079:95;;;1428:13276:31;3929:4:15;2079:95;;;1428:13276:31;2079:95:15;4204:80;;;;;;:::i;:::-;1428:13276:31;4194:91:15;;4060:30;:::o;3921:63::-;3970:14;;3953:13;:31;3921:63;;2129:766:14;1428:13276:31;;;2129:766:14;2276:2;2256:22;;2276:2;;2739:25;2539:180;;;;;;;;;;;;;;;-1:-1:-1;2539:180:14;2739:25;;:::i;:::-;2732:32;;;;;:::o;2252:637::-;2795:83;;2811:1;2795:83;2815:35;2795:83;;:::o;1428:13276:31:-;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;-1:-1:-1;1428:13276:31;;;;:::o;:::-;;;:::o;5140:1530:14:-;;;6199:66;6186:79;;6182:164;;1428:13276:31;;;;;;-1:-1:-1;1428:13276:31;;;;;;;;;;;;;;;;;;;6457:24:14;;;;;;;;;-1:-1:-1;6457:24:14;-1:-1:-1;;;;;1428:13276:31;;6495:20:14;6491:113;;6614:49;-1:-1:-1;6614:49:14;-1:-1:-1;5140:1530:14;:::o;6491:113::-;6531:62;-1:-1:-1;6531:62:14;6457:24;6531:62;-1:-1:-1;6531:62:14;:::o;6182:164::-;6281:54;;;6297:1;6281:54;6301:30;6281:54;;:::o;4625:582:9:-;;4797:8;;-1:-1:-1;1428:13276:31;;5874:21:9;:17;;6046:142;;;;;;5870:383;6225:17;;;5894:1;6225:17;;5894:1;6225:17;4793:408;1428:13276:31;;5045:22:9;:49;;;4793:408;5041:119;;5173:17;;:::o;5041:119::-;-1:-1:-1;;;5066:1:9;5121:24;;;-1:-1:-1;;;;;1428:13276:31;;;;5121:24:9;1428:13276:31;;;5121:24:9;5045:49;5071:18;;;:23;5045:49;
Swarm Source
ipfs://e39e9ad2cb2fbd0b267a0000e0e1432ec3ada7e1a021a8bb5287c20e41c36122
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$97,262.94
Net Worth in MON
Token Allocations
USDC
100.00%
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|---|---|---|---|---|
| MONAD | 100.00% | $0.999701 | 97,292.03 | $97,262.94 |
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.