Source Code
Overview
MON Balance
MON Value
$0.00| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Advanced mode: Intended for advanced users or developers and will display all Internal Transactions including zero value transfers.
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Block | From | To | ||||
|---|---|---|---|---|---|---|---|
| 51773976 | 8 hrs ago | 0 MON | |||||
| 51773976 | 8 hrs ago | 0 MON | |||||
| 51773976 | 8 hrs ago | 0 MON | |||||
| 50508238 | 6 days ago | 0 MON | |||||
| 49834427 | 9 days ago | 0 MON | |||||
| 49834427 | 9 days ago | 0 MON | |||||
| 49834427 | 9 days ago | 0 MON | |||||
| 47683350 | 19 days ago | 0 MON | |||||
| 47683350 | 19 days ago | 0 MON | |||||
| 47683350 | 19 days ago | 0 MON | |||||
| 47611598 | 19 days ago | 0 MON | |||||
| 47611598 | 19 days ago | 0 MON | |||||
| 47611598 | 19 days ago | 0 MON | |||||
| 47539858 | 20 days ago | 0 MON | |||||
| 47539858 | 20 days ago | 0 MON | |||||
| 47539858 | 20 days ago | 0 MON | |||||
| 47467998 | 20 days ago | 0 MON | |||||
| 47467998 | 20 days ago | 0 MON | |||||
| 47467998 | 20 days ago | 0 MON | |||||
| 47396233 | 20 days ago | 0 MON | |||||
| 47396233 | 20 days ago | 0 MON | |||||
| 47396233 | 20 days ago | 0 MON | |||||
| 47360686 | 20 days ago | 0 MON | |||||
| 47360686 | 20 days ago | 0 MON | |||||
| 47360686 | 20 days ago | 0 MON |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
MultipliVault
Compiler Version
v0.8.30+commit.73712a01
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.30;
import { Errors } from "../libraries/Errors.sol";
import { IMultipliVault } from "../interfaces/IMultipliVault.sol";
import { IVariableVaultFee } from "../interfaces/IVariableVaultFee.sol";
import { IMultipliVaultCallee } from "../interfaces/IMultipliVaultCallee.sol";
import { VaultFeeUpgradeable } from "../base/VaultFeeUpgradeable.sol";
import { AuthUpgradeable, Authority } from "../base/AuthUpgradeable.sol";
import { FundMovementHelperUpgradeable } from "../base/FundMovementHelperUpgradeable.sol";
import { Math } from "@openzeppelin/contracts/utils/math/Math.sol";
import { Address } from "@openzeppelin/contracts/utils/Address.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { ERC4626Upgradeable } from
"@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC4626Upgradeable.sol";
import { PausableUpgradeable } from
"@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol";
import { ReentrancyGuardUpgradeable } from
"@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
import { UUPSUpgradeable } from "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";
/**
* @title MultipliVault
* @author Multipli Team
* @notice A vault contract that enables an operator to manage vault assets asynchronously
* @dev Implements the ERC4626 standard with Auth contract for access control and ERC-7201 storage pattern
*
* The contract provides a redeem request mechanism that allows users to initiate a redeem request,
* and the operator to fulfill it at a later time. This mechanism is particularly useful for scenarios
* where the operator needs to move assets across chains or to different strategies before settling
* the user's redemption request. Upon fulfillment, assets are transferred to the vault, and the request
* is marked as complete.
*
* @custom:security-contact [email protected]
*/
contract MultipliVault is
UUPSUpgradeable,
ERC4626Upgradeable,
IMultipliVault,
AuthUpgradeable,
PausableUpgradeable,
VaultFeeUpgradeable,
FundMovementHelperUpgradeable,
ReentrancyGuardUpgradeable
{
using Math for uint256;
using Address for address;
using SafeERC20 for IERC20;
//============================== TYPES ===============================
/**
* @notice Enum defining different types of redemption requests
* @dev Used to handle different redemption flows with varying fee structures and processing methods
*/
enum RedeemType {
NORMAL, // Standard redemption with regular fees
INSTANT // Fast-forward redemption with higher fees
}
/**
* @notice Internal struct for request parameters
* @dev Used to pass redemption request data between functions
* @param shares The amount of shares to redeem
* @param receiver The address that will receive the assets
* @param owner The address that owns the shares
* @param redeemType The type of redemption (NORMAL or INSTANT)
*/
struct RedeemParams {
uint256 shares;
address receiver;
address owner;
RedeemType redeemType;
}
/**
* @notice Internal struct for fulfillment parameters
* @dev Used to pass fulfillment data between functions
* @param receiver The address that will receive the assets
* @param shares The amount of shares being fulfilled
* @param assetsWithFee The amount of assets including fees
* @param redeemType The type of redemption being fulfilled
*/
struct FulfillParams {
address receiver;
uint256 shares;
uint256 assetsWithFee;
RedeemType redeemType;
}
/**
* @custom:storage-location erc7201:multipli.storage.MultipliVaultStorage
* @dev Structure to hold MultipliVault storage data following ERC-7201 standard
*/
struct MultipliVaultStorage {
/// @dev The aggregated underlying balances across all strategies/chains, reported by an oracle
uint256 aggregatedUnderlyingBalances;
/// @dev The last block number when the aggregated underlying balances were updated
uint256 lastBlockUpdated;
/// @dev The last price per share calculated after the aggregated underlying balances are reported
uint256 lastPricePerShare;
/// @dev The total amount of assets that are pending redemption
uint256 totalPendingAssets;
/// @dev The maximum percentage change allowed before the vault is paused
uint256 maxPercentageChange;
/// @dev Minimum deposit amount required for deposits and mints
uint256 minDepositAmount;
/// @dev Mapping to store pending redemption requests for each user
mapping(address user => PendingRedeem redeem) pendingRedeem;
}
//============================== CONSTANTS ===============================
/// @dev Assume requests are non-fungible and all have ID = 0, so we can differentiate between a request ID and the assets amount
uint256 internal constant REQUEST_ID = 0;
/// @dev The denominator used for precision calculations (1e18 = 100%)
uint256 internal constant DENOMINATOR = 1e18;
/// @dev The maximum percentage that can be set as a threshold for the percentage change (1e17 = 10%)
uint256 internal constant MAX_PERCENTAGE_THRESHOLD = 1e17;
//============================== STORAGE ===============================
// Storage slot for the MultipliVaultStorage struct.
// keccak256(abi.encode(uint256(keccak256("multipli.storage.MultipliVaultStorage")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant MULTIPLI_VAULT_STORAGE_LOCATION =
0x5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af900;
//============================== CONSTRUCTOR ===============================
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
//============================== INITIALIZER ===============================
/**
* @notice Initializes the MultipliVault contract
* @param _asset The underlying ERC20 asset for the vault
* @param _owner The initial owner of the vault
* @param _name The name of the vault token
* @param _symbol The symbol of the vault token
*/
function initialize(
IERC20 _asset,
address _owner,
string memory _name,
string memory _symbol
)
public
initializer
{
__MultipliVault_init(_asset, _owner, _name, _symbol);
}
/**
* @notice Initializes the MultipliVault contract
* @dev This function should be called during contract initialization
* @param _asset The underlying ERC20 asset for the vault
* @param _owner The initial owner of the vault
* @param _name The name of the vault token
* @param _symbol The symbol of the vault token
*/
function __MultipliVault_init(
IERC20 _asset,
address _owner,
string memory _name,
string memory _symbol
)
internal
onlyInitializing
{
__ERC20_init(_name, _symbol);
__ERC4626_init(_asset);
__Auth_init(_owner, Authority(address(0)));
__Pausable_init();
__VaultFeeUpgreadable_init(IVariableVaultFee(address(0)));
__FundMovementHelper_init();
__ReentrancyGuard_init();
__MultipliVault_init_unchained();
}
/**
* @notice Unchained initializer for MultipliVault
* @dev Contains the actual initialization logic for MultipliVault-specific storage
*/
/// @custom:oz-upgrades-unsafe-allow missing-initializer-call
// reference: https://forum.openzeppelin.com/t/potential-false-positive-missing-initializer-calls-for-one-or-more-parent-contracts/43911/3
function __MultipliVault_init_unchained() internal onlyInitializing {
MultipliVaultStorage storage $ = _getMultipliVaultStorage();
$.maxPercentageChange = 1e16; // 1%
$.minDepositAmount = 0;
}
//============================== PUBLIC FUNCTIONS ===============================
/**
* @notice Allows the vault operator to manage the vault by calling external contracts
* @param target The target contract to make a call to
* @param data The data to send to the target contract
* @param value The amount of native assets to send with the call
* @return result The return data from the external call
* @dev Requires authorization and target method must be authorized by the authority
*/
function manage(
address target,
bytes calldata data,
uint256 value
)
external
requiresAuth
returns (bytes memory result)
{
bytes4 functionSig = bytes4(data);
require(
authority().canCall(msg.sender, target, functionSig),
Errors.TargetMethodNotAuthorized(target, functionSig)
);
result = target.functionCallWithValue(data, value);
}
/**
* @notice Same as `manage` but allows for multiple calls in a single transaction
* @param targets The target contracts to make calls to
* @param data The data to send to the target contracts
* @param values The amounts of native assets to send with the calls
* @return results Array of return data from the external calls
* @dev Requires authorization and all target methods must be authorized by the authority
*/
function manage(
address[] calldata targets,
bytes[] calldata data,
uint256[] calldata values
)
external
requiresAuth
returns (bytes[] memory results)
{
uint256 targetsLength = targets.length;
require(
targetsLength == data.length && data.length == values.length,
"Array lengths must match"
);
results = new bytes[](targetsLength);
for (uint256 i; i < targetsLength; ++i) {
bytes4 functionSig = bytes4(data[i]);
require(
authority().canCall(msg.sender, targets[i], functionSig),
Errors.TargetMethodNotAuthorized(targets[i], functionSig)
);
results[i] = targets[i].functionCallWithValue(data[i], values[i]);
}
}
/**
* @notice Pause the contract to prevent any further deposits, withdrawals, or transfers
* @dev Can only be called by authorized users
*/
function pause() public requiresAuth {
_pause();
}
/**
* @notice Unpause the contract to allow deposits, withdrawals, and transfers
* @dev Can only be called by authorized users
*/
function unpause() public requiresAuth {
_unpause();
}
/**
* @notice Whitelist or remove a user from the fund transfer recipient list
* @param user The address to update whitelist status for
* @param status True to whitelist, false to remove from whitelist
* @dev Can only be called by authorized users
*/
function whitelistFundTransferRecipient(address user, bool status) public requiresAuth {
_whitelistFundTransferRecipient(user, status);
}
/**
* @notice Remove funds from the vault to a whitelisted recipient
* @param amount The amount of assets to transfer
* @param to The address to receive the funds (must be whitelisted)
* @dev Can only be called by authorized users
*/
function removeFunds(uint256 amount, address to) public requiresAuth {
_removeFunds(asset(), amount, to);
}
/**
* @notice Request a standard redemption of shares
* @param shares The amount of shares to redeem
* @param receiver The address that will receive the assets
* @param owner The address that owns the shares
* @return requestId The ID of the request (always 0)
* @dev Transfers shares to the vault and stores the request for later fulfillment
*/
function requestRedeem(
uint256 shares,
address receiver,
address owner
)
external
whenNotPaused
returns (uint256)
{
return _processRedeemRequest(RedeemParams(shares, receiver, owner, RedeemType.NORMAL));
}
/**
* @notice Request an instant redemption of shares (requires authorization)
* @param shares The amount of shares to redeem instantly
* @param receiver The address that will receive the assets
* @param owner The address that owns the shares
* @return requestId The ID of the request (always 0)
* @dev Only authorized users (external curators) can call this function
*/
function requestInstantRedeem(
uint256 shares,
address receiver,
address owner
)
external
whenNotPaused
requiresAuth
returns (uint256)
{
return _processRedeemRequest(RedeemParams(shares, receiver, owner, RedeemType.INSTANT));
}
/**
* @notice Fulfill a standard redemption request
* @param receiver The address that will receive the assets
* @param shares The amount of shares to fulfill
* @param assetsWithFee The amount of assets to transfer (including fees)
* @dev Can only be called by authorized operators
*/
function fulfillRedeem(
address receiver,
uint256 shares,
uint256 assetsWithFee
)
external
requiresAuth
{
_processFulfillment(FulfillParams(receiver, shares, assetsWithFee, RedeemType.NORMAL));
}
/**
* @notice Fulfill an instant redemption request
* @param receiver The address that will receive the assets
* @param shares The amount of shares to fulfill
* @param assetsWithFee The amount of assets to transfer (including fees)
* @dev Can only be called by authorized operators
*/
function fulfillInstantRedeem(
address receiver,
uint256 shares,
uint256 assetsWithFee
)
external
requiresAuth
{
_processFulfillment(FulfillParams(receiver, shares, assetsWithFee, RedeemType.INSTANT));
}
/**
* @notice Flash redemption for unwinding leveraged positions
* @dev Provides USDC upfront, expects equivalent xUSDC shares back after external operator call
* @param initiator The address that originally initiated the request
* @param operator The contract that will handle position unwinding on Euler
* @param receiver The address that will receive the USDC (usually the user)
* @param shares The amount of shares to redeem (total position size)
* @param data Additional data for the operator callback
*/
function flashRedeem(
address initiator,
address operator,
address receiver,
uint256 shares,
bytes calldata data
)
external
whenNotPaused
requiresAuth
nonReentrant
{
// Input validation
require(shares > 0, Errors.SharesAmountZero());
require(receiver != address(0), Errors.InvalidReceiverAddress());
require(operator != address(0), Errors.InvalidOperatorAddress());
address token = asset();
// Calculate assets and fees
uint256 assetsWithFee = convertToAssets(shares);
uint256 fee = _feeOnTotalFlashWithdrawal(token, assetsWithFee); // Use flash Redeem withdrawal fee
uint256 assetsWithoutFee = assetsWithFee - fee;
// Check vault has sufficient liquidity
uint256 vaultBalance = IERC20(token).balanceOf(address(this));
require(vaultBalance >= assetsWithFee, Errors.InvalidAssetsAmount());
uint256 shareBalanceBefore = balanceOf(address(this));
uint256 totalSupplyBefore = totalSupply();
// Transfer USDC to receiver pre-emptively
IERC20(token).safeTransfer(receiver, assetsWithoutFee);
// Invoke the operator to transfer the shares back to the vault
IMultipliVaultCallee(operator).onRedemptionFlashLoan(
initiator, address(this), token, shares, assetsWithoutFee, data
);
{
// Verify the operator returned the required shares
uint256 shareBalanceAfter = balanceOf(address(this));
require(shareBalanceAfter >= shareBalanceBefore + shares, Errors.SharesNotReturned());
}
// Burn the returned shares (completing the redemption)
_burn(address(this), shares);
{
// note: totalSupply check was added before re-entrancy
// guard was added to `flashRedeem` method, is this still required?
// Verify total supply decreased correctly
require(totalSupply() == totalSupplyBefore - shares, Errors.TotalSupplyMismatch());
// Verify the `asset` balance after redemption
uint256 tokenBalanceAfter = IERC20(token).balanceOf(address(this));
require(
vaultBalance - assetsWithFee <= tokenBalanceAfter, Errors.AssetBalanceMismatch()
);
}
// Transfer fee to fee recipient
address feeRecipient = _getFeeRecipient(token);
if (fee > 0 && feeRecipient != address(0)) {
IERC20(token).safeTransfer(feeRecipient, fee);
}
emit FlashRedeemFulfilled(initiator, operator, receiver, shares, assetsWithoutFee, fee);
}
/**
* @notice Cancel a redemption request in case of a black swan event.
* @param receiver The address that had the pending request.
* @param shares The amount of shares to cancel.
* @param assetsWithFee The amount of assets to cancel (including fees)
* @dev Returns shares back to the receiver and updates pending amounts
*/
function cancelRedeem(
address receiver,
uint256 shares,
uint256 assetsWithFee
)
external
requiresAuth
{
MultipliVaultStorage storage $ = _getMultipliVaultStorage();
PendingRedeem storage pending = $.pendingRedeem[receiver];
require(pending.shares != 0 && shares <= pending.shares, Errors.InvalidSharesAmount());
require(
pending.assets != 0 && assetsWithFee <= pending.assets, Errors.InvalidAssetsAmount()
);
pending.shares -= shares;
pending.assets -= assetsWithFee;
$.totalPendingAssets -= assetsWithFee;
emit RequestCancelled(receiver, shares, assetsWithFee);
// Transfer the shares back to the receiver
IERC20(address(this)).safeTransfer(receiver, shares);
}
/**
* @notice Update the aggregated underlying balances across all strategies/chains
* @param newAggregatedBalance The new aggregated underlying balances
* @dev Can be called only once per block to prevent oracle abuse and flash loan attacks
* @dev Automatically pauses the vault if price change exceeds the maximum threshold
*/
function onUnderlyingBalanceUpdate(uint256 newAggregatedBalance) external requiresAuth {
MultipliVaultStorage storage $ = _getMultipliVaultStorage();
// Fail fast - ensure this is the first update in this block
require(block.number > $.lastBlockUpdated, Errors.UpdateAlreadyCompletedInThisBlock());
emit UnderlyingBalanceUpdated($.aggregatedUnderlyingBalances, newAggregatedBalance);
$.aggregatedUnderlyingBalances = newAggregatedBalance;
// Calculate new price per share and check for excessive volatility
// todo: should this be replaced with `convertToAssets(1e6)`?
uint256 newPricePerShare = totalAssets().mulDiv(DENOMINATOR, totalSupply());
uint256 percentageChange = _calculatePercentageChange($.lastPricePerShare, newPricePerShare);
// Pause the vault if the percentage change exceeds the threshold (works in both directions)
if (percentageChange > $.maxPercentageChange) {
_pause();
}
$.lastPricePerShare = newPricePerShare;
$.lastBlockUpdated = block.number;
}
/**
* @notice Set the fee contract for the vault
* @param _feeContract The new fee contract address
* @dev Overrides the base implementation to add authorization requirement
*/
function setFeeContract(IVariableVaultFee _feeContract) public override requiresAuth {
super.setFeeContract(_feeContract);
}
/**
* @notice Get the fee recipient address for the vault's asset
* @return The address that receives fees
*/
function getFeeRecipient() public view returns (address) {
return _getFeeRecipient(asset());
}
/**
* @notice Update the maximum percentage change allowed before the vault is paused
* @param newMaxPercentageChange The new maximum percentage change (max value is 1e17 = 10%)
* @dev Used to protect against oracle manipulation and excessive volatility
*/
function updateMaxPercentageChange(uint256 newMaxPercentageChange) external requiresAuth {
require(newMaxPercentageChange < MAX_PERCENTAGE_THRESHOLD, Errors.InvalidMaxPercentage());
MultipliVaultStorage storage $ = _getMultipliVaultStorage();
emit MaxPercentageUpdated($.maxPercentageChange, newMaxPercentageChange);
$.maxPercentageChange = newMaxPercentageChange;
}
/**
* @notice Update the minimum deposit amount required for deposits and mints
* @param newMinDepositAmount The new minimum deposit amount
* @dev Used to prevent dust deposits and ensure economic viability
*/
function updateMinDepositAmount(uint256 newMinDepositAmount) external requiresAuth {
MultipliVaultStorage storage $ = _getMultipliVaultStorage();
emit MinDepositAmountUpdated($.minDepositAmount, newMinDepositAmount);
$.minDepositAmount = newMinDepositAmount;
}
//============================== VIEW FUNCTIONS ===============================
/**
* @notice Get the pending redemption request details for a user
* @param user The address to check
* @return assets The amount of assets pending redemption
* @return pendingShares The amount of shares pending redemption
*/
function pendingRedeemRequest(address user)
public
view
returns (uint256 assets, uint256 pendingShares)
{
MultipliVaultStorage storage $ = _getMultipliVaultStorage();
return ($.pendingRedeem[user].assets, $.pendingRedeem[user].shares);
}
/**
* @notice Get the aggregated underlying balances across all strategies
* @return The total underlying balances
*/
function aggregatedUnderlyingBalances() public view returns (uint256) {
return _getMultipliVaultStorage().aggregatedUnderlyingBalances;
}
/**
* @notice Get the last block number when underlying balances were updated
* @return The last update block number
*/
function lastBlockUpdated() public view returns (uint256) {
return _getMultipliVaultStorage().lastBlockUpdated;
}
/**
* @notice Get the last calculated price per share
* @return The last price per share
*/
function lastPricePerShare() public view returns (uint256) {
return _getMultipliVaultStorage().lastPricePerShare;
}
/**
* @notice Get the total amount of assets pending redemption
* @return The total pending assets
*/
function totalPendingAssets() public view returns (uint256) {
return _getMultipliVaultStorage().totalPendingAssets;
}
/**
* @notice Get the maximum percentage change allowed before pausing
* @return The maximum percentage change threshold
*/
function maxPercentageChange() public view returns (uint256) {
return _getMultipliVaultStorage().maxPercentageChange;
}
/**
* @notice Get the minimum deposit amount required
* @return The minimum deposit amount
*/
function minDepositAmount() public view returns (uint256) {
return _getMultipliVaultStorage().minDepositAmount;
}
//============================== OVERRIDES ===============================
/**
* @notice Override the default `totalAssets` function to include aggregated underlying balances
* @return The total assets held by the vault and across all strategies
*/
function totalAssets() public view override returns (uint256) {
MultipliVaultStorage storage $ = _getMultipliVaultStorage();
return IERC20(asset()).balanceOf(address(this)) + $.aggregatedUnderlyingBalances;
}
/**
* @notice Override the default `deposit` function with additional checks
* @param assets The amount of assets to deposit
* @param receiver The address that will receive the shares
* @return shares The amount of shares minted
* @dev Adds pause protection and minimum deposit amount validation
*/
function deposit(
uint256 assets,
address receiver
)
public
override
whenNotPaused
nonReentrant
returns (uint256)
{
uint256 maxAssets = maxDeposit(receiver);
if (assets > maxAssets) {
revert ERC4626ExceededMaxDeposit(receiver, assets, maxAssets);
}
MultipliVaultStorage storage $ = _getMultipliVaultStorage();
uint256 currentMinDepositAmount = $.minDepositAmount;
if (assets < currentMinDepositAmount) {
revert Errors.DepositAmountLessThanThreshold(assets, currentMinDepositAmount);
}
uint256 shares = previewDeposit(assets);
_deposit(_msgSender(), receiver, assets, shares);
return shares;
}
/**
* @notice Deposit assets with slippage protection (ERC-5143 compatible)
* @dev This function extends the standard ERC-4626 deposit function with slippage protection
* as specified in ERC-5143: Slippage Protection for Tokenized Vault and introduces additional checks.
* Reverts if the number of shares received is less than the minimum expected.
* @param assets The amount of assets to deposit
* @param receiver The address that will receive the vault shares
* @param minShares The minimum number of shares the caller is willing to accept
* @return shares The actual number of shares minted to the receiver
* @custom:security Protects against MEV attacks and exchange rate manipulation
*/
function deposit(
uint256 assets,
address receiver,
uint256 minShares
)
public
whenNotPaused
returns (uint256)
{
uint256 shares = deposit(assets, receiver);
if (shares < minShares) {
revert Errors.InsufficientSharesReceived(shares, minShares);
}
return shares;
}
/**
* @notice Override the default `mint` function with additional checks
* @param shares The amount of shares to mint
* @param receiver The address that will receive the shares
* @return assets The amount of assets required
* @dev Adds pause protection and minimum deposit amount validation
*/
function mint(
uint256 shares,
address receiver
)
public
override
whenNotPaused
nonReentrant
returns (uint256)
{
uint256 maxShares = maxMint(receiver);
if (shares > maxShares) {
revert ERC4626ExceededMaxMint(receiver, shares, maxShares);
}
uint256 assets = previewMint(shares);
MultipliVaultStorage storage $ = _getMultipliVaultStorage();
uint256 currentMinDepositAmount = $.minDepositAmount;
if (assets < currentMinDepositAmount) {
revert Errors.DepositAmountLessThanThreshold(assets, currentMinDepositAmount);
}
_deposit(_msgSender(), receiver, assets, shares);
return assets;
}
/**
* @notice Mint shares with slippage protection (ERC-5143 compatible)
* @dev This function extends the standard ERC-4626 mint function with slippage protection
* as specified in ERC-5143: Slippage Protection for Tokenized Vault.
* Reverts if the number of assets required exceeds the maximum the caller is willing to pay.
* @param shares The exact number of shares to mint
* @param receiver The address that will receive the vault shares
* @param maxAssets The maximum number of assets the caller is willing to pay
* @return assets The actual number of assets transferred from the caller
* @custom:security Protects against MEV attacks and exchange rate manipulation
*/
function mint(
uint256 shares,
address receiver,
uint256 maxAssets
)
public
whenNotPaused
returns (uint256)
{
uint256 assets = mint(shares, receiver);
if (assets > maxAssets) {
revert Errors.ExcessiveAssetsRequired(assets, maxAssets);
}
return assets;
}
/**
* @notice Disabled - use requestRedeem instead
* @dev This function is disabled to enforce the asynchronous redemption flow
*/
function withdraw(uint256, address, address) public override whenNotPaused returns (uint256) {
revert Errors.UseRequestRedeem();
}
/**
* @notice Disabled - use requestRedeem instead
* @dev This function is disabled to enforce the asynchronous redemption flow
*/
function redeem(uint256, address, address) public override whenNotPaused returns (uint256) {
revert Errors.UseRequestRedeem();
}
/**
* @notice Override the default `_update` function to add pause protection
* @dev The _update function is called on all transfers, mints and burns
*/
function _update(address from, address to, uint256 value) internal override whenNotPaused {
super._update(from, to, value);
}
/**
* @notice Preview the shares received for a deposit after fees
* @param assets The amount of assets to deposit
* @return The amount of shares that would be received
*/
function previewDeposit(uint256 assets) public view virtual override returns (uint256) {
uint256 fee = _feeOnTotalDeposit(asset(), assets);
return super.previewDeposit(assets - fee);
}
/**
* @notice Preview the assets required for minting shares including fees
* @param shares The amount of shares to mint
* @return The amount of assets required
*/
function previewMint(uint256 shares) public view virtual override returns (uint256) {
uint256 assets = super.previewMint(shares);
return assets + _feeOnRawDeposit(asset(), assets);
}
/**
* @notice Preview the shares required for withdrawing assets including fees
* @param assets The amount of assets to withdraw
* @return The amount of shares required
*/
function previewWithdraw(uint256 assets) public view virtual override returns (uint256) {
uint256 fee = _feeOnRawWithdrawal(asset(), assets);
return super.previewWithdraw(assets + fee);
}
/**
* @notice Preview the assets received for redeeming shares after fees
* @param shares The amount of shares to redeem
* @return The amount of assets that would be received
*/
function previewRedeem(uint256 shares) public view virtual override returns (uint256) {
uint256 assets = super.previewRedeem(shares);
return assets - _feeOnTotalWithdrawal(asset(), assets);
}
/**
* @notice Preview the assets received for instant redeeming shares after fees
* @param shares The amount of shares to redeem instantly
* @return The amount of assets that would be received
*/
function previewInstantRedeem(uint256 shares) public view virtual returns (uint256) {
uint256 assets = super.previewRedeem(shares);
return assets - _feeOnTotalInstantWithdrawal(asset(), assets);
}
/**
* @notice Preview the assets received for flash redeeming shares after fees
* @param shares The amount of shares to redeem instantly
* @return The amount of assets that would be received
*/
function previewFlashRedeem(uint256 shares) public view virtual returns (uint256) {
uint256 assets = convertToAssets(shares);
return assets - _feeOnTotalFlashWithdrawal(asset(), assets);
}
//============================== INTERNAL FUNCTIONS ===============================
/**
* @notice Internal deposit function with fee handling
* @param caller The address calling the deposit
* @param receiver The address receiving the shares
* @param assets The amount of assets being deposited
* @param shares The amount of shares being minted
* @dev Handles fee collection and transfer to fee recipient
*/
function _deposit(
address caller,
address receiver,
uint256 assets,
uint256 shares
)
internal
override
{
address token = asset();
uint256 feeAmount = _feeOnTotalDeposit(token, assets);
address recipient = _getFeeRecipient(token);
super._deposit(caller, receiver, assets, shares);
if (feeAmount > 0 && recipient != address(0)) {
IERC20(token).safeTransfer(recipient, feeAmount);
}
}
/**
* @notice Internal function to handle redeem request logic for all redeem types
* @param params The redemption parameters
* @return requestId The request ID (always 0)
* @dev Validates ownership, transfers shares to vault, and stores pending request
*/
function _processRedeemRequest(RedeemParams memory params) internal virtual returns (uint256) {
require(params.shares > 0, Errors.SharesAmountZero());
require(params.owner == msg.sender, Errors.NotSharesOwner());
require(balanceOf(params.owner) >= params.shares, Errors.InsufficientShares());
uint256 assetsWithFee = super.previewRedeem(params.shares);
// Emit appropriate event based on redemption type
_emitRedeemRequestEvent(
params.receiver, params.owner, assetsWithFee, params.shares, params.redeemType
);
// Store the redemption request
MultipliVaultStorage storage $ = _getMultipliVaultStorage();
_transfer(params.owner, address(this), params.shares);
$.totalPendingAssets += assetsWithFee;
$.pendingRedeem[params.receiver] = PendingRedeem({
shares: $.pendingRedeem[params.receiver].shares + params.shares,
assets: $.pendingRedeem[params.receiver].assets + assetsWithFee
});
return REQUEST_ID;
}
/**
* @notice Internal function to emit appropriate events based on redeem type
* @param receiver The address that will receive the assets
* @param owner The address that owns the shares
* @param assetsWithFee The amount of assets including fees
* @param shares The amount of shares being redeemed
* @param redeemType The type of redemption
*/
function _emitRedeemRequestEvent(
address receiver,
address owner,
uint256 assetsWithFee,
uint256 shares,
RedeemType redeemType
)
internal
{
if (redeemType == RedeemType.NORMAL) {
emit RedeemRequest(receiver, owner, assetsWithFee, shares);
} else if (redeemType == RedeemType.INSTANT) {
emit InstantRedeemRequest(receiver, owner, assetsWithFee, shares);
} else {
revert Errors.UnsupportedRedeemType(uint8(redeemType));
}
}
/**
* @notice Internal function to emit fulfillment events
* @param receiver The address receiving the assets
* @param shares The amount of shares being fulfilled
* @param assetsWithFee The amount of assets including fees
* @param redeemType The type of redemption being fulfilled
*/
function _emitFulfillmentEvent(
address receiver,
uint256 shares,
uint256 assetsWithFee,
RedeemType redeemType
)
internal
{
if (redeemType == RedeemType.NORMAL) {
emit RequestFulfilled(receiver, shares, assetsWithFee);
} else if (redeemType == RedeemType.INSTANT) {
emit InstantRequestFulfilled(receiver, shares, assetsWithFee);
} else {
revert Errors.UnsupportedRedeemType(uint8(redeemType));
}
}
/**
* @notice Internal function to handle fulfillment logic for all redeem types
* @param params The fulfillment parameters
* @dev Validates pending request, updates state, and executes withdrawal
*/
function _processFulfillment(FulfillParams memory params) internal {
MultipliVaultStorage storage $ = _getMultipliVaultStorage();
PendingRedeem storage pending = $.pendingRedeem[params.receiver];
require(
pending.shares != 0 && params.shares <= pending.shares, Errors.InvalidSharesAmount()
);
require(
pending.assets != 0 && params.assetsWithFee <= pending.assets,
Errors.InvalidAssetsAmount()
);
pending.shares -= params.shares;
pending.assets -= params.assetsWithFee;
$.totalPendingAssets -= params.assetsWithFee;
// Emit appropriate event based on redemption type
_emitFulfillmentEvent(
params.receiver, params.shares, params.assetsWithFee, params.redeemType
);
// Execute the withdrawal with appropriate fee handling
_executeWithdrawal(params.receiver, params.assetsWithFee, params.shares, params.redeemType);
}
/**
* @notice Internal function to execute withdrawal with fee handling
* @param receiver The address receiving the assets
* @param assetsWithFee The total amount of assets including fees
* @param shares The amount of shares being burned
* @param redeemType The type of redemption (affects fee calculation)
* @dev Calculates fees based on redemption type and transfers assets to receiver
*/
function _executeWithdrawal(
address receiver,
uint256 assetsWithFee,
uint256 shares,
RedeemType redeemType
)
internal
{
address token = asset();
uint256 feeAmount;
// Calculate fee based on redemption type
if (redeemType == RedeemType.NORMAL) {
feeAmount = _feeOnTotalWithdrawal(token, assetsWithFee);
} else if (redeemType == RedeemType.INSTANT) {
feeAmount = _feeOnTotalInstantWithdrawal(token, assetsWithFee);
} else {
revert Errors.UnsupportedRedeemType(uint8(redeemType));
}
uint256 assets = assetsWithFee - feeAmount;
address recipient = _getFeeRecipient(token);
// Execute the withdrawal
super._withdraw(address(this), receiver, address(this), assets, shares);
// Transfer fees to fee recipient if applicable
if (feeAmount > 0 && recipient != address(0)) {
IERC20(token).safeTransfer(recipient, feeAmount);
}
}
//============================== PRIVATE FUNCTIONS ===============================
/**
* @notice Calculate the percentage change between two prices
* @param oldPrice The previous price
* @param newPrice The new price
* @return The percentage change (1e18 = 100%)
* @dev Used to detect excessive price volatility and trigger emergency pause
*/
function _calculatePercentageChange(
uint256 oldPrice,
uint256 newPrice
)
private
pure
returns (uint256)
{
if (oldPrice == 0) {
return 0;
}
uint256 diff = newPrice > oldPrice ? newPrice - oldPrice : oldPrice - newPrice;
return diff.mulDiv(DENOMINATOR, oldPrice, Math.Rounding.Ceil);
}
/**
* @notice Returns a reference to the MultipliVaultStorage struct
* @return $ Reference to the MultipliVaultStorage struct
* @dev Uses ERC-7201 storage pattern to prevent storage collisions
*/
function _getMultipliVaultStorage() private pure returns (MultipliVaultStorage storage $) {
assembly {
$.slot := MULTIPLI_VAULT_STORAGE_LOCATION
}
}
/**
* @notice Authorize contract upgrades (UUPS pattern)
* @dev Only owner or authorized roles can upgrade the implementation
* @param newImplementation The new implementation contract address
* @custom:security Prevents unauthorized upgrades that could compromise the protocol
*/
function _authorizeUpgrade(address newImplementation) internal virtual override requiresAuth { }
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.30;
/**
* @title Errors
* @notice Defines custom error types for various contract operations.
* @dev This library provides reusable error messages for share operations, authorization checks, and vault interactions.
*/
library Errors {
//============================== GENERICS ===============================
/**
* @notice Thrown when an unauthorized method to a target is called.
* @dev The method must be authorized by setUserRole and setRoleCapability from RolesAuthority.
* @param target The target address.
* @param functionSig The function signature being called.
*/
error TargetMethodNotAuthorized(address target, bytes4 functionSig);
/**
* @notice Thrown when insufficient shares balance is available to complete the operation.
*/
error InsufficientShares();
/**
* @notice Thrown when the operation is called by a user that is not the owner of the shares.
*/
error NotSharesOwner();
/**
* @notice Thrown when the input shares amount is zero.
*/
error SharesAmountZero();
/**
* @notice Thrown when a claim request is fulfilled with an invalid shares amount.
*/
error InvalidSharesAmount();
/**
* @notice Thrown receiver is invalid.
*/
error InvalidReceiverAddress();
/**
* @notice Thrown receiver is invalid.
*/
error InvalidOperatorAddress();
/**
* @notice Thrown owner is invalid.
*/
error InvalidOwnerAddress();
/**
* @notice Thrown shares are not returned during flashRedeem
*/
error SharesNotReturned();
/**
* @notice Thrown when the actual shares received is less than the minimum expected
* @param actualShares The number of shares actually received
* @param minShares The minimum number of shares expected
*/
error InsufficientSharesReceived(uint256 actualShares, uint256 minShares);
/**
* @notice Thrown when the assets required exceeds the maximum the caller is willing to pay
* @param actualAssets The number of assets actually required
* @param maxAssets The maximum number of assets the caller is willing to pay
*/
error ExcessiveAssetsRequired(uint256 actualAssets, uint256 maxAssets);
/**
* @notice Thrown there is a mismatch in Total Supply
*/
error TotalSupplyMismatch();
/**
* @notice Thrown there is a asset balance mismatch in Vault
*/
error AssetBalanceMismatch();
/**
* @notice Thrown when a withdraw is attempted with an amount different than the claimable assets.
*/
error InvalidAssetsAmount();
/**
* @notice Thrown when the new max percentage is greater than the current max percentage.
*/
error InvalidMaxPercentage();
/**
* @notice Thrown when the new fee is greater than the max allowed fee.
*/
error InvalidFee();
/**
* @notice Thrown when the underlying balance has already been updated in the current block.
*/
error UpdateAlreadyCompletedInThisBlock();
/**
* @notice Thrown when redeem() or withdraw() is called.
*/
error UseRequestRedeem();
/**
* @notice Thrown when deposit / mint is with assets < minimum deposit amount
*/
error DepositAmountLessThanThreshold(uint256 amount, uint256 minDepositAmount);
/**
* @notice Thrown when deposit / mint is with assets < minimum deposit amount
*/
error UnsupportedRedeemType(uint8 redeemType);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.30;
/**
* @title MultipliVault
* @notice Interface for the Multipli vault
* @dev Defines events and functions related to redeem requests, fee updates, and balance tracking.
*/
interface IMultipliVault {
/**
* @dev Structure to store pending redeem requests.
* @param assets The amount of assets to be redeemed.
* @param shares The amount of shares to be redeemed.
*/
struct PendingRedeem {
uint256 assets;
uint256 shares;
}
/**
* @notice Emitted when the withdraw fee is updated.
* @param lastFee The previous fee value.
* @param newFee The new fee value.
*/
event WithdrawFeeUpdated(uint256 lastFee, uint256 newFee);
/**
* @notice Emitted when the deposit fee is updated.
* @param lastFee The previous fee value.
* @param newFee The new fee value.
*/
event DepositFeeUpdated(uint256 lastFee, uint256 newFee);
/**
* @notice Emitted when the fee recipient is updated.
* @param lastFeeRecipient The previous fee recipient address.
* @param newFeeRecipient The new fee recipient address.
*/
event FeeRecipientUpdated(address lastFeeRecipient, address newFeeRecipient);
/**
* @notice Emitted when the max percentage is updated.
* @param lastMaxPercentage The previous max percentage.
* @param newMaxPercentage The new max percentage.
*/
event MaxPercentageUpdated(uint256 lastMaxPercentage, uint256 newMaxPercentage);
event MinDepositAmountUpdated(uint256 minDepositAmount, uint256 newMinDepositAmount);
/**
* @notice Emitted when the underlying balance is updated by the oracle.
* @param lastUnderlyingBalance The previous underlying balance.
* @param newUnderlyingBalance The new underlying balance.
*/
event UnderlyingBalanceUpdated(uint256 lastUnderlyingBalance, uint256 newUnderlyingBalance);
/**
* @notice Emitted when a new redeem request is created.
* @param receiver The receiving address.
* @param owner The owner address.
* @param assets The assets amount.
* @param shares The shares amount.
*/
event RedeemRequest(
address indexed receiver, address indexed owner, uint256 assets, uint256 shares
);
/**
* @notice Emitted when a new instant redeem request is created.
* @param receiver The receiving address.
* @param owner The owner address.
* @param assets The assets amount.
* @param shares The shares amount.
*/
event InstantRedeemRequest(
address indexed receiver, address indexed owner, uint256 assets, uint256 shares
);
/**
* @notice Emitted when a redeem request is fulfilled.
* @param receiver The receiving address.
* @param shares The shares amount.
* @param assets The assets amount.
*/
event RequestFulfilled(address indexed receiver, uint256 shares, uint256 assets);
/**
* @notice Emitted when a instant redeem request is fulfilled.
* @param receiver The receiving address.
* @param shares The shares amount.
* @param assets The assets amount.
*/
event InstantRequestFulfilled(address indexed receiver, uint256 shares, uint256 assets);
/**
* @notice Emitted when a flash redeem request is fulfilled.
* @param initiator The address that originally initiated the flashRedeem request
* @param operator The contract that is responsible for paying back the shares
* @param receiver The address that will receive the assets (usdc, wbtc, etc)
* @param shares The amount of shares to redeem (total position size)
* @param assetsWithoutFee The amount of assets excluding fee
* @param fee The amount of assets paid as fee
*/
event FlashRedeemFulfilled(
address indexed initiator,
address indexed operator,
address indexed receiver,
uint256 shares,
uint256 assetsWithoutFee,
uint256 fee
);
/**
* @notice Emitted when a redeem request is cancelled.
* @param receiver The receiving address.
* @param shares The shares amount.
* @param assets The assets amount.
*/
event RequestCancelled(address indexed receiver, uint256 shares, uint256 assets);
/**
* @notice Requests a redeem operation for the specified shares.
* @param shares The number of shares to redeem.
* @param receiver The address to receive the assets.
* @param owner The address of the owner of the shares.
* @return requestId The ID of the created redeem request.
*/
function requestRedeem(
uint256 shares,
address receiver,
address owner
)
external
returns (uint256 requestId);
/**
* @notice Request an instant redemption of shares (requires authorization)
* @param shares The amount of shares to redeem instantly
* @param receiver The address that will receive the assets
* @param owner The address that owns the shares
* @return requestId The ID of the request (always 0)
* @dev Only authorized users (external curators) can call this function
*/
function requestInstantRedeem(
uint256 shares,
address receiver,
address owner
)
external
returns (uint256);
/**
* @notice Flash redemption for unwinding leveraged positions
* @dev Provides USDC upfront, expects equivalent xUSDC shares back after external operator call
* @param initiator The address that originally initiated the request
* @param operator The contract that will handle position unwinding on Euler
* @param receiver The address that will receive the USDC (usually the user)
* @param shares The amount of shares to redeem (total position size)
* @param data Additional data for the operator callback
*/
function flashRedeem(
address initiator,
address operator,
address receiver,
uint256 shares,
bytes calldata data
)
external;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.30;
/**
* @title IVariableVaultFee
* @notice Interface for managing variable fees on vault operations
* @dev Supports both flat and percentage-based fees for deposits and withdrawals
*/
interface IVariableVaultFee {
// Enums
enum FeeType {
FLAT,
PERCENTAGE
}
enum FeeOperation {
DEPOSIT,
WITHDRAWAL,
INSTANT_WITHDRAWAL,
FLASH_REDEEM
}
// Structs
struct FeeConfig {
FeeType feeType;
uint256 feeAmount; // Either percentage (1e17 = 10%) or flat amount (e.g., 100e18)
}
struct AssetFeeConfig {
FeeConfig withdrawalFee;
FeeConfig depositFee;
FeeConfig instantWithdrawalFee;
FeeConfig flashRedeemFee;
address feeRecipient;
}
// Events
event RegisterAsset(address indexed user, address indexed asset, AssetFeeConfig config);
event DeregisterAsset(address indexed user, address indexed asset);
event UpdateAssetFeeConfig(
address indexed user,
address indexed asset,
AssetFeeConfig oldConfig,
AssetFeeConfig newConfig
);
// Errors
/// @notice Thrown when an invalid asset address is provided or asset is not registered
error InvalidAsset();
/// @notice Thrown when asset configuration parameters are invalid
error InvalidAssetConfig();
/// @notice Thrown when attempting to register an asset that is already registered
error AssetAlreadyRegistered();
/// @notice Thrown when amount is insufficient for the operation
error ZeroAmount();
/// @notice Thrown when amount is insufficient for the operation
error InsufficientAmount();
// View Functions
/**
* @notice Calculate fee on raw amount (amount without fees included)
* @param asset The asset address
* @param amount The raw amount
* @param operation The fee operation type (deposit/withdrawal)
* @return The fee amount to be added
*/
function feeOnRaw(
address asset,
uint256 amount,
FeeOperation operation
)
external
view
returns (uint256);
/**
* @notice Calculate fee on total amount (amount with fees already included)
* @param asset The asset address
* @param amount The total amount including fees
* @param operation The fee operation type (deposit/withdrawal)
* @return The fee portion of the total amount
*/
function feeOnTotal(
address asset,
uint256 amount,
FeeOperation operation
)
external
view
returns (uint256);
/**
* @notice Return the Fee Recipient
* @param asset The asset address
* @return The address to which the fee should be sent
*/
function getFeeRecipient(address asset) external view returns (address);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.30;
interface IMultipliVaultCallee {
/// @notice This function is called by the Multipli vault, which sends in flash
/// loaned amount beforehand. The Multipli vault expects the specified shares
/// to be returned by the contract at the end of the call.
/// @param _initiator The address that initiated the flashRedeem request
/// @param _asset The asset to return to Multipli.
/// @param _underlyingAsset The underlying asset sent by Multipli in the flash loan.
/// @param _shares The amount of asset to return.
/// @param _underlyingAmount The amount of flash loaned underlying asset sent by
/// Multipli.
/// @param _additionalData Any additional data for the flash loan.
function onRedemptionFlashLoan(
address _initiator,
address _asset,
address _underlyingAsset,
uint256 _shares,
uint256 _underlyingAmount,
bytes memory _additionalData
)
external;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.30;
import { IVariableVaultFee } from "../interfaces/IVariableVaultFee.sol";
import { Authority } from "@solmate/auth/Auth.sol";
import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
/**
* @title VaultFeeUpgradeable
*/
abstract contract VaultFeeUpgradeable is Initializable {
/**
* @notice Emitted when the fee contract is updated.
* @param user The address initiating the update.
* @param oldFeeContract The previous fee contract.
* @param newFeeContract The new fee contract.
*/
event FeeContractUpdated(address indexed user, address oldFeeContract, address newFeeContract);
error ConfiguredIncorrectly(bytes4 msgSig);
/**
* @custom:storage-location erc7201:multipli.storage.vaultfee
* @dev Structure to hold Vault fee contract data
*/
struct VaultFeeStorage {
IVariableVaultFee feeContract;
}
// Storage slot for the VaultFeeStorageLocation struct.
// keccak256(abi.encode(uint256(keccak256("multipli.storage.vaultfeeV1")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant VaultFeeStorageLocation =
0x4e0114f5bb788bf295d0ab17f602045fbe9841605d1e05a2674fbfa584e94700;
/**
* @dev Returns a reference to the VaultFeeStorage struct.
* @return $ Reference to the VaultFeeStorage struct.
*/
function _getVaultFeeStorage() private pure returns (VaultFeeStorage storage $) {
assembly {
$.slot := VaultFeeStorageLocation
}
}
/**
* @notice Initializes the contract with the vault fee contract.
* @param _feeContract The initial fee contract.
* @dev This function can only be called during contract initialization.
*/
function __VaultFeeUpgreadable_init(IVariableVaultFee _feeContract) internal onlyInitializing {
__VaultFeeUpgreadable_init_unchained(_feeContract);
}
function __VaultFeeUpgreadable_init_unchained(IVariableVaultFee _feeContract)
internal
onlyInitializing
{
VaultFeeStorage storage $ = _getVaultFeeStorage();
$.feeContract = _feeContract;
emit FeeContractUpdated(msg.sender, address(0), address(_feeContract));
}
/**
* @notice Gets the current fee contract.
* @return The current fee contract address.
*/
function feeContract() public view virtual returns (IVariableVaultFee) {
return _getVaultFeeStorage().feeContract;
}
/**
* @notice Updates the fee contract. Developers are expected to add access control for this method.
* @param _feeContract The new fee contract.
*/
function setFeeContract(IVariableVaultFee _feeContract) public virtual {
VaultFeeStorage storage $ = _getVaultFeeStorage();
IVariableVaultFee oldFeeContract = feeContract();
$.feeContract = _feeContract;
emit FeeContractUpdated(msg.sender, address(oldFeeContract), address(_feeContract));
}
function _getFeeRecipient(address asset) internal view virtual returns (address) {
IVariableVaultFee feeContractAddr = feeContract();
return feeContractAddr.getFeeRecipient(asset);
}
/**
* @notice Internal function to calculate fees for operations.
* @dev Refactored common logic for all fee calculation methods.
* @param asset The asset address.
* @param amount The amount to calculate fees for.
* @param operation The fee operation type.
* @param isRawAmount Whether the amount is raw (true) or total (false).
* @return The calculated fee amount.
*/
function _calculateFee(
address asset,
uint256 amount,
IVariableVaultFee.FeeOperation operation,
bool isRawAmount
)
internal
view
virtual
returns (uint256)
{
IVariableVaultFee feeContractAddr = feeContract();
if (address(feeContractAddr) == address(0)) {
revert ConfiguredIncorrectly(msg.sig);
}
if (isRawAmount) {
return feeContractAddr.feeOnRaw(asset, amount, operation);
} else {
return feeContractAddr.feeOnTotal(asset, amount, operation);
}
}
/**
* @notice Calculate fee on raw deposit amount.
* @param asset The asset address.
* @param amount The raw deposit amount.
* @return The fee amount.
*/
function _feeOnRawDeposit(
address asset,
uint256 amount
)
internal
view
virtual
returns (uint256)
{
return _calculateFee(asset, amount, IVariableVaultFee.FeeOperation.DEPOSIT, true);
}
/**
* @notice Calculate fee on raw withdrawal amount.
* @param asset The asset address.
* @param amount The raw withdrawal amount.
* @return The fee amount.
*/
function _feeOnRawWithdrawal(
address asset,
uint256 amount
)
internal
view
virtual
returns (uint256)
{
return _calculateFee(asset, amount, IVariableVaultFee.FeeOperation.WITHDRAWAL, true);
}
/**
* @notice Calculate fee on raw instant withdrawal amount.
* @param asset The asset address.
* @param amount The raw withdrawal amount.
* @return The fee amount.
*/
function _feeOnRawInstantWithdrawal(
address asset,
uint256 amount
)
internal
view
virtual
returns (uint256)
{
return _calculateFee(asset, amount, IVariableVaultFee.FeeOperation.INSTANT_WITHDRAWAL, true);
}
/**
* @notice Calculate fee on total deposit amount.
* @param asset The asset address.
* @param amount The total deposit amount.
* @return The fee amount.
*/
function _feeOnTotalDeposit(
address asset,
uint256 amount
)
internal
view
virtual
returns (uint256)
{
return _calculateFee(asset, amount, IVariableVaultFee.FeeOperation.DEPOSIT, false);
}
/**
* @notice Calculate fee on total withdrawal amount.
* @param asset The asset address.
* @param amount The total withdrawal amount.
* @return The fee amount.
*/
function _feeOnTotalWithdrawal(
address asset,
uint256 amount
)
internal
view
virtual
returns (uint256)
{
return _calculateFee(asset, amount, IVariableVaultFee.FeeOperation.WITHDRAWAL, false);
}
/**
* @notice Calculate fee on total instant withdrawal amount.
* @param asset The asset address.
* @param amount The total withdrawal amount.
* @return The fee amount.
*/
function _feeOnTotalInstantWithdrawal(
address asset,
uint256 amount
)
internal
view
virtual
returns (uint256)
{
return
_calculateFee(asset, amount, IVariableVaultFee.FeeOperation.INSTANT_WITHDRAWAL, false);
}
/**
* @notice Calculate fee on total instant withdrawal amount.
* @param asset The asset address.
* @param amount The total withdrawal amount.
* @return The fee amount.
*/
function _feeOnTotalFlashWithdrawal(
address asset,
uint256 amount
)
internal
view
virtual
returns (uint256)
{
// todo: create a new redemption type
// temporarily using INSTANT_WITHDRAWAL fee
return _calculateFee(asset, amount, IVariableVaultFee.FeeOperation.FLASH_REDEEM, false);
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.30;
import { Authority } from "@solmate/auth/Auth.sol";
import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
/**
* @title AuthUpgradeable
* @notice Upgradable fork of https://github.com/transmissions11/solmate/blob/main/src/auth/Auth.sol
* @dev Provides role-based authorization mechanism with upgradeability support.
*/
abstract contract AuthUpgradeable is Initializable {
/**
* @notice Emitted when ownership is transferred.
* @param user The address of the old owner.
* @param newOwner The address receiving ownership.
*/
event OwnershipTransferred(address indexed user, address indexed newOwner);
/**
* @notice Emitted when the authority contract is updated.
* @param user The address initiating the update.
* @param newAuthority The new authority contract.
*/
event AuthorityUpdated(address indexed user, Authority indexed newAuthority);
/**
* @custom:storage-location erc7201:auth.storage
* @dev Structure to hold authorization data.
*/
struct AuthStorage {
address owner;
Authority authority;
}
// Storage slot for the AuthStorage struct.
// keccak256(abi.encode(uint256(keccak256("auth.storage")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant AuthStorageLocation =
0xdd3fd67aef415aded9493b31ad20a02d2991d4bb2760431cc729821271eaea00;
/**
* @dev Returns a reference to the AuthStorage struct.
* @return $ Reference to the AuthStorage struct.
*/
function _getAuthStorage() private pure returns (AuthStorage storage $) {
assembly {
$.slot := AuthStorageLocation
}
}
/**
* @notice Initializes the contract with the specified owner and authority.
* @param _owner The address of the initial owner.
* @param _authority The initial authority contract.
* @dev This function can only be called during contract initialization.
*/
function __Auth_init(address _owner, Authority _authority) internal onlyInitializing {
__Auth_init_unchained(_owner, _authority);
}
function __Auth_init_unchained(
address _owner,
Authority _authority
)
internal
onlyInitializing
{
AuthStorage storage $ = _getAuthStorage();
$.owner = _owner;
$.authority = _authority;
emit OwnershipTransferred(msg.sender, _owner);
emit AuthorityUpdated(msg.sender, _authority);
}
/**
* @notice Modifier to restrict access to authorized users.
*/
modifier requiresAuth() virtual {
require(isAuthorized(msg.sender, msg.sig), "UNAUTHORIZED");
_;
}
/**
* @notice Checks if a user is authorized to call a specific function.
* @param user The address of the user.
* @param functionSig The function signature being called.
* @return bool True if authorized, false otherwise.
*/
function isAuthorized(address user, bytes4 functionSig) public view virtual returns (bool) {
AuthStorage storage $ = _getAuthStorage();
Authority auth = $.authority;
return (address(auth) != address(0) && auth.canCall(user, address(this), functionSig))
|| user == $.owner;
}
/**
* @notice Gets the address of the owner.
* @return The address of the current owner.
*/
function owner() public view virtual returns (address) {
return _getAuthStorage().owner;
}
/**
* @notice Gets the current authority contract.
* @return The current authority contract address.
*/
function authority() public view virtual returns (Authority) {
return _getAuthStorage().authority;
}
/**
* @notice Updates the authority contract.
* @param newAuthority The new authority contract.
* @dev Can only be called by the owner or current authority.
*/
function setAuthority(Authority newAuthority) public virtual {
AuthStorage storage $ = _getAuthStorage();
require(
msg.sender == $.owner || $.authority.canCall(msg.sender, address(this), msg.sig),
"UNAUTHORIZED"
);
$.authority = newAuthority;
emit AuthorityUpdated(msg.sender, newAuthority);
}
/**
* @notice Transfers ownership to a new address.
* @param newOwner The address to receive ownership.
* @dev Can only be called by an authorized user.
*/
function transferOwnership(address newOwner) public virtual requiresAuth {
AuthStorage storage $ = _getAuthStorage();
$.owner = newOwner;
emit OwnershipTransferred(msg.sender, newOwner);
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.30;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
/**
* @title FundMovementHelperUpgradeable
* @notice Abstract contract providing fund transfer functionality with recipient whitelisting
* @dev This contract implements a whitelist-based fund transfer system for upgradeable contracts.
* It allows authorized users to transfer funds only to pre-approved recipients.
*
* Key features:
* - Recipient whitelisting mechanism
* - Safe ERC20 token transfers
* - Upgradeable storage pattern using ERC-7201
* - Event emission for transparency
*
* @custom:security-contact [email protected]
*/
abstract contract FundMovementHelperUpgradeable is Initializable {
using SafeERC20 for IERC20;
//============================== ERRORS ===============================
/// @notice Thrown when attempting to set the same whitelist status for a user
error NoChangeInWhitelistStatus();
/// @notice Thrown when attempting to transfer zero amount
error AmountZero();
/// @notice Thrown when attempting to transfer to a non-whitelisted recipient
error RecipientNotWhitelisted();
/// @notice Thrown when address is 0 (address(0))
error AddressZero();
//============================== EVENTS ===============================
/**
* @notice Emitted when funds are removed from the contract
* @param initiator The address that initiated the fund removal
* @param asset The address of the asset being transferred
* @param amount The amount of assets transferred
* @param recipient The address receiving the funds
*/
event FundsRemoved(
address indexed initiator, address indexed asset, uint256 amount, address indexed recipient
);
/**
* @notice Emitted when a user's whitelist status is updated
* @param initiator The address that initiated the whitelist update
* @param recipient The address whose whitelist status was updated
* @param isWhitelisted The new whitelist status (true = whitelisted, false = removed)
*/
event WhitelistUpdated(
address indexed initiator, address indexed recipient, bool isWhitelisted
);
//============================== STORAGE ===============================
/// @custom:storage-location erc7201:multipli.storage.FundMovementHelperStorage
struct FundMovementHelperStorage {
/// @dev Mapping to track whitelisted fund transfer recipients
mapping(address => bool) whitelistedRecipients;
}
// Storage slot for the FundMovementHelperStorage struct.
// keccak256(abi.encode(uint256(keccak256("multipli.storage.FundMovementHelperStorage")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant FUND_MOVEMENT_STORAGE_LOCATION =
0x2bbdf87c296f0fc445d947563c77d7b805fc738a2e220084769a264d45deaf00;
//============================== INITIALIZER ===============================
/**
* @notice Initializes the FundMovementHelper contract
* @dev This function should be called during contract initialization
*/
function __FundMovementHelper_init() internal onlyInitializing {
__FundMovementHelper_init_unchained();
}
/**
* @notice Unchained initializer for FundMovementHelper
* @dev Contains the actual initialization logic
*/
function __FundMovementHelper_init_unchained() internal onlyInitializing {
// No initialization logic needed currently
}
//============================== VIEW FUNCTIONS ===============================
/**
* @notice Checks if a user is whitelisted as a fund transfer recipient
* @param user The address to check
* @return isWhitelisted True if the user is whitelisted, false otherwise
*/
function isRecipientWhitelisted(address user) public view returns (bool isWhitelisted) {
FundMovementHelperStorage storage $ = _getFundMovementHelperStorage();
return $.whitelistedRecipients[user];
}
//============================== INTERNAL FUNCTIONS ===============================
/**
* @notice Updates the whitelist status of a fund transfer recipient
* @dev This method is expected to be called from the inheriting contract with proper access controls
* @param user The address to update whitelist status for
* @param isWhitelisted True to whitelist the user, false to remove from whitelist
*/
function _whitelistFundTransferRecipient(address user, bool isWhitelisted) internal virtual {
FundMovementHelperStorage storage $ = _getFundMovementHelperStorage();
if (user == address(0)) {
revert AddressZero();
}
if ($.whitelistedRecipients[user] == isWhitelisted) {
revert NoChangeInWhitelistStatus();
}
$.whitelistedRecipients[user] = isWhitelisted;
emit WhitelistUpdated(msg.sender, user, isWhitelisted);
}
/**
* @notice Removes funds from the contract and transfers them to a whitelisted recipient
* @dev This method should be called from the inheriting contract with proper access controls
* @param asset The address of the ERC20 token to transfer
* @param amount The amount of tokens to transfer
* @param recipient The address to receive the funds (must be whitelisted)
*/
function _removeFunds(address asset, uint256 amount, address recipient) internal virtual {
if (amount == 0) {
revert AmountZero();
}
if (!isRecipientWhitelisted(recipient)) {
revert RecipientNotWhitelisted();
}
IERC20(asset).safeTransfer(recipient, amount);
emit FundsRemoved(msg.sender, asset, amount, recipient);
}
//============================== PRIVATE FUNCTIONS ===============================
/**
* @dev Returns a reference to the FundMovementHelperStorage struct
* @return $ Reference to the FundMovementHelperStorage struct
*/
function _getFundMovementHelperStorage()
private
pure
returns (FundMovementHelperStorage storage $)
{
assembly {
$.slot := FUND_MOVEMENT_STORAGE_LOCATION
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (utils/math/Math.sol)
pragma solidity ^0.8.20;
import {Panic} from "../Panic.sol";
import {SafeCast} from "./SafeCast.sol";
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Floor, // Toward negative infinity
Ceil, // Toward positive infinity
Trunc, // Toward zero
Expand // Away from zero
}
/**
* @dev Return the 512-bit addition of two uint256.
*
* The result is stored in two 256 variables such that sum = high * 2²⁵⁶ + low.
*/
function add512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {
assembly ("memory-safe") {
low := add(a, b)
high := lt(low, a)
}
}
/**
* @dev Return the 512-bit multiplication of two uint256.
*
* The result is stored in two 256 variables such that product = high * 2²⁵⁶ + low.
*/
function mul512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {
// 512-bit multiply [high low] = x * y. Compute the product mod 2²⁵⁶ and mod 2²⁵⁶ - 1, then use
// the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = high * 2²⁵⁶ + low.
assembly ("memory-safe") {
let mm := mulmod(a, b, not(0))
low := mul(a, b)
high := sub(sub(mm, low), lt(mm, low))
}
}
/**
* @dev Returns the addition of two unsigned integers, with a success flag (no overflow).
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
uint256 c = a + b;
success = c >= a;
result = c * SafeCast.toUint(success);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with a success flag (no overflow).
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
uint256 c = a - b;
success = c <= a;
result = c * SafeCast.toUint(success);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with a success flag (no overflow).
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
uint256 c = a * b;
assembly ("memory-safe") {
// Only true when the multiplication doesn't overflow
// (c / a == b) || (a == 0)
success := or(eq(div(c, a), b), iszero(a))
}
// equivalent to: success ? c : 0
result = c * SafeCast.toUint(success);
}
}
/**
* @dev Returns the division of two unsigned integers, with a success flag (no division by zero).
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
success = b > 0;
assembly ("memory-safe") {
// The `DIV` opcode returns zero when the denominator is 0.
result := div(a, b)
}
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero).
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
success = b > 0;
assembly ("memory-safe") {
// The `MOD` opcode returns zero when the denominator is 0.
result := mod(a, b)
}
}
}
/**
* @dev Unsigned saturating addition, bounds to `2²⁵⁶ - 1` instead of overflowing.
*/
function saturatingAdd(uint256 a, uint256 b) internal pure returns (uint256) {
(bool success, uint256 result) = tryAdd(a, b);
return ternary(success, result, type(uint256).max);
}
/**
* @dev Unsigned saturating subtraction, bounds to zero instead of overflowing.
*/
function saturatingSub(uint256 a, uint256 b) internal pure returns (uint256) {
(, uint256 result) = trySub(a, b);
return result;
}
/**
* @dev Unsigned saturating multiplication, bounds to `2²⁵⁶ - 1` instead of overflowing.
*/
function saturatingMul(uint256 a, uint256 b) internal pure returns (uint256) {
(bool success, uint256 result) = tryMul(a, b);
return ternary(success, result, type(uint256).max);
}
/**
* @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.
*
* IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.
* However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute
* one branch when needed, making this function more expensive.
*/
function ternary(bool condition, uint256 a, uint256 b) internal pure returns (uint256) {
unchecked {
// branchless ternary works because:
// b ^ (a ^ b) == a
// b ^ 0 == b
return b ^ ((a ^ b) * SafeCast.toUint(condition));
}
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return ternary(a > b, a, b);
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return ternary(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.
Panic.panic(Panic.DIVISION_BY_ZERO);
}
// The following calculation ensures accurate ceiling division without overflow.
// Since a is non-zero, (a - 1) / b will not overflow.
// The largest possible result occurs when (a - 1) / b is type(uint256).max,
// but the largest value we can obtain is type(uint256).max - 1, which happens
// when a = type(uint256).max and b = 1.
unchecked {
return SafeCast.toUint(a > 0) * ((a - 1) / b + 1);
}
}
/**
* @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
* denominator == 0.
*
* 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 {
(uint256 high, uint256 low) = mul512(x, y);
// Handle non-overflow cases, 256 by 256 division.
if (high == 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 low / denominator;
}
// Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0.
if (denominator <= high) {
Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_OVERFLOW));
}
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [high low].
uint256 remainder;
assembly ("memory-safe") {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
high := sub(high, gt(remainder, low))
low := sub(low, 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 ("memory-safe") {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [high low] by twos.
low := div(low, twos)
// Flip twos such that it is 2²⁵⁶ / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from high into low.
low |= high * twos;
// Invert denominator mod 2²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such
// that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv ≡ 1 mod 2⁴.
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⁸
inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶
inverse *= 2 - denominator * inverse; // inverse mod 2³²
inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴
inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸
inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶
// 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²⁵⁶. Since the preconditions guarantee that the outcome is
// less than 2²⁵⁶, this is the final result. We don't need to compute the high bits of the result and high
// is no longer required.
result = low * inverse;
return result;
}
}
/**
* @dev 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) {
return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0);
}
/**
* @dev Calculates floor(x * y >> n) with full precision. Throws if result overflows a uint256.
*/
function mulShr(uint256 x, uint256 y, uint8 n) internal pure returns (uint256 result) {
unchecked {
(uint256 high, uint256 low) = mul512(x, y);
if (high >= 1 << n) {
Panic.panic(Panic.UNDER_OVERFLOW);
}
return (high << (256 - n)) | (low >> n);
}
}
/**
* @dev Calculates x * y >> n with full precision, following the selected rounding direction.
*/
function mulShr(uint256 x, uint256 y, uint8 n, Rounding rounding) internal pure returns (uint256) {
return mulShr(x, y, n) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, 1 << n) > 0);
}
/**
* @dev Calculate the modular multiplicative inverse of a number in Z/nZ.
*
* If n is a prime, then Z/nZ is a field. In that case all elements are inversible, except 0.
* If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible.
*
* If the input value is not inversible, 0 is returned.
*
* NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Fermat's little theorem and get the
* inverse using `Math.modExp(a, n - 2, n)`. See {invModPrime}.
*/
function invMod(uint256 a, uint256 n) internal pure returns (uint256) {
unchecked {
if (n == 0) return 0;
// The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version)
// Used to compute integers x and y such that: ax + ny = gcd(a, n).
// When the gcd is 1, then the inverse of a modulo n exists and it's x.
// ax + ny = 1
// ax = 1 + (-y)n
// ax ≡ 1 (mod n) # x is the inverse of a modulo n
// If the remainder is 0 the gcd is n right away.
uint256 remainder = a % n;
uint256 gcd = n;
// Therefore the initial coefficients are:
// ax + ny = gcd(a, n) = n
// 0a + 1n = n
int256 x = 0;
int256 y = 1;
while (remainder != 0) {
uint256 quotient = gcd / remainder;
(gcd, remainder) = (
// The old remainder is the next gcd to try.
remainder,
// Compute the next remainder.
// Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd
// where gcd is at most n (capped to type(uint256).max)
gcd - remainder * quotient
);
(x, y) = (
// Increment the coefficient of a.
y,
// Decrement the coefficient of n.
// Can overflow, but the result is casted to uint256 so that the
// next value of y is "wrapped around" to a value between 0 and n - 1.
x - y * int256(quotient)
);
}
if (gcd != 1) return 0; // No inverse exists.
return ternary(x < 0, n - uint256(-x), uint256(x)); // Wrap the result if it's negative.
}
}
/**
* @dev Variant of {invMod}. More efficient, but only works if `p` is known to be a prime greater than `2`.
*
* From https://en.wikipedia.org/wiki/Fermat%27s_little_theorem[Fermat's little theorem], we know that if p is
* prime, then `a**(p-1) ≡ 1 mod p`. As a consequence, we have `a * a**(p-2) ≡ 1 mod p`, which means that
* `a**(p-2)` is the modular multiplicative inverse of a in Fp.
*
* NOTE: this function does NOT check that `p` is a prime greater than `2`.
*/
function invModPrime(uint256 a, uint256 p) internal view returns (uint256) {
unchecked {
return Math.modExp(a, p - 2, p);
}
}
/**
* @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m)
*
* Requirements:
* - modulus can't be zero
* - underlying staticcall to precompile must succeed
*
* IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make
* sure the chain you're using it on supports the precompiled contract for modular exponentiation
* at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise,
* the underlying function will succeed given the lack of a revert, but the result may be incorrectly
* interpreted as 0.
*/
function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) {
(bool success, uint256 result) = tryModExp(b, e, m);
if (!success) {
Panic.panic(Panic.DIVISION_BY_ZERO);
}
return result;
}
/**
* @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m).
* It includes a success flag indicating if the operation succeeded. Operation will be marked as failed if trying
* to operate modulo 0 or if the underlying precompile reverted.
*
* IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain
* you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in
* https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack
* of a revert, but the result may be incorrectly interpreted as 0.
*/
function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) {
if (m == 0) return (false, 0);
assembly ("memory-safe") {
let ptr := mload(0x40)
// | Offset | Content | Content (Hex) |
// |-----------|------------|--------------------------------------------------------------------|
// | 0x00:0x1f | size of b | 0x0000000000000000000000000000000000000000000000000000000000000020 |
// | 0x20:0x3f | size of e | 0x0000000000000000000000000000000000000000000000000000000000000020 |
// | 0x40:0x5f | size of m | 0x0000000000000000000000000000000000000000000000000000000000000020 |
// | 0x60:0x7f | value of b | 0x<.............................................................b> |
// | 0x80:0x9f | value of e | 0x<.............................................................e> |
// | 0xa0:0xbf | value of m | 0x<.............................................................m> |
mstore(ptr, 0x20)
mstore(add(ptr, 0x20), 0x20)
mstore(add(ptr, 0x40), 0x20)
mstore(add(ptr, 0x60), b)
mstore(add(ptr, 0x80), e)
mstore(add(ptr, 0xa0), m)
// Given the result < m, it's guaranteed to fit in 32 bytes,
// so we can use the memory scratch space located at offset 0.
success := staticcall(gas(), 0x05, ptr, 0xc0, 0x00, 0x20)
result := mload(0x00)
}
}
/**
* @dev Variant of {modExp} that supports inputs of arbitrary length.
*/
function modExp(bytes memory b, bytes memory e, bytes memory m) internal view returns (bytes memory) {
(bool success, bytes memory result) = tryModExp(b, e, m);
if (!success) {
Panic.panic(Panic.DIVISION_BY_ZERO);
}
return result;
}
/**
* @dev Variant of {tryModExp} that supports inputs of arbitrary length.
*/
function tryModExp(
bytes memory b,
bytes memory e,
bytes memory m
) internal view returns (bool success, bytes memory result) {
if (_zeroBytes(m)) return (false, new bytes(0));
uint256 mLen = m.length;
// Encode call args in result and move the free memory pointer
result = abi.encodePacked(b.length, e.length, mLen, b, e, m);
assembly ("memory-safe") {
let dataPtr := add(result, 0x20)
// Write result on top of args to avoid allocating extra memory.
success := staticcall(gas(), 0x05, dataPtr, mload(result), dataPtr, mLen)
// Overwrite the length.
// result.length > returndatasize() is guaranteed because returndatasize() == m.length
mstore(result, mLen)
// Set the memory pointer after the returned data.
mstore(0x40, add(dataPtr, mLen))
}
}
/**
* @dev Returns whether the provided byte array is zero.
*/
function _zeroBytes(bytes memory byteArray) private pure returns (bool) {
for (uint256 i = 0; i < byteArray.length; ++i) {
if (byteArray[i] != 0) {
return false;
}
}
return true;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
* towards zero.
*
* This method is based on Newton's method for computing square roots; the algorithm is restricted to only
* using integer operations.
*/
function sqrt(uint256 a) internal pure returns (uint256) {
unchecked {
// Take care of easy edge cases when a == 0 or a == 1
if (a <= 1) {
return a;
}
// In this function, we use Newton's method to get a root of `f(x) := x² - a`. It involves building a
// sequence x_n that converges toward sqrt(a). For each iteration x_n, we also define the error between
// the current value as `ε_n = | x_n - sqrt(a) |`.
//
// For our first estimation, we consider `e` the smallest power of 2 which is bigger than the square root
// of the target. (i.e. `2**(e-1) ≤ sqrt(a) < 2**e`). We know that `e ≤ 128` because `(2¹²⁸)² = 2²⁵⁶` is
// bigger than any uint256.
//
// By noticing that
// `2**(e-1) ≤ sqrt(a) < 2**e → (2**(e-1))² ≤ a < (2**e)² → 2**(2*e-2) ≤ a < 2**(2*e)`
// we can deduce that `e - 1` is `log2(a) / 2`. We can thus compute `x_n = 2**(e-1)` using a method similar
// to the msb function.
uint256 aa = a;
uint256 xn = 1;
if (aa >= (1 << 128)) {
aa >>= 128;
xn <<= 64;
}
if (aa >= (1 << 64)) {
aa >>= 64;
xn <<= 32;
}
if (aa >= (1 << 32)) {
aa >>= 32;
xn <<= 16;
}
if (aa >= (1 << 16)) {
aa >>= 16;
xn <<= 8;
}
if (aa >= (1 << 8)) {
aa >>= 8;
xn <<= 4;
}
if (aa >= (1 << 4)) {
aa >>= 4;
xn <<= 2;
}
if (aa >= (1 << 2)) {
xn <<= 1;
}
// We now have x_n such that `x_n = 2**(e-1) ≤ sqrt(a) < 2**e = 2 * x_n`. This implies ε_n ≤ 2**(e-1).
//
// We can refine our estimation by noticing that the middle of that interval minimizes the error.
// If we move x_n to equal 2**(e-1) + 2**(e-2), then we reduce the error to ε_n ≤ 2**(e-2).
// This is going to be our x_0 (and ε_0)
xn = (3 * xn) >> 1; // ε_0 := | x_0 - sqrt(a) | ≤ 2**(e-2)
// From here, Newton's method give us:
// x_{n+1} = (x_n + a / x_n) / 2
//
// One should note that:
// x_{n+1}² - a = ((x_n + a / x_n) / 2)² - a
// = ((x_n² + a) / (2 * x_n))² - a
// = (x_n⁴ + 2 * a * x_n² + a²) / (4 * x_n²) - a
// = (x_n⁴ + 2 * a * x_n² + a² - 4 * a * x_n²) / (4 * x_n²)
// = (x_n⁴ - 2 * a * x_n² + a²) / (4 * x_n²)
// = (x_n² - a)² / (2 * x_n)²
// = ((x_n² - a) / (2 * x_n))²
// ≥ 0
// Which proves that for all n ≥ 1, sqrt(a) ≤ x_n
//
// This gives us the proof of quadratic convergence of the sequence:
// ε_{n+1} = | x_{n+1} - sqrt(a) |
// = | (x_n + a / x_n) / 2 - sqrt(a) |
// = | (x_n² + a - 2*x_n*sqrt(a)) / (2 * x_n) |
// = | (x_n - sqrt(a))² / (2 * x_n) |
// = | ε_n² / (2 * x_n) |
// = ε_n² / | (2 * x_n) |
//
// For the first iteration, we have a special case where x_0 is known:
// ε_1 = ε_0² / | (2 * x_0) |
// ≤ (2**(e-2))² / (2 * (2**(e-1) + 2**(e-2)))
// ≤ 2**(2*e-4) / (3 * 2**(e-1))
// ≤ 2**(e-3) / 3
// ≤ 2**(e-3-log2(3))
// ≤ 2**(e-4.5)
//
// For the following iterations, we use the fact that, 2**(e-1) ≤ sqrt(a) ≤ x_n:
// ε_{n+1} = ε_n² / | (2 * x_n) |
// ≤ (2**(e-k))² / (2 * 2**(e-1))
// ≤ 2**(2*e-2*k) / 2**e
// ≤ 2**(e-2*k)
xn = (xn + a / xn) >> 1; // ε_1 := | x_1 - sqrt(a) | ≤ 2**(e-4.5) -- special case, see above
xn = (xn + a / xn) >> 1; // ε_2 := | x_2 - sqrt(a) | ≤ 2**(e-9) -- general case with k = 4.5
xn = (xn + a / xn) >> 1; // ε_3 := | x_3 - sqrt(a) | ≤ 2**(e-18) -- general case with k = 9
xn = (xn + a / xn) >> 1; // ε_4 := | x_4 - sqrt(a) | ≤ 2**(e-36) -- general case with k = 18
xn = (xn + a / xn) >> 1; // ε_5 := | x_5 - sqrt(a) | ≤ 2**(e-72) -- general case with k = 36
xn = (xn + a / xn) >> 1; // ε_6 := | x_6 - sqrt(a) | ≤ 2**(e-144) -- general case with k = 72
// Because e ≤ 128 (as discussed during the first estimation phase), we know have reached a precision
// ε_6 ≤ 2**(e-144) < 1. Given we're operating on integers, then we can ensure that xn is now either
// sqrt(a) or sqrt(a) + 1.
return xn - SafeCast.toUint(xn > a / xn);
}
}
/**
* @dev 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 + SafeCast.toUint(unsignedRoundsUp(rounding) && result * result < a);
}
}
/**
* @dev Return the log in base 2 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log2(uint256 x) internal pure returns (uint256 r) {
// If value has upper 128 bits set, log2 result is at least 128
r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;
// If upper 64 bits of 128-bit half set, add 64 to result
r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;
// If upper 32 bits of 64-bit half set, add 32 to result
r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;
// If upper 16 bits of 32-bit half set, add 16 to result
r |= SafeCast.toUint((x >> r) > 0xffff) << 4;
// If upper 8 bits of 16-bit half set, add 8 to result
r |= SafeCast.toUint((x >> r) > 0xff) << 3;
// If upper 4 bits of 8-bit half set, add 4 to result
r |= SafeCast.toUint((x >> r) > 0xf) << 2;
// Shifts value right by the current result and use it as an index into this lookup table:
//
// | x (4 bits) | index | table[index] = MSB position |
// |------------|---------|-----------------------------|
// | 0000 | 0 | table[0] = 0 |
// | 0001 | 1 | table[1] = 0 |
// | 0010 | 2 | table[2] = 1 |
// | 0011 | 3 | table[3] = 1 |
// | 0100 | 4 | table[4] = 2 |
// | 0101 | 5 | table[5] = 2 |
// | 0110 | 6 | table[6] = 2 |
// | 0111 | 7 | table[7] = 2 |
// | 1000 | 8 | table[8] = 3 |
// | 1001 | 9 | table[9] = 3 |
// | 1010 | 10 | table[10] = 3 |
// | 1011 | 11 | table[11] = 3 |
// | 1100 | 12 | table[12] = 3 |
// | 1101 | 13 | table[13] = 3 |
// | 1110 | 14 | table[14] = 3 |
// | 1111 | 15 | table[15] = 3 |
//
// The lookup table is represented as a 32-byte value with the MSB positions for 0-15 in the last 16 bytes.
assembly ("memory-safe") {
r := or(r, byte(shr(r, x), 0x0000010102020202030303030303030300000000000000000000000000000000))
}
}
/**
* @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 + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << result < value);
}
}
/**
* @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 + SafeCast.toUint(unsignedRoundsUp(rounding) && 10 ** result < value);
}
}
/**
* @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 x) internal pure returns (uint256 r) {
// If value has upper 128 bits set, log2 result is at least 128
r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;
// If upper 64 bits of 128-bit half set, add 64 to result
r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;
// If upper 32 bits of 64-bit half set, add 32 to result
r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;
// If upper 16 bits of 32-bit half set, add 16 to result
r |= SafeCast.toUint((x >> r) > 0xffff) << 4;
// Add 1 if upper 8 bits of 16-bit half set, and divide accumulated result by 8
return (r >> 3) | SafeCast.toUint((x >> r) > 0xff);
}
/**
* @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 + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << (result << 3) < value);
}
}
/**
* @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.2.0) (utils/Address.sol)
pragma solidity ^0.8.20;
import {Errors} from "./Errors.sol";
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @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 Errors.InsufficientBalance(address(this).balance, amount);
}
(bool success, bytes memory returndata) = recipient.call{value: amount}("");
if (!success) {
_revert(returndata);
}
}
/**
* @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
* {Errors.FailedCall} 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 Errors.InsufficientBalance(address(this).balance, value);
}
(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 {Errors.FailedCall}) 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 {Errors.FailedCall} 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 {Errors.FailedCall}.
*/
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
assembly ("memory-safe") {
revert(add(returndata, 0x20), mload(returndata))
}
} else {
revert Errors.FailedCall();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.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 ERC-20
* applications.
*/
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}.
*
* Both 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;
}
/// @inheritdoc IERC20
function totalSupply() public view virtual returns (uint256) {
return _totalSupply;
}
/// @inheritdoc IERC20
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;
}
/// @inheritdoc IERC20
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}.
*
* Skips emitting an {Approval} event indicating an allowance update. This is not
* required by the ERC. See {xref-ERC20-_approve-address-address-uint256-bool-}[_approve].
*
* 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:
*
* ```solidity
* 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.3.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC-20 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 {
/**
* @dev An operation with an ERC-20 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 Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {
return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {
return _callOptionalReturnBool(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.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
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.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
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.
*
* NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
* only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
* set here.
*/
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 Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
safeTransfer(token, to, value);
} else if (!token.transferAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
* has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferFromAndCallRelaxed(
IERC1363 token,
address from,
address to,
uint256 value,
bytes memory data
) internal {
if (to.code.length == 0) {
safeTransferFrom(token, from, to, value);
} else if (!token.transferFromAndCall(from, to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
* Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
* once without retrying, and relies on the returned value to be true.
*
* Reverts if the returned value is other than `true`.
*/
function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
forceApprove(token, to, value);
} else if (!token.approveAndCall(to, value, data)) {
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 {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
// bubble errors
if iszero(success) {
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize())
revert(ptr, returndatasize())
}
returnSize := returndatasize()
returnValue := mload(0)
}
if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
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 silently catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
bool success;
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
returnSize := returndatasize()
returnValue := mload(0)
}
return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/extensions/ERC4626.sol)
pragma solidity ^0.8.20;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {ERC20Upgradeable} from "../ERC20Upgradeable.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol";
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
import {Initializable} from "../../../proxy/utils/Initializable.sol";
/**
* @dev Implementation of the ERC-4626 "Tokenized Vault Standard" as defined in
* https://eips.ethereum.org/EIPS/eip-4626[ERC-4626].
*
* This extension allows the minting and burning of "shares" (represented using the ERC-20 inheritance) in exchange for
* underlying "assets" through standardized {deposit}, {mint}, {redeem} and {burn} workflows. This contract extends
* the ERC-20 standard. Any additional extensions included along it would affect the "shares" token represented by this
* contract and not the "assets" token which is an independent contract.
*
* [CAUTION]
* ====
* In empty (or nearly empty) ERC-4626 vaults, deposits are at high risk of being stolen through frontrunning
* with a "donation" to the vault that inflates the price of a share. This is variously known as a donation or inflation
* attack and is essentially a problem of slippage. Vault deployers can protect against this attack by making an initial
* deposit of a non-trivial amount of the asset, such that price manipulation becomes infeasible. Withdrawals may
* similarly be affected by slippage. Users can protect against this attack as well as unexpected slippage in general by
* verifying the amount received is as expected, using a wrapper that performs these checks such as
* https://github.com/fei-protocol/ERC4626#erc4626router-and-base[ERC4626Router].
*
* Since v4.9, this implementation introduces configurable virtual assets and shares to help developers mitigate that risk.
* The `_decimalsOffset()` corresponds to an offset in the decimal representation between the underlying asset's decimals
* and the vault decimals. This offset also determines the rate of virtual shares to virtual assets in the vault, which
* itself determines the initial exchange rate. While not fully preventing the attack, analysis shows that the default
* offset (0) makes it non-profitable even if an attacker is able to capture value from multiple user deposits, as a result
* of the value being captured by the virtual shares (out of the attacker's donation) matching the attacker's expected gains.
* With a larger offset, the attack becomes orders of magnitude more expensive than it is profitable. More details about the
* underlying math can be found xref:ROOT:erc4626.adoc#inflation-attack[here].
*
* The drawback of this approach is that the virtual shares do capture (a very small) part of the value being accrued
* to the vault. Also, if the vault experiences losses, the users try to exit the vault, the virtual shares and assets
* will cause the first user to exit to experience reduced losses in detriment to the last users that will experience
* bigger losses. Developers willing to revert back to the pre-v4.9 behavior just need to override the
* `_convertToShares` and `_convertToAssets` functions.
*
* To learn more, check out our xref:ROOT:erc4626.adoc[ERC-4626 guide].
* ====
*/
abstract contract ERC4626Upgradeable is Initializable, ERC20Upgradeable, IERC4626 {
using Math for uint256;
/// @custom:storage-location erc7201:openzeppelin.storage.ERC4626
struct ERC4626Storage {
IERC20 _asset;
uint8 _underlyingDecimals;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ERC4626")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant ERC4626StorageLocation = 0x0773e532dfede91f04b12a73d3d2acd361424f41f76b4fb79f090161e36b4e00;
function _getERC4626Storage() private pure returns (ERC4626Storage storage $) {
assembly {
$.slot := ERC4626StorageLocation
}
}
/**
* @dev Attempted to deposit more assets than the max amount for `receiver`.
*/
error ERC4626ExceededMaxDeposit(address receiver, uint256 assets, uint256 max);
/**
* @dev Attempted to mint more shares than the max amount for `receiver`.
*/
error ERC4626ExceededMaxMint(address receiver, uint256 shares, uint256 max);
/**
* @dev Attempted to withdraw more assets than the max amount for `receiver`.
*/
error ERC4626ExceededMaxWithdraw(address owner, uint256 assets, uint256 max);
/**
* @dev Attempted to redeem more shares than the max amount for `receiver`.
*/
error ERC4626ExceededMaxRedeem(address owner, uint256 shares, uint256 max);
/**
* @dev Set the underlying asset contract. This must be an ERC20-compatible contract (ERC-20 or ERC-777).
*/
function __ERC4626_init(IERC20 asset_) internal onlyInitializing {
__ERC4626_init_unchained(asset_);
}
function __ERC4626_init_unchained(IERC20 asset_) internal onlyInitializing {
ERC4626Storage storage $ = _getERC4626Storage();
(bool success, uint8 assetDecimals) = _tryGetAssetDecimals(asset_);
$._underlyingDecimals = success ? assetDecimals : 18;
$._asset = asset_;
}
/**
* @dev Attempts to fetch the asset decimals. A return value of false indicates that the attempt failed in some way.
*/
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);
}
/**
* @dev Decimals are computed by adding the decimal offset on top of the underlying asset's decimals. This
* "original" value is cached during construction of the vault contract. If this read operation fails (e.g., the
* asset has not been created yet), a default of 18 is used to represent the underlying asset's decimals.
*
* See {IERC20Metadata-decimals}.
*/
function decimals() public view virtual override(IERC20Metadata, ERC20Upgradeable) returns (uint8) {
ERC4626Storage storage $ = _getERC4626Storage();
return $._underlyingDecimals + _decimalsOffset();
}
/// @inheritdoc IERC4626
function asset() public view virtual returns (address) {
ERC4626Storage storage $ = _getERC4626Storage();
return address($._asset);
}
/// @inheritdoc IERC4626
function totalAssets() public view virtual returns (uint256) {
return IERC20(asset()).balanceOf(address(this));
}
/// @inheritdoc IERC4626
function convertToShares(uint256 assets) public view virtual returns (uint256) {
return _convertToShares(assets, Math.Rounding.Floor);
}
/// @inheritdoc IERC4626
function convertToAssets(uint256 shares) public view virtual returns (uint256) {
return _convertToAssets(shares, Math.Rounding.Floor);
}
/// @inheritdoc IERC4626
function maxDeposit(address) public view virtual returns (uint256) {
return type(uint256).max;
}
/// @inheritdoc IERC4626
function maxMint(address) public view virtual returns (uint256) {
return type(uint256).max;
}
/// @inheritdoc IERC4626
function maxWithdraw(address owner) public view virtual returns (uint256) {
return _convertToAssets(balanceOf(owner), Math.Rounding.Floor);
}
/// @inheritdoc IERC4626
function maxRedeem(address owner) public view virtual returns (uint256) {
return balanceOf(owner);
}
/// @inheritdoc IERC4626
function previewDeposit(uint256 assets) public view virtual returns (uint256) {
return _convertToShares(assets, Math.Rounding.Floor);
}
/// @inheritdoc IERC4626
function previewMint(uint256 shares) public view virtual returns (uint256) {
return _convertToAssets(shares, Math.Rounding.Ceil);
}
/// @inheritdoc IERC4626
function previewWithdraw(uint256 assets) public view virtual returns (uint256) {
return _convertToShares(assets, Math.Rounding.Ceil);
}
/// @inheritdoc IERC4626
function previewRedeem(uint256 shares) public view virtual returns (uint256) {
return _convertToAssets(shares, Math.Rounding.Floor);
}
/// @inheritdoc IERC4626
function deposit(uint256 assets, address receiver) public virtual returns (uint256) {
uint256 maxAssets = maxDeposit(receiver);
if (assets > maxAssets) {
revert ERC4626ExceededMaxDeposit(receiver, assets, maxAssets);
}
uint256 shares = previewDeposit(assets);
_deposit(_msgSender(), receiver, assets, shares);
return shares;
}
/// @inheritdoc IERC4626
function mint(uint256 shares, address receiver) public virtual returns (uint256) {
uint256 maxShares = maxMint(receiver);
if (shares > maxShares) {
revert ERC4626ExceededMaxMint(receiver, shares, maxShares);
}
uint256 assets = previewMint(shares);
_deposit(_msgSender(), receiver, assets, shares);
return assets;
}
/// @inheritdoc IERC4626
function withdraw(uint256 assets, address receiver, address owner) public virtual returns (uint256) {
uint256 maxAssets = maxWithdraw(owner);
if (assets > maxAssets) {
revert ERC4626ExceededMaxWithdraw(owner, assets, maxAssets);
}
uint256 shares = previewWithdraw(assets);
_withdraw(_msgSender(), receiver, owner, assets, shares);
return shares;
}
/// @inheritdoc IERC4626
function redeem(uint256 shares, address receiver, address owner) public virtual returns (uint256) {
uint256 maxShares = maxRedeem(owner);
if (shares > maxShares) {
revert ERC4626ExceededMaxRedeem(owner, shares, maxShares);
}
uint256 assets = previewRedeem(shares);
_withdraw(_msgSender(), receiver, owner, assets, shares);
return assets;
}
/**
* @dev Internal conversion function (from assets to shares) with support for rounding direction.
*/
function _convertToShares(uint256 assets, Math.Rounding rounding) internal view virtual returns (uint256) {
return assets.mulDiv(totalSupply() + 10 ** _decimalsOffset(), totalAssets() + 1, rounding);
}
/**
* @dev Internal conversion function (from shares to assets) with support for rounding direction.
*/
function _convertToAssets(uint256 shares, Math.Rounding rounding) internal view virtual returns (uint256) {
return shares.mulDiv(totalAssets() + 1, totalSupply() + 10 ** _decimalsOffset(), rounding);
}
/**
* @dev Deposit/mint common workflow.
*/
function _deposit(address caller, address receiver, uint256 assets, uint256 shares) internal virtual {
// If asset() is ERC-777, `transferFrom` can trigger a reentrancy BEFORE the transfer happens through the
// `tokensToSend` hook. On the other hand, the `tokenReceived` hook, that is triggered after the transfer,
// calls the vault, which is assumed not malicious.
//
// Conclusion: we need to do the transfer before we mint so that any reentrancy would happen before the
// assets are transferred and before the shares are minted, which is a valid state.
// slither-disable-next-line reentrancy-no-eth
SafeERC20.safeTransferFrom(IERC20(asset()), caller, address(this), assets);
_mint(receiver, shares);
emit Deposit(caller, receiver, assets, shares);
}
/**
* @dev Withdraw/redeem common workflow.
*/
function _withdraw(
address caller,
address receiver,
address owner,
uint256 assets,
uint256 shares
) internal virtual {
if (caller != owner) {
_spendAllowance(owner, caller, shares);
}
// If asset() is ERC-777, `transfer` can trigger a reentrancy AFTER the transfer happens through the
// `tokensReceived` hook. On the other hand, the `tokensToSend` hook, that is triggered before the transfer,
// calls the vault, which is assumed not malicious.
//
// Conclusion: we need to do the transfer after the burn so that any reentrancy would happen after the
// shares are burned and after the assets are transferred, which is a valid state.
_burn(owner, shares);
SafeERC20.safeTransfer(IERC20(asset()), receiver, assets);
emit Withdraw(caller, receiver, owner, assets, shares);
}
function _decimalsOffset() internal view virtual returns (uint8) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (utils/Pausable.sol)
pragma solidity ^0.8.20;
import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract PausableUpgradeable is Initializable, ContextUpgradeable {
/// @custom:storage-location erc7201:openzeppelin.storage.Pausable
struct PausableStorage {
bool _paused;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Pausable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant PausableStorageLocation = 0xcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300;
function _getPausableStorage() private pure returns (PausableStorage storage $) {
assembly {
$.slot := PausableStorageLocation
}
}
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
/**
* @dev The operation failed because the contract is paused.
*/
error EnforcedPause();
/**
* @dev The operation failed because the contract is not paused.
*/
error ExpectedPause();
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
_requirePaused();
_;
}
function __Pausable_init() internal onlyInitializing {
}
function __Pausable_init_unchained() internal onlyInitializing {
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
PausableStorage storage $ = _getPausableStorage();
return $._paused;
}
/**
* @dev Throws if the contract is paused.
*/
function _requireNotPaused() internal view virtual {
if (paused()) {
revert EnforcedPause();
}
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
if (!paused()) {
revert ExpectedPause();
}
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
PausableStorage storage $ = _getPausableStorage();
$._paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
PausableStorage storage $ = _getPausableStorage();
$._paused = false;
emit Unpaused(_msgSender());
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol)
pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at,
* consider using {ReentrancyGuardTransient} instead.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuardUpgradeable is Initializable {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
/// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard
struct ReentrancyGuardStorage {
uint256 _status;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant ReentrancyGuardStorageLocation = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;
function _getReentrancyGuardStorage() private pure returns (ReentrancyGuardStorage storage $) {
assembly {
$.slot := ReentrancyGuardStorageLocation
}
}
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
function __ReentrancyGuard_init() internal onlyInitializing {
__ReentrancyGuard_init_unchained();
}
function __ReentrancyGuard_init_unchained() internal onlyInitializing {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
$._status = NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
// On the first call to nonReentrant, _status will be NOT_ENTERED
if ($._status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
$._status = ENTERED;
}
function _nonReentrantAfter() private {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
$._status = NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
return $._status == ENTERED;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (proxy/utils/UUPSUpgradeable.sol)
pragma solidity ^0.8.22;
import {IERC1822Proxiable} from "../../interfaces/draft-IERC1822.sol";
import {ERC1967Utils} from "../ERC1967/ERC1967Utils.sol";
/**
* @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
* {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
*
* A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
* reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
* `UUPSUpgradeable` with a custom implementation of upgrades.
*
* The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
*/
abstract contract UUPSUpgradeable is IERC1822Proxiable {
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
address private immutable __self = address(this);
/**
* @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgradeTo(address)`
* and `upgradeToAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called,
* while `upgradeToAndCall` will invoke the `receive` function if the second argument is the empty byte string.
* If the getter returns `"5.0.0"`, only `upgradeToAndCall(address,bytes)` is present, and the second argument must
* be the empty byte string if no function should be called, making it impossible to invoke the `receive` function
* during an upgrade.
*/
string public constant UPGRADE_INTERFACE_VERSION = "5.0.0";
/**
* @dev The call is from an unauthorized context.
*/
error UUPSUnauthorizedCallContext();
/**
* @dev The storage `slot` is unsupported as a UUID.
*/
error UUPSUnsupportedProxiableUUID(bytes32 slot);
/**
* @dev Check that the execution is being performed through a delegatecall call and that the execution context is
* a proxy contract with an implementation (as defined in ERC-1967) pointing to self. This should only be the case
* for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
* function through ERC-1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
* fail.
*/
modifier onlyProxy() {
_checkProxy();
_;
}
/**
* @dev Check that the execution is not being performed through a delegate call. This allows a function to be
* callable on the implementing contract but not through proxies.
*/
modifier notDelegated() {
_checkNotDelegated();
_;
}
/**
* @dev Implementation of the ERC-1822 {proxiableUUID} function. This returns the storage slot used by the
* implementation. It is used to validate the implementation's compatibility when performing an upgrade.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
*/
function proxiableUUID() external view virtual notDelegated returns (bytes32) {
return ERC1967Utils.IMPLEMENTATION_SLOT;
}
/**
* @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
* encoded in `data`.
*
* Calls {_authorizeUpgrade}.
*
* Emits an {Upgraded} event.
*
* @custom:oz-upgrades-unsafe-allow-reachable delegatecall
*/
function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy {
_authorizeUpgrade(newImplementation);
_upgradeToAndCallUUPS(newImplementation, data);
}
/**
* @dev Reverts if the execution is not performed via delegatecall or the execution
* context is not of a proxy with an ERC-1967 compliant implementation pointing to self.
*/
function _checkProxy() internal view virtual {
if (
address(this) == __self || // Must be called through delegatecall
ERC1967Utils.getImplementation() != __self // Must be called through an active proxy
) {
revert UUPSUnauthorizedCallContext();
}
}
/**
* @dev Reverts if the execution is performed via delegatecall.
* See {notDelegated}.
*/
function _checkNotDelegated() internal view virtual {
if (address(this) != __self) {
// Must not be called through delegatecall
revert UUPSUnauthorizedCallContext();
}
}
/**
* @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
* {upgradeToAndCall}.
*
* Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
*
* ```solidity
* function _authorizeUpgrade(address) internal onlyOwner {}
* ```
*/
function _authorizeUpgrade(address newImplementation) internal virtual;
/**
* @dev Performs an implementation upgrade with a security check for UUPS proxies, and additional setup call.
*
* As a security check, {proxiableUUID} is invoked in the new implementation, and the return value
* is expected to be the implementation slot in ERC-1967.
*
* Emits an {IERC1967-Upgraded} event.
*/
function _upgradeToAndCallUUPS(address newImplementation, bytes memory data) private {
try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
if (slot != ERC1967Utils.IMPLEMENTATION_SLOT) {
revert UUPSUnsupportedProxiableUUID(slot);
}
ERC1967Utils.upgradeToAndCall(newImplementation, data);
} catch {
// The implementation is not UUPS
revert ERC1967Utils.ERC1967InvalidImplementation(newImplementation);
}
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
/// @notice Provides a flexible and updatable auth pattern which is completely separate from application logic.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Auth.sol)
/// @author Modified from Dappsys (https://github.com/dapphub/ds-auth/blob/master/src/auth.sol)
abstract contract Auth {
event OwnershipTransferred(address indexed user, address indexed newOwner);
event AuthorityUpdated(address indexed user, Authority indexed newAuthority);
address public owner;
Authority public authority;
constructor(address _owner, Authority _authority) {
owner = _owner;
authority = _authority;
emit OwnershipTransferred(msg.sender, _owner);
emit AuthorityUpdated(msg.sender, _authority);
}
modifier requiresAuth() virtual {
require(isAuthorized(msg.sender, msg.sig), "UNAUTHORIZED");
_;
}
function isAuthorized(address user, bytes4 functionSig) internal view virtual returns (bool) {
Authority auth = authority; // Memoizing authority saves us a warm SLOAD, around 100 gas.
// Checking if the caller is the owner only after calling the authority saves gas in most cases, but be
// aware that this makes protected functions uncallable even to the owner if the authority is out of order.
return (address(auth) != address(0) && auth.canCall(user, address(this), functionSig)) || user == owner;
}
function setAuthority(Authority newAuthority) public virtual {
// We check if the caller is the owner first because we want to ensure they can
// always swap out the authority even if it's reverting or using up a lot of gas.
require(msg.sender == owner || authority.canCall(msg.sender, address(this), msg.sig));
authority = newAuthority;
emit AuthorityUpdated(msg.sender, newAuthority);
}
function transferOwnership(address newOwner) public virtual requiresAuth {
owner = newOwner;
emit OwnershipTransferred(msg.sender, newOwner);
}
}
/// @notice A generic interface for a contract which provides authorization data to an Auth instance.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Auth.sol)
/// @author Modified from Dappsys (https://github.com/dapphub/ds-auth/blob/master/src/auth.sol)
interface Authority {
function canCall(
address user,
address target,
bytes4 functionSig
) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.20;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Storage of the initializable contract.
*
* It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
* when using with upgradeable contracts.
*
* @custom:storage-location erc7201:openzeppelin.storage.Initializable
*/
struct InitializableStorage {
/**
* @dev Indicates that the contract has been initialized.
*/
uint64 _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
/**
* @dev The contract is already initialized.
*/
error InvalidInitialization();
/**
* @dev The contract is not initializing.
*/
error NotInitializing();
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint64 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
* number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
* production.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
// Cache values to avoid duplicated sloads
bool isTopLevelCall = !$._initializing;
uint64 initialized = $._initialized;
// Allowed calls:
// - initialSetup: the contract is not in the initializing state and no previous version was
// initialized
// - construction: the contract is initialized at version 1 (no reinitialization) and the
// current contract is just being deployed
bool initialSetup = initialized == 0 && isTopLevelCall;
bool construction = initialized == 1 && address(this).code.length == 0;
if (!initialSetup && !construction) {
revert InvalidInitialization();
}
$._initialized = 1;
if (isTopLevelCall) {
$._initializing = true;
}
_;
if (isTopLevelCall) {
$._initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint64 version) {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing || $._initialized >= version) {
revert InvalidInitialization();
}
$._initialized = version;
$._initializing = true;
_;
$._initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
_checkInitializing();
_;
}
/**
* @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
*/
function _checkInitializing() internal view virtual {
if (!_isInitializing()) {
revert NotInitializing();
}
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing) {
revert InvalidInitialization();
}
if ($._initialized != type(uint64).max) {
$._initialized = type(uint64).max;
emit Initialized(type(uint64).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint64) {
return _getInitializableStorage()._initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _getInitializableStorage()._initializing;
}
/**
* @dev Pointer to storage slot. Allows integrators to override it with a custom storage location.
*
* NOTE: Consider following the ERC-7201 formula to derive storage locations.
*/
function _initializableStorageSlot() internal pure virtual returns (bytes32) {
return INITIALIZABLE_STORAGE;
}
/**
* @dev Returns a pointer to the storage namespace.
*/
// solhint-disable-next-line var-name-mixedcase
function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
bytes32 slot = _initializableStorageSlot();
assembly {
$.slot := slot
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-20 standard as defined in the ERC.
*/
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: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Panic.sol)
pragma solidity ^0.8.20;
/**
* @dev Helper library for emitting standardized panic codes.
*
* ```solidity
* contract Example {
* using Panic for uint256;
*
* // Use any of the declared internal constants
* function foo() { Panic.GENERIC.panic(); }
*
* // Alternatively
* function foo() { Panic.panic(Panic.GENERIC); }
* }
* ```
*
* Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil].
*
* _Available since v5.1._
*/
// slither-disable-next-line unused-state
library Panic {
/// @dev generic / unspecified error
uint256 internal constant GENERIC = 0x00;
/// @dev used by the assert() builtin
uint256 internal constant ASSERT = 0x01;
/// @dev arithmetic underflow or overflow
uint256 internal constant UNDER_OVERFLOW = 0x11;
/// @dev division or modulo by zero
uint256 internal constant DIVISION_BY_ZERO = 0x12;
/// @dev enum conversion error
uint256 internal constant ENUM_CONVERSION_ERROR = 0x21;
/// @dev invalid encoding in storage
uint256 internal constant STORAGE_ENCODING_ERROR = 0x22;
/// @dev empty array pop
uint256 internal constant EMPTY_ARRAY_POP = 0x31;
/// @dev array out of bounds access
uint256 internal constant ARRAY_OUT_OF_BOUNDS = 0x32;
/// @dev resource error (too large allocation or too large array)
uint256 internal constant RESOURCE_ERROR = 0x41;
/// @dev calling invalid internal function
uint256 internal constant INVALID_INTERNAL_FUNCTION = 0x51;
/// @dev Reverts with a panic code. Recommended to use with
/// the internal constants with predefined codes.
function panic(uint256 code) internal pure {
assembly ("memory-safe") {
mstore(0x00, 0x4e487b71)
mstore(0x20, code)
revert(0x1c, 0x24)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.20;
/**
* @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such an operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeCast {
/**
* @dev Value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);
/**
* @dev An int value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedIntToUint(int256 value);
/**
* @dev Value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);
/**
* @dev An uint value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedUintToInt(uint256 value);
/**
* @dev Returns the downcasted uint248 from uint256, reverting on
* overflow (when the input is greater than largest uint248).
*
* Counterpart to Solidity's `uint248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toUint248(uint256 value) internal pure returns (uint248) {
if (value > type(uint248).max) {
revert SafeCastOverflowedUintDowncast(248, value);
}
return uint248(value);
}
/**
* @dev Returns the downcasted uint240 from uint256, reverting on
* overflow (when the input is greater than largest uint240).
*
* Counterpart to Solidity's `uint240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toUint240(uint256 value) internal pure returns (uint240) {
if (value > type(uint240).max) {
revert SafeCastOverflowedUintDowncast(240, value);
}
return uint240(value);
}
/**
* @dev Returns the downcasted uint232 from uint256, reverting on
* overflow (when the input is greater than largest uint232).
*
* Counterpart to Solidity's `uint232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toUint232(uint256 value) internal pure returns (uint232) {
if (value > type(uint232).max) {
revert SafeCastOverflowedUintDowncast(232, value);
}
return uint232(value);
}
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toUint224(uint256 value) internal pure returns (uint224) {
if (value > type(uint224).max) {
revert SafeCastOverflowedUintDowncast(224, value);
}
return uint224(value);
}
/**
* @dev Returns the downcasted uint216 from uint256, reverting on
* overflow (when the input is greater than largest uint216).
*
* Counterpart to Solidity's `uint216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toUint216(uint256 value) internal pure returns (uint216) {
if (value > type(uint216).max) {
revert SafeCastOverflowedUintDowncast(216, value);
}
return uint216(value);
}
/**
* @dev Returns the downcasted uint208 from uint256, reverting on
* overflow (when the input is greater than largest uint208).
*
* Counterpart to Solidity's `uint208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toUint208(uint256 value) internal pure returns (uint208) {
if (value > type(uint208).max) {
revert SafeCastOverflowedUintDowncast(208, value);
}
return uint208(value);
}
/**
* @dev Returns the downcasted uint200 from uint256, reverting on
* overflow (when the input is greater than largest uint200).
*
* Counterpart to Solidity's `uint200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toUint200(uint256 value) internal pure returns (uint200) {
if (value > type(uint200).max) {
revert SafeCastOverflowedUintDowncast(200, value);
}
return uint200(value);
}
/**
* @dev Returns the downcasted uint192 from uint256, reverting on
* overflow (when the input is greater than largest uint192).
*
* Counterpart to Solidity's `uint192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toUint192(uint256 value) internal pure returns (uint192) {
if (value > type(uint192).max) {
revert SafeCastOverflowedUintDowncast(192, value);
}
return uint192(value);
}
/**
* @dev Returns the downcasted uint184 from uint256, reverting on
* overflow (when the input is greater than largest uint184).
*
* Counterpart to Solidity's `uint184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toUint184(uint256 value) internal pure returns (uint184) {
if (value > type(uint184).max) {
revert SafeCastOverflowedUintDowncast(184, value);
}
return uint184(value);
}
/**
* @dev Returns the downcasted uint176 from uint256, reverting on
* overflow (when the input is greater than largest uint176).
*
* Counterpart to Solidity's `uint176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toUint176(uint256 value) internal pure returns (uint176) {
if (value > type(uint176).max) {
revert SafeCastOverflowedUintDowncast(176, value);
}
return uint176(value);
}
/**
* @dev Returns the downcasted uint168 from uint256, reverting on
* overflow (when the input is greater than largest uint168).
*
* Counterpart to Solidity's `uint168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toUint168(uint256 value) internal pure returns (uint168) {
if (value > type(uint168).max) {
revert SafeCastOverflowedUintDowncast(168, value);
}
return uint168(value);
}
/**
* @dev Returns the downcasted uint160 from uint256, reverting on
* overflow (when the input is greater than largest uint160).
*
* Counterpart to Solidity's `uint160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toUint160(uint256 value) internal pure returns (uint160) {
if (value > type(uint160).max) {
revert SafeCastOverflowedUintDowncast(160, value);
}
return uint160(value);
}
/**
* @dev Returns the downcasted uint152 from uint256, reverting on
* overflow (when the input is greater than largest uint152).
*
* Counterpart to Solidity's `uint152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toUint152(uint256 value) internal pure returns (uint152) {
if (value > type(uint152).max) {
revert SafeCastOverflowedUintDowncast(152, value);
}
return uint152(value);
}
/**
* @dev Returns the downcasted uint144 from uint256, reverting on
* overflow (when the input is greater than largest uint144).
*
* Counterpart to Solidity's `uint144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toUint144(uint256 value) internal pure returns (uint144) {
if (value > type(uint144).max) {
revert SafeCastOverflowedUintDowncast(144, value);
}
return uint144(value);
}
/**
* @dev Returns the downcasted uint136 from uint256, reverting on
* overflow (when the input is greater than largest uint136).
*
* Counterpart to Solidity's `uint136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toUint136(uint256 value) internal pure returns (uint136) {
if (value > type(uint136).max) {
revert SafeCastOverflowedUintDowncast(136, value);
}
return uint136(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toUint128(uint256 value) internal pure returns (uint128) {
if (value > type(uint128).max) {
revert SafeCastOverflowedUintDowncast(128, value);
}
return uint128(value);
}
/**
* @dev Returns the downcasted uint120 from uint256, reverting on
* overflow (when the input is greater than largest uint120).
*
* Counterpart to Solidity's `uint120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toUint120(uint256 value) internal pure returns (uint120) {
if (value > type(uint120).max) {
revert SafeCastOverflowedUintDowncast(120, value);
}
return uint120(value);
}
/**
* @dev Returns the downcasted uint112 from uint256, reverting on
* overflow (when the input is greater than largest uint112).
*
* Counterpart to Solidity's `uint112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toUint112(uint256 value) internal pure returns (uint112) {
if (value > type(uint112).max) {
revert SafeCastOverflowedUintDowncast(112, value);
}
return uint112(value);
}
/**
* @dev Returns the downcasted uint104 from uint256, reverting on
* overflow (when the input is greater than largest uint104).
*
* Counterpart to Solidity's `uint104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toUint104(uint256 value) internal pure returns (uint104) {
if (value > type(uint104).max) {
revert SafeCastOverflowedUintDowncast(104, value);
}
return uint104(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toUint96(uint256 value) internal pure returns (uint96) {
if (value > type(uint96).max) {
revert SafeCastOverflowedUintDowncast(96, value);
}
return uint96(value);
}
/**
* @dev Returns the downcasted uint88 from uint256, reverting on
* overflow (when the input is greater than largest uint88).
*
* Counterpart to Solidity's `uint88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toUint88(uint256 value) internal pure returns (uint88) {
if (value > type(uint88).max) {
revert SafeCastOverflowedUintDowncast(88, value);
}
return uint88(value);
}
/**
* @dev Returns the downcasted uint80 from uint256, reverting on
* overflow (when the input is greater than largest uint80).
*
* Counterpart to Solidity's `uint80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toUint80(uint256 value) internal pure returns (uint80) {
if (value > type(uint80).max) {
revert SafeCastOverflowedUintDowncast(80, value);
}
return uint80(value);
}
/**
* @dev Returns the downcasted uint72 from uint256, reverting on
* overflow (when the input is greater than largest uint72).
*
* Counterpart to Solidity's `uint72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toUint72(uint256 value) internal pure returns (uint72) {
if (value > type(uint72).max) {
revert SafeCastOverflowedUintDowncast(72, value);
}
return uint72(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toUint64(uint256 value) internal pure returns (uint64) {
if (value > type(uint64).max) {
revert SafeCastOverflowedUintDowncast(64, value);
}
return uint64(value);
}
/**
* @dev Returns the downcasted uint56 from uint256, reverting on
* overflow (when the input is greater than largest uint56).
*
* Counterpart to Solidity's `uint56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toUint56(uint256 value) internal pure returns (uint56) {
if (value > type(uint56).max) {
revert SafeCastOverflowedUintDowncast(56, value);
}
return uint56(value);
}
/**
* @dev Returns the downcasted uint48 from uint256, reverting on
* overflow (when the input is greater than largest uint48).
*
* Counterpart to Solidity's `uint48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toUint48(uint256 value) internal pure returns (uint48) {
if (value > type(uint48).max) {
revert SafeCastOverflowedUintDowncast(48, value);
}
return uint48(value);
}
/**
* @dev Returns the downcasted uint40 from uint256, reverting on
* overflow (when the input is greater than largest uint40).
*
* Counterpart to Solidity's `uint40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toUint40(uint256 value) internal pure returns (uint40) {
if (value > type(uint40).max) {
revert SafeCastOverflowedUintDowncast(40, value);
}
return uint40(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toUint32(uint256 value) internal pure returns (uint32) {
if (value > type(uint32).max) {
revert SafeCastOverflowedUintDowncast(32, value);
}
return uint32(value);
}
/**
* @dev Returns the downcasted uint24 from uint256, reverting on
* overflow (when the input is greater than largest uint24).
*
* Counterpart to Solidity's `uint24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toUint24(uint256 value) internal pure returns (uint24) {
if (value > type(uint24).max) {
revert SafeCastOverflowedUintDowncast(24, value);
}
return uint24(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toUint16(uint256 value) internal pure returns (uint16) {
if (value > type(uint16).max) {
revert SafeCastOverflowedUintDowncast(16, value);
}
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toUint8(uint256 value) internal pure returns (uint8) {
if (value > type(uint8).max) {
revert SafeCastOverflowedUintDowncast(8, value);
}
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*/
function toUint256(int256 value) internal pure returns (uint256) {
if (value < 0) {
revert SafeCastOverflowedIntToUint(value);
}
return uint256(value);
}
/**
* @dev Returns the downcasted int248 from int256, reverting on
* overflow (when the input is less than smallest int248 or
* greater than largest int248).
*
* Counterpart to Solidity's `int248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(248, value);
}
}
/**
* @dev Returns the downcasted int240 from int256, reverting on
* overflow (when the input is less than smallest int240 or
* greater than largest int240).
*
* Counterpart to Solidity's `int240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(240, value);
}
}
/**
* @dev Returns the downcasted int232 from int256, reverting on
* overflow (when the input is less than smallest int232 or
* greater than largest int232).
*
* Counterpart to Solidity's `int232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(232, value);
}
}
/**
* @dev Returns the downcasted int224 from int256, reverting on
* overflow (when the input is less than smallest int224 or
* greater than largest int224).
*
* Counterpart to Solidity's `int224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(224, value);
}
}
/**
* @dev Returns the downcasted int216 from int256, reverting on
* overflow (when the input is less than smallest int216 or
* greater than largest int216).
*
* Counterpart to Solidity's `int216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(216, value);
}
}
/**
* @dev Returns the downcasted int208 from int256, reverting on
* overflow (when the input is less than smallest int208 or
* greater than largest int208).
*
* Counterpart to Solidity's `int208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(208, value);
}
}
/**
* @dev Returns the downcasted int200 from int256, reverting on
* overflow (when the input is less than smallest int200 or
* greater than largest int200).
*
* Counterpart to Solidity's `int200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(200, value);
}
}
/**
* @dev Returns the downcasted int192 from int256, reverting on
* overflow (when the input is less than smallest int192 or
* greater than largest int192).
*
* Counterpart to Solidity's `int192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(192, value);
}
}
/**
* @dev Returns the downcasted int184 from int256, reverting on
* overflow (when the input is less than smallest int184 or
* greater than largest int184).
*
* Counterpart to Solidity's `int184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(184, value);
}
}
/**
* @dev Returns the downcasted int176 from int256, reverting on
* overflow (when the input is less than smallest int176 or
* greater than largest int176).
*
* Counterpart to Solidity's `int176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(176, value);
}
}
/**
* @dev Returns the downcasted int168 from int256, reverting on
* overflow (when the input is less than smallest int168 or
* greater than largest int168).
*
* Counterpart to Solidity's `int168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(168, value);
}
}
/**
* @dev Returns the downcasted int160 from int256, reverting on
* overflow (when the input is less than smallest int160 or
* greater than largest int160).
*
* Counterpart to Solidity's `int160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(160, value);
}
}
/**
* @dev Returns the downcasted int152 from int256, reverting on
* overflow (when the input is less than smallest int152 or
* greater than largest int152).
*
* Counterpart to Solidity's `int152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(152, value);
}
}
/**
* @dev Returns the downcasted int144 from int256, reverting on
* overflow (when the input is less than smallest int144 or
* greater than largest int144).
*
* Counterpart to Solidity's `int144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(144, value);
}
}
/**
* @dev Returns the downcasted int136 from int256, reverting on
* overflow (when the input is less than smallest int136 or
* greater than largest int136).
*
* Counterpart to Solidity's `int136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(136, value);
}
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(128, value);
}
}
/**
* @dev Returns the downcasted int120 from int256, reverting on
* overflow (when the input is less than smallest int120 or
* greater than largest int120).
*
* Counterpart to Solidity's `int120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(120, value);
}
}
/**
* @dev Returns the downcasted int112 from int256, reverting on
* overflow (when the input is less than smallest int112 or
* greater than largest int112).
*
* Counterpart to Solidity's `int112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(112, value);
}
}
/**
* @dev Returns the downcasted int104 from int256, reverting on
* overflow (when the input is less than smallest int104 or
* greater than largest int104).
*
* Counterpart to Solidity's `int104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(104, value);
}
}
/**
* @dev Returns the downcasted int96 from int256, reverting on
* overflow (when the input is less than smallest int96 or
* greater than largest int96).
*
* Counterpart to Solidity's `int96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(96, value);
}
}
/**
* @dev Returns the downcasted int88 from int256, reverting on
* overflow (when the input is less than smallest int88 or
* greater than largest int88).
*
* Counterpart to Solidity's `int88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(88, value);
}
}
/**
* @dev Returns the downcasted int80 from int256, reverting on
* overflow (when the input is less than smallest int80 or
* greater than largest int80).
*
* Counterpart to Solidity's `int80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(80, value);
}
}
/**
* @dev Returns the downcasted int72 from int256, reverting on
* overflow (when the input is less than smallest int72 or
* greater than largest int72).
*
* Counterpart to Solidity's `int72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(72, value);
}
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(64, value);
}
}
/**
* @dev Returns the downcasted int56 from int256, reverting on
* overflow (when the input is less than smallest int56 or
* greater than largest int56).
*
* Counterpart to Solidity's `int56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(56, value);
}
}
/**
* @dev Returns the downcasted int48 from int256, reverting on
* overflow (when the input is less than smallest int48 or
* greater than largest int48).
*
* Counterpart to Solidity's `int48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(48, value);
}
}
/**
* @dev Returns the downcasted int40 from int256, reverting on
* overflow (when the input is less than smallest int40 or
* greater than largest int40).
*
* Counterpart to Solidity's `int40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(40, value);
}
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(32, value);
}
}
/**
* @dev Returns the downcasted int24 from int256, reverting on
* overflow (when the input is less than smallest int24 or
* greater than largest int24).
*
* Counterpart to Solidity's `int24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(24, value);
}
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(16, value);
}
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(8, value);
}
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
if (value > uint256(type(int256).max)) {
revert SafeCastOverflowedUintToInt(value);
}
return int256(value);
}
/**
* @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump.
*/
function toUint(bool b) internal pure returns (uint256 u) {
assembly ("memory-safe") {
u := iszero(iszero(b))
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of common custom errors used in multiple contracts
*
* IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library.
* It is recommended to avoid relying on the error API for critical functionality.
*
* _Available since v5.1._
*/
library Errors {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error InsufficientBalance(uint256 balance, uint256 needed);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedCall();
/**
* @dev The deployment failed.
*/
error FailedDeployment();
/**
* @dev A necessary precompile is missing.
*/
error MissingPrecompile(address);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.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 ERC-20 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: 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.1.0) (interfaces/draft-IERC6093.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard ERC-20 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-20 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 ERC-721 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-721 tokens.
*/
interface IERC721Errors {
/**
* @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in ERC-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 ERC-1155 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-1155 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.1.0) (interfaces/IERC1363.sol)
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";
/**
* @title IERC1363
* @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
*
* Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
* after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
*/
interface IERC1363 is IERC20, IERC165 {
/*
* Note: the ERC-165 identifier for this interface is 0xb0202a11.
* 0xb0202a11 ===
* bytes4(keccak256('transferAndCall(address,uint256)')) ^
* bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
* bytes4(keccak256('approveAndCall(address,uint256)')) ^
* bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
*/
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @param data Additional data with no specified format, sent in call to `spender`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {ContextUpgradeable} from "../../utils/ContextUpgradeable.sol";
import {IERC20Errors} from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol";
import {Initializable} from "../../proxy/utils/Initializable.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 ERC-20
* applications.
*/
abstract contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20, IERC20Metadata, IERC20Errors {
/// @custom:storage-location erc7201:openzeppelin.storage.ERC20
struct ERC20Storage {
mapping(address account => uint256) _balances;
mapping(address account => mapping(address spender => uint256)) _allowances;
uint256 _totalSupply;
string _name;
string _symbol;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ERC20")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant ERC20StorageLocation = 0x52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00;
function _getERC20Storage() private pure returns (ERC20Storage storage $) {
assembly {
$.slot := ERC20StorageLocation
}
}
/**
* @dev Sets the values for {name} and {symbol}.
*
* Both values are immutable: they can only be set once during construction.
*/
function __ERC20_init(string memory name_, string memory symbol_) internal onlyInitializing {
__ERC20_init_unchained(name_, symbol_);
}
function __ERC20_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing {
ERC20Storage storage $ = _getERC20Storage();
$._name = name_;
$._symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual returns (string memory) {
ERC20Storage storage $ = _getERC20Storage();
return $._name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual returns (string memory) {
ERC20Storage storage $ = _getERC20Storage();
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;
}
/// @inheritdoc IERC20
function totalSupply() public view virtual returns (uint256) {
ERC20Storage storage $ = _getERC20Storage();
return $._totalSupply;
}
/// @inheritdoc IERC20
function balanceOf(address account) public view virtual returns (uint256) {
ERC20Storage storage $ = _getERC20Storage();
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;
}
/// @inheritdoc IERC20
function allowance(address owner, address spender) public view virtual returns (uint256) {
ERC20Storage storage $ = _getERC20Storage();
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}.
*
* Skips emitting an {Approval} event indicating an allowance update. This is not
* required by the ERC. See {xref-ERC20-_approve-address-address-uint256-bool-}[_approve].
*
* 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 {
ERC20Storage storage $ = _getERC20Storage();
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:
*
* ```solidity
* 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 {
ERC20Storage storage $ = _getERC20Storage();
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.3.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 ERC-4626 "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 redemption 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.1) (utils/Context.sol)
pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/draft-IERC1822.sol)
pragma solidity ^0.8.20;
/**
* @dev ERC-1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
* proxy whose upgrades are fully controlled by the current implementation.
*/
interface IERC1822Proxiable {
/**
* @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
* address.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy.
*/
function proxiableUUID() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.2.0) (proxy/ERC1967/ERC1967Utils.sol)
pragma solidity ^0.8.22;
import {IBeacon} from "../beacon/IBeacon.sol";
import {IERC1967} from "../../interfaces/IERC1967.sol";
import {Address} from "../../utils/Address.sol";
import {StorageSlot} from "../../utils/StorageSlot.sol";
/**
* @dev This library provides getters and event emitting update functions for
* https://eips.ethereum.org/EIPS/eip-1967[ERC-1967] slots.
*/
library ERC1967Utils {
/**
* @dev Storage slot with the address of the current implementation.
* This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1.
*/
// solhint-disable-next-line private-vars-leading-underscore
bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/**
* @dev The `implementation` of the proxy is invalid.
*/
error ERC1967InvalidImplementation(address implementation);
/**
* @dev The `admin` of the proxy is invalid.
*/
error ERC1967InvalidAdmin(address admin);
/**
* @dev The `beacon` of the proxy is invalid.
*/
error ERC1967InvalidBeacon(address beacon);
/**
* @dev An upgrade function sees `msg.value > 0` that may be lost.
*/
error ERC1967NonPayable();
/**
* @dev Returns the current implementation address.
*/
function getImplementation() internal view returns (address) {
return StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value;
}
/**
* @dev Stores a new address in the ERC-1967 implementation slot.
*/
function _setImplementation(address newImplementation) private {
if (newImplementation.code.length == 0) {
revert ERC1967InvalidImplementation(newImplementation);
}
StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation;
}
/**
* @dev Performs implementation upgrade with additional setup call if data is nonempty.
* This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
* to avoid stuck value in the contract.
*
* Emits an {IERC1967-Upgraded} event.
*/
function upgradeToAndCall(address newImplementation, bytes memory data) internal {
_setImplementation(newImplementation);
emit IERC1967.Upgraded(newImplementation);
if (data.length > 0) {
Address.functionDelegateCall(newImplementation, data);
} else {
_checkNonPayable();
}
}
/**
* @dev Storage slot with the admin of the contract.
* This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1.
*/
// solhint-disable-next-line private-vars-leading-underscore
bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
/**
* @dev Returns the current admin.
*
* TIP: To get this value clients can read directly from the storage slot shown below (specified by ERC-1967) using
* the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
* `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
*/
function getAdmin() internal view returns (address) {
return StorageSlot.getAddressSlot(ADMIN_SLOT).value;
}
/**
* @dev Stores a new address in the ERC-1967 admin slot.
*/
function _setAdmin(address newAdmin) private {
if (newAdmin == address(0)) {
revert ERC1967InvalidAdmin(address(0));
}
StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin;
}
/**
* @dev Changes the admin of the proxy.
*
* Emits an {IERC1967-AdminChanged} event.
*/
function changeAdmin(address newAdmin) internal {
emit IERC1967.AdminChanged(getAdmin(), newAdmin);
_setAdmin(newAdmin);
}
/**
* @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
* This is the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1.
*/
// solhint-disable-next-line private-vars-leading-underscore
bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
/**
* @dev Returns the current beacon.
*/
function getBeacon() internal view returns (address) {
return StorageSlot.getAddressSlot(BEACON_SLOT).value;
}
/**
* @dev Stores a new beacon in the ERC-1967 beacon slot.
*/
function _setBeacon(address newBeacon) private {
if (newBeacon.code.length == 0) {
revert ERC1967InvalidBeacon(newBeacon);
}
StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon;
address beaconImplementation = IBeacon(newBeacon).implementation();
if (beaconImplementation.code.length == 0) {
revert ERC1967InvalidImplementation(beaconImplementation);
}
}
/**
* @dev Change the beacon and trigger a setup call if data is nonempty.
* This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
* to avoid stuck value in the contract.
*
* Emits an {IERC1967-BeaconUpgraded} event.
*
* CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since
* it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for
* efficiency.
*/
function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal {
_setBeacon(newBeacon);
emit IERC1967.BeaconUpgraded(newBeacon);
if (data.length > 0) {
Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
} else {
_checkNonPayable();
}
}
/**
* @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract
* if an upgrade doesn't perform an initialization call.
*/
function _checkNonPayable() private {
if (msg.value > 0) {
revert ERC1967NonPayable();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../token/ERC20/IERC20.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../utils/introspection/IERC165.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol)
pragma solidity ^0.8.20;
/**
* @dev This is the interface that {BeaconProxy} expects of its beacon.
*/
interface IBeacon {
/**
* @dev Must return an address that can be used as a delegate call target.
*
* {UpgradeableBeacon} will check that this address is a contract.
*/
function implementation() external view returns (address);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1967.sol)
pragma solidity ^0.8.20;
/**
* @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.
*/
interface IERC1967 {
/**
* @dev Emitted when the implementation is upgraded.
*/
event Upgraded(address indexed implementation);
/**
* @dev Emitted when the admin account has changed.
*/
event AdminChanged(address previousAdmin, address newAdmin);
/**
* @dev Emitted when the beacon is changed.
*/
event BeaconUpgraded(address indexed beacon);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.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 ERC-1967 implementation slot:
* ```solidity
* contract ERC1967 {
* // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.
* 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;
* }
* }
* ```
*
* TIP: Consider using this library along with {SlotDerivation}.
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct Int256Slot {
int256 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) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `Int256Slot` with member `value` located at `slot`.
*/
function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
assembly ("memory-safe") {
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) {
assembly ("memory-safe") {
r.slot := store.slot
}
}
/**
* @dev Returns a `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
assembly ("memory-safe") {
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) {
assembly ("memory-safe") {
r.slot := store.slot
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[ERC].
*
* 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[ERC 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);
}{
"remappings": [
"@openzeppelin/contracts/=lib/multipli-vault/lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/",
"@openzeppelin/contracts-upgradeable/=lib/multipli-vault/lib/openzeppelin-contracts-upgradeable/contracts/",
"@solmate/=lib/multipli-vault/lib/solmate/src/",
"@multipli-vault/=lib/Multipli-Vault/",
"forge-std/=lib/multipli-vault/lib/forge-std/src/",
"Multipli-Vault/=lib/Multipli-Vault/",
"ds-test/=lib/Multipli-Vault/lib/solmate/lib/ds-test/src/",
"erc4626-tests/=lib/Multipli-Vault/lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
"halmos-cheatcodes/=lib/Multipli-Vault/lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/",
"openzeppelin-contracts-upgradeable/=lib/Multipli-Vault/lib/openzeppelin-contracts-upgradeable/",
"openzeppelin-contracts/=lib/Multipli-Vault/lib/openzeppelin-contracts/",
"openzeppelin-foundry-upgrades/=lib/openzeppelin-foundry-upgrades/src/",
"script/=lib/Multipli-Vault/script/",
"solmate/=lib/Multipli-Vault/lib/solmate/src/",
"test/=lib/Multipli-Vault/test/"
],
"optimizer": {
"enabled": true,
"runs": 8000
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": false
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[],"name":"AddressZero","type":"error"},{"inputs":[],"name":"AmountZero","type":"error"},{"inputs":[],"name":"AssetBalanceMismatch","type":"error"},{"inputs":[{"internalType":"bytes4","name":"msgSig","type":"bytes4"}],"name":"ConfiguredIncorrectly","type":"error"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minDepositAmount","type":"uint256"}],"name":"DepositAmountLessThanThreshold","type":"error"},{"inputs":[{"internalType":"address","name":"implementation","type":"address"}],"name":"ERC1967InvalidImplementation","type":"error"},{"inputs":[],"name":"ERC1967NonPayable","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":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"uint256","name":"max","type":"uint256"}],"name":"ERC4626ExceededMaxDeposit","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"uint256","name":"max","type":"uint256"}],"name":"ERC4626ExceededMaxMint","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"uint256","name":"max","type":"uint256"}],"name":"ERC4626ExceededMaxRedeem","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"uint256","name":"max","type":"uint256"}],"name":"ERC4626ExceededMaxWithdraw","type":"error"},{"inputs":[],"name":"EnforcedPause","type":"error"},{"inputs":[{"internalType":"uint256","name":"actualAssets","type":"uint256"},{"internalType":"uint256","name":"maxAssets","type":"uint256"}],"name":"ExcessiveAssetsRequired","type":"error"},{"inputs":[],"name":"ExpectedPause","type":"error"},{"inputs":[],"name":"FailedCall","type":"error"},{"inputs":[{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"InsufficientShares","type":"error"},{"inputs":[{"internalType":"uint256","name":"actualShares","type":"uint256"},{"internalType":"uint256","name":"minShares","type":"uint256"}],"name":"InsufficientSharesReceived","type":"error"},{"inputs":[],"name":"InvalidAssetsAmount","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"InvalidMaxPercentage","type":"error"},{"inputs":[],"name":"InvalidOperatorAddress","type":"error"},{"inputs":[],"name":"InvalidReceiverAddress","type":"error"},{"inputs":[],"name":"InvalidSharesAmount","type":"error"},{"inputs":[],"name":"NoChangeInWhitelistStatus","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"NotSharesOwner","type":"error"},{"inputs":[],"name":"RecipientNotWhitelisted","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"SharesAmountZero","type":"error"},{"inputs":[],"name":"SharesNotReturned","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes4","name":"functionSig","type":"bytes4"}],"name":"TargetMethodNotAuthorized","type":"error"},{"inputs":[],"name":"TotalSupplyMismatch","type":"error"},{"inputs":[],"name":"UUPSUnauthorizedCallContext","type":"error"},{"inputs":[{"internalType":"bytes32","name":"slot","type":"bytes32"}],"name":"UUPSUnsupportedProxiableUUID","type":"error"},{"inputs":[{"internalType":"uint8","name":"redeemType","type":"uint8"}],"name":"UnsupportedRedeemType","type":"error"},{"inputs":[],"name":"UpdateAlreadyCompletedInThisBlock","type":"error"},{"inputs":[],"name":"UseRequestRedeem","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"contract Authority","name":"newAuthority","type":"address"}],"name":"AuthorityUpdated","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":[{"indexed":false,"internalType":"uint256","name":"lastFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFee","type":"uint256"}],"name":"DepositFeeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"address","name":"oldFeeContract","type":"address"},{"indexed":false,"internalType":"address","name":"newFeeContract","type":"address"}],"name":"FeeContractUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"lastFeeRecipient","type":"address"},{"indexed":false,"internalType":"address","name":"newFeeRecipient","type":"address"}],"name":"FeeRecipientUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"initiator","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assetsWithoutFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"FlashRedeemFulfilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"initiator","type":"address"},{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"}],"name":"FundsRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"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":"InstantRedeemRequest","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"}],"name":"InstantRequestFulfilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"lastMaxPercentage","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newMaxPercentage","type":"uint256"}],"name":"MaxPercentageUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"minDepositAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newMinDepositAmount","type":"uint256"}],"name":"MinDepositAmountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"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":"RedeemRequest","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"}],"name":"RequestCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"}],"name":"RequestFulfilled","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":"lastUnderlyingBalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newUnderlyingBalance","type":"uint256"}],"name":"UnderlyingBalanceUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"initiator","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"bool","name":"isWhitelisted","type":"bool"}],"name":"WhitelistUpdated","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"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"lastFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFee","type":"uint256"}],"name":"WithdrawFeeUpdated","type":"event"},{"inputs":[],"name":"UPGRADE_INTERFACE_VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"aggregatedUnderlyingBalances","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":"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":"authority","outputs":[{"internalType":"contract Authority","name":"","type":"address"}],"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":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"uint256","name":"assetsWithFee","type":"uint256"}],"name":"cancelRedeem","outputs":[],"stateMutability":"nonpayable","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"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"minShares","type":"uint256"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"feeContract","outputs":[{"internalType":"contract IVariableVaultFee","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"initiator","type":"address"},{"internalType":"address","name":"operator","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"flashRedeem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"uint256","name":"assetsWithFee","type":"uint256"}],"name":"fulfillInstantRedeem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"uint256","name":"assetsWithFee","type":"uint256"}],"name":"fulfillRedeem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getFeeRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_asset","type":"address"},{"internalType":"address","name":"_owner","type":"address"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"bytes4","name":"functionSig","type":"bytes4"}],"name":"isAuthorized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"isRecipientWhitelisted","outputs":[{"internalType":"bool","name":"isWhitelisted","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastBlockUpdated","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastPricePerShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"targets","type":"address[]"},{"internalType":"bytes[]","name":"data","type":"bytes[]"},{"internalType":"uint256[]","name":"values","type":"uint256[]"}],"name":"manage","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"manage","outputs":[{"internalType":"bytes","name":"result","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"maxDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"maxMint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxPercentageChange","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"maxRedeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"maxWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minDepositAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"maxAssets","type":"uint256"}],"name":"mint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newAggregatedBalance","type":"uint256"}],"name":"onUnderlyingBalanceUpdate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"pendingRedeemRequest","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"uint256","name":"pendingShares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewFlashRedeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewInstantRedeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewMint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewRedeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"removeFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"requestInstantRedeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"requestRedeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract Authority","name":"newAuthority","type":"address"}],"name":"setAuthority","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IVariableVaultFee","name":"_feeContract","type":"address"}],"name":"setFeeContract","outputs":[],"stateMutability":"nonpayable","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":"totalPendingAssets","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":"value","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":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newMaxPercentageChange","type":"uint256"}],"name":"updateMaxPercentageChange","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newMinDepositAmount","type":"uint256"}],"name":"updateMinDepositAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"bool","name":"status","type":"bool"}],"name":"whitelistFundTransferRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60a060405230608052348015610013575f5ffd5b5061001c610021565b6100d3565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000900460ff16156100715760405163f92ee8a960e01b815260040160405180910390fd5b80546001600160401b03908116146100d05780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b608051615d706100f95f395f81816136c0015281816136e901526138b80152615d705ff3fe6080604052600436106103cd575f3560e01c80637d41c86e11610203578063b460af9411610122578063cfa40aed116100b7578063dd62ed3e11610087578063ef8b30f71161006d578063ef8b30f714610d0b578063f2fde38b14610d2a578063f6e715d014610d49575f5ffd5b8063dd62ed3e14610c89578063e3d00c5e14610cec575f5ffd5b8063cfa40aed14610bc2578063d237c54e14610bf5578063d905777e14610c4b578063d9972b9614610c6a575f5ffd5b8063c63d75b6116100f2578063c63d75b614610657578063c6e6f59214610b65578063ca1435f314610b84578063ce96cb7714610ba3575f5ffd5b8063b460af9414610aeb578063ba08765214610aeb578063bc157ac114610b0a578063bf7e214f14610b29575f5ffd5b806395d89b4111610198578063ac9dc9e811610168578063ac9dc9e814610a32578063ad3cb1cc14610a65578063af4b7d5d14610aad578063b3d7f6b914610acc575f5ffd5b806395d89b41146109ad578063985be808146109c1578063a9059cbb146109e0578063ab4f0f01146109ff575f5ffd5b80638d2ff937116101d35780638d2ff9371461093c5780638da5cb5b1461095b57806394bf804d1461096f57806395c5eaf51461098e575f5ffd5b80637d41c86e146108cb578063836a1040146108ea5780638456cb5914610909578063847802051461091d575f5ffd5b80633f4ba83a116102ef5780635c975abb1161028457806370a082311161025457806370a0823114610807578063757815e11461085a578063760f5f27146108795780637a9e5e4b146108ac575f5ffd5b80635c975abb146107605780636442b2ba14610796578063645006ca146107b55780636e553f65146107e8575f5ffd5b80634cdad506116102bf5780634cdad506146106aa5780634f1ef286146106c957806352d1902d146106dc57806353dc1dd3146106f0575f5ffd5b80633f4ba83a14610643578063402d267d1461065757806342dbe168146106775780634ccb20c014610696575f5ffd5b806318160ddd1161036557806323b872dd1161033557806323b872dd146105a3578063313ce567146105c257806338d52e0f146105e85780633e4d991214610624575f5ffd5b806318160ddd146105065780631cd1c8c3146105395780632016a0d214610558578063224d870314610577575f5ffd5b806307a2d13a116103a057806307a2d13a14610478578063095ea7b3146104975780630a28a477146104c657806314d7b912146104e5575f5ffd5b806301e1d114146103d157806303d4113b146103f857806306e297121461042b57806306fdde0314610457575b5f5ffd5b3480156103dc575f5ffd5b506103e5610d68565b6040519081526020015b60405180910390f35b348015610403575f5ffd5b507f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af900546103e5565b348015610436575f5ffd5b5061043f610e50565b6040516001600160a01b0390911681526020016103ef565b348015610462575f5ffd5b5061046b610e82565b6040516103ef91906151c9565b348015610483575f5ffd5b506103e56104923660046151db565b610f55565b3480156104a2575f5ffd5b506104b66104b1366004615206565b610f66565b60405190151581526020016103ef565b3480156104d1575f5ffd5b506103e56104e03660046151db565b610f7d565b3480156104f0575f5ffd5b506105046104ff366004615230565b610fd4565b005b348015610511575f5ffd5b507f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace02546103e5565b348015610544575f5ffd5b50610504610553366004615230565b611070565b348015610563575f5ffd5b50610504610572366004615324565b61124d565b348015610582575f5ffd5b506105966105913660046153f5565b6113bc565b6040516103ef9190615494565b3480156105ae575f5ffd5b506104b66105bd366004615515565b61172d565b3480156105cd575f5ffd5b506105d6611750565b60405160ff90911681526020016103ef565b3480156105f3575f5ffd5b507f0773e532dfede91f04b12a73d3d2acd361424f41f76b4fb79f090161e36b4e00546001600160a01b031661043f565b34801561062f575f5ffd5b5061050461063e366004615553565b61179d565b34801561064e575f5ffd5b5061050461182c565b348015610662575f5ffd5b506103e5610671366004615581565b505f1990565b348015610682575f5ffd5b50610504610691366004615581565b611886565b3480156106a1575f5ffd5b5061043f6118e2565b3480156106b5575f5ffd5b506103e56106c43660046151db565b611921565b6105046106d736600461559c565b611972565b3480156106e7575f5ffd5b506103e561198d565b3480156106fb575f5ffd5b5061074b61070a366004615581565b6001600160a01b03165f9081527f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af9066020526040902080546001909101549091565b604080519283526020830191909152016103ef565b34801561076b575f5ffd5b507fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff166104b6565b3480156107a1575f5ffd5b506105046107b0366004615230565b6119bb565b3480156107c0575f5ffd5b507f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af905546103e5565b3480156107f3575f5ffd5b506103e5610802366004615553565b611a46565b348015610812575f5ffd5b506103e5610821366004615581565b6001600160a01b03165f9081527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00602052604090205490565b348015610865575f5ffd5b5061050461087436600461563a565b611b27565b348015610884575f5ffd5b507f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af901546103e5565b3480156108b7575f5ffd5b506105046108c6366004615581565b6120a8565b3480156108d6575f5ffd5b506103e56108e53660046156a8565b612219565b3480156108f5575f5ffd5b506103e56109043660046156e7565b612275565b348015610914575f5ffd5b506105046122cf565b348015610928575f5ffd5b506105046109373660046151db565b612327565b348015610947575f5ffd5b50610504610956366004615718565b6123fa565b348015610966575f5ffd5b5061043f612454565b34801561097a575f5ffd5b506103e5610989366004615553565b61247b565b348015610999575f5ffd5b506105046109a83660046151db565b61255e565b3480156109b8575f5ffd5b5061046b612672565b3480156109cc575f5ffd5b506103e56109db3660046151db565b6126c3565b3480156109eb575f5ffd5b506104b66109fa366004615206565b61270a565b348015610a0a575f5ffd5b507f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af903546103e5565b348015610a3d575f5ffd5b507f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af902546103e5565b348015610a70575f5ffd5b5061046b6040518060400160405280600581526020017f352e302e3000000000000000000000000000000000000000000000000000000081525081565b348015610ab8575f5ffd5b506103e5610ac73660046156a8565b612717565b348015610ad7575f5ffd5b506103e5610ae63660046151db565b6127b4565b348015610af6575f5ffd5b506103e5610b053660046156a8565b612805565b348015610b15575f5ffd5b506103e5610b243660046156e7565b612840565b348015610b34575f5ffd5b507fdd3fd67aef415aded9493b31ad20a02d2991d4bb2760431cc729821271eaea01546001600160a01b031661043f565b348015610b70575f5ffd5b506103e5610b7f3660046151db565b61289a565b348015610b8f575f5ffd5b506103e5610b9e3660046151db565b6128a5565b348015610bae575f5ffd5b506103e5610bbd366004615581565b6128ec565b348015610bcd575f5ffd5b507f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af904546103e5565b348015610c00575f5ffd5b506104b6610c0f366004615581565b6001600160a01b03165f9081527f2bbdf87c296f0fc445d947563c77d7b805fc738a2e220084769a264d45deaf00602052604090205460ff1690565b348015610c56575f5ffd5b506103e5610c65366004615581565b61292d565b348015610c75575f5ffd5b506104b6610c84366004615744565b612969565b348015610c94575f5ffd5b506103e5610ca336600461577c565b6001600160a01b039182165f9081527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace016020908152604080832093909416825291909152205490565b348015610cf7575f5ffd5b50610504610d063660046151db565b612a79565b348015610d16575f5ffd5b506103e5610d253660046151db565b612bfe565b348015610d35575f5ffd5b50610504610d44366004615581565b612c49565b348015610d54575f5ffd5b5061046b610d633660046157a8565b612d1b565b7f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af90080545f9190610dbf7f0773e532dfede91f04b12a73d3d2acd361424f41f76b4fb79f090161e36b4e00546001600160a01b031690565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa158015610e1c573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e409190615800565b610e4a9190615844565b91505090565b5f7f4e0114f5bb788bf295d0ab17f602045fbe9841605d1e05a2674fbfa584e947005b546001600160a01b0316919050565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0380546060917f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0091610ed390615857565b80601f0160208091040260200160405190810160405280929190818152602001828054610eff90615857565b8015610f4a5780601f10610f2157610100808354040283529160200191610f4a565b820191905f5260205f20905b815481529060010190602001808311610f2d57829003601f168201915b505050505091505090565b5f610f60825f612eef565b92915050565b5f33610f73818585612f46565b5060019392505050565b5f5f610fb9610fb37f0773e532dfede91f04b12a73d3d2acd361424f41f76b4fb79f090161e36b4e00546001600160a01b031690565b84612f53565b9050610fcd610fc88285615844565b612f61565b9392505050565b610fe9335f356001600160e01b031916612969565b6110295760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b60448201526064015b60405180910390fd5b61106b6040518060800160405280856001600160a01b03168152602001848152602001838152602001600180811115611064576110646158a8565b9052612f6d565b505050565b611085335f356001600160e01b031916612969565b6110c05760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606401611020565b6001600160a01b0383165f9081527f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af9066020526040902060018101547f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af900919015801590611130575080600101548411155b611166576040517f01e3468e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805415801590611177575080548311155b6111ad576040517f3b83271300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83816001015f8282546111c091906158d5565b90915550508054839082905f906111d89084906158d5565b9250508190555082826003015f8282546111f291906158d5565b909155505060408051858152602081018590526001600160a01b038716917f55ec94ca0f01023d07c5752a75f44048cfbdb0e4cfedf5e7eacecf21fcde3587910160405180910390a26112463086866130ef565b5050505050565b5f611256613163565b805490915060ff68010000000000000000820416159067ffffffffffffffff165f811580156112825750825b90505f8267ffffffffffffffff16600114801561129e5750303b155b9050811580156112ac575080155b156112e3576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84547fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000016600117855583156113445784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff16680100000000000000001785555b6113508989898961318b565b83156113b15784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b505050505050505050565b60606113d3335f356001600160e01b031916612969565b61140e5760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606401611020565b85848114801561141d57508483145b6114695760405162461bcd60e51b815260206004820152601860248201527f4172726179206c656e67746873206d757374206d6174636800000000000000006044820152606401611020565b8067ffffffffffffffff81111561148257611482615262565b6040519080825280602002602001820160405280156114b557816020015b60608152602001906001900390816114a05790505b5091505f5b81811015611721575f8787838181106114d5576114d56158e8565b90506020028101906114e79190615915565b6114f091615976565b90506115237fdd3fd67aef415aded9493b31ad20a02d2991d4bb2760431cc729821271eaea01546001600160a01b031690565b6001600160a01b031663b7009613338c8c86818110611544576115446158e8565b90506020020160208101906115599190615581565b6040516001600160e01b031960e085901b811682526001600160a01b0393841660048301529290911660248201529084166044820152606401602060405180830381865afa1580156115ad573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115d191906159ac565b8a8a848181106115e3576115e36158e8565b90506020020160208101906115f89190615581565b82909161164c576040517ffb5630260000000000000000000000000000000000000000000000000000000081526001600160a01b0390921660048301526001600160e01b0319166024820152604401611020565b50506116fb888884818110611663576116636158e8565b90506020028101906116759190615915565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152508a92508991508690508181106116bd576116bd6158e8565b905060200201358c8c868181106116d6576116d66158e8565b90506020020160208101906116eb9190615581565b6001600160a01b031691906131df565b84838151811061170d5761170d6158e8565b6020908102919091010152506001016114ba565b50509695505050505050565b5f3361173a85828561328e565b61174585858561333c565b506001949350505050565b5f807f0773e532dfede91f04b12a73d3d2acd361424f41f76b4fb79f090161e36b4e0090505f8154610e4a919074010000000000000000000000000000000000000000900460ff166159c7565b6117b2335f356001600160e01b031916612969565b6117ed5760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606401611020565b6118286118217f0773e532dfede91f04b12a73d3d2acd361424f41f76b4fb79f090161e36b4e00546001600160a01b031690565b83836133cb565b5050565b611841335f356001600160e01b031916612969565b61187c5760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606401611020565b6118846134e4565b565b61189b335f356001600160e01b031916612969565b6118d65760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606401611020565b6118df81613574565b50565b5f61191c6119177f0773e532dfede91f04b12a73d3d2acd361424f41f76b4fb79f090161e36b4e00546001600160a01b031690565b613618565b905090565b5f5f61192c83610f55565b90506119686119627f0773e532dfede91f04b12a73d3d2acd361424f41f76b4fb79f090161e36b4e00546001600160a01b031690565b826136a7565b610fcd90826158d5565b61197a6136b5565b6119838261375c565b61182882826137ac565b5f6119966138ad565b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc90565b6119d0335f356001600160e01b031916612969565b611a0b5760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606401611020565b61106b6040518060800160405280856001600160a01b031681526020018481526020018381526020015f6001811115611064576110646158a8565b5f611a4f61390f565b611a5761396b565b5f197f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af905547f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af9009080861015611ae1576040517fc42971700000000000000000000000000000000000000000000000000000000081526004810187905260248101829052604401611020565b5f611aeb87612bfe565b9050611af9338789846139ec565b9350505050610f6060017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b611b2f61390f565b611b44335f356001600160e01b031916612969565b611b7f5760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606401611020565b611b8761396b565b5f8311611bc0576040517f840c364a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038416611c00576040517fa05ff47e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038516611c40576040517feb32d3bf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f611c727f0773e532dfede91f04b12a73d3d2acd361424f41f76b4fb79f090161e36b4e00546001600160a01b031690565b90505f611c7e85610f55565b90505f611c8b8383613aa4565b90505f611c9882846158d5565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529091505f906001600160a01b038616906370a0823190602401602060405180830381865afa158015611cf8573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611d1c9190615800565b905083811015611d58576040517f3b83271300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b305f9081527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0060205260409020547f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0254611dbc6001600160a01b0388168c866130ef565b8b6001600160a01b0316636b5fe49d8e308a8e898f8f6040518863ffffffff1660e01b8152600401611df497969594939291906159e0565b5f604051808303815f87803b158015611e0b575f5ffd5b505af1158015611e1d573d5f5f3e3d5ffd5b5050305f9081527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0060205260409020549150611e5b90508b84615844565b811015611e94576040517f7cabe4bc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50611e9f308b613ab2565b611ea98a826158d5565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace025414611f02576040517f596a843700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f906001600160a01b038916906370a0823190602401602060405180830381865afa158015611f5f573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f839190615800565b905080611f9088866158d5565b1115611fc8576040517f19c17f2f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505f611fd388613618565b90505f86118015611fec57506001600160a01b03811615155b15612005576120056001600160a01b03891682886130ef565b8b6001600160a01b03168d6001600160a01b03168f6001600160a01b03167f98ad0da4de20359d393d1dfaa8f15da86ac4e45a9108ab5582f871ee281a0f948e898b604051612067939291909283526020830191909152604082015260600190565b60405180910390a450505050505050506120a060017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b505050505050565b7fdd3fd67aef415aded9493b31ad20a02d2991d4bb2760431cc729821271eaea0080546001600160a01b0316331480612178575060018101546040517fb70096130000000000000000000000000000000000000000000000000000000081523360048201523060248201525f356001600160e01b03191660448201526001600160a01b039091169063b700961390606401602060405180830381865afa158015612154573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061217891906159ac565b6121b35760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606401611020565b6001810180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03841690811790915560405133907fa3396fd7f6e0a21b50e5089d2da70d5ac0a3bbbd1f617a93f134b76389980198905f90a35050565b5f61222261390f565b61226d6040518060800160405280868152602001856001600160a01b03168152602001846001600160a01b031681526020015f6001811115612266576122666158a8565b9052613aff565b949350505050565b5f61227e61390f565b5f612289858561247b565b90508281111561226d576040517f9bab65290000000000000000000000000000000000000000000000000000000081526004810182905260248101849052604401611020565b6122e4335f356001600160e01b031916612969565b61231f5760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606401611020565b611884613d07565b61233c335f356001600160e01b031916612969565b6123775760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606401611020565b7f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af90554604080519182526020820183905280517f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af900927f5fb4589fcdfab8bd40d9776abc10876bb1cb02c0edab28d05cc42869b40e032992908290030190a160050155565b61240f335f356001600160e01b031916612969565b61244a5760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606401611020565b6118288282613d80565b5f7fdd3fd67aef415aded9493b31ad20a02d2991d4bb2760431cc729821271eaea00610e73565b5f61248461390f565b61248c61396b565b5f195f612498856127b4565b7f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af905549091507f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af9009080831015612523576040517fc42971700000000000000000000000000000000000000000000000000000000081526004810184905260248101829052604401611020565b61252f3387858a6139ec565b509092505050610f6060017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b612573335f356001600160e01b031916612969565b6125ae5760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606401611020565b67016345785d8a000081106125ef576040517f5aede91d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af90454604080519182526020820183905280517f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af900927f5b1f8430a1675242d4a0bdb976ee1c8740d114671db54660aba42fb46293e5dd92908290030190a160040155565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0480546060917f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0091610ed390615857565b5f5f6126ce83610f55565b90506119686127047f0773e532dfede91f04b12a73d3d2acd361424f41f76b4fb79f090161e36b4e00546001600160a01b031690565b82613aa4565b5f33610f7381858561333c565b5f61272061390f565b612735335f356001600160e01b031916612969565b6127705760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606401611020565b61226d6040518060800160405280868152602001856001600160a01b03168152602001846001600160a01b03168152602001600180811115612266576122666158a8565b5f5f6127bf83613eb7565b90506127fb6127f57f0773e532dfede91f04b12a73d3d2acd361424f41f76b4fb79f090161e36b4e00546001600160a01b031690565b82613ec3565b610fcd9082615844565b5f61280e61390f565b6040517f797f246a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f61284961390f565b5f6128548585611a46565b90508281101561226d576040517fb305bf640000000000000000000000000000000000000000000000000000000081526004810182905260248101849052604401611020565b5f610f60825f613ed1565b5f5f6128b083610f55565b90506119686128e67f0773e532dfede91f04b12a73d3d2acd361424f41f76b4fb79f090161e36b4e00546001600160a01b031690565b82613f1f565b6001600160a01b0381165f9081527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace006020526040812054610f60905f612eef565b6001600160a01b0381165f9081527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace006020526040812054610f60565b7fdd3fd67aef415aded9493b31ad20a02d2991d4bb2760431cc729821271eaea01545f907fdd3fd67aef415aded9493b31ad20a02d2991d4bb2760431cc729821271eaea00906001600160a01b03168015801590612a5957506040517fb70096130000000000000000000000000000000000000000000000000000000081526001600160a01b0386811660048301523060248301526001600160e01b03198616604483015282169063b700961390606401602060405180830381865afa158015612a35573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612a5991906159ac565b80612a70575081546001600160a01b038681169116145b95945050505050565b612a8e335f356001600160e01b031916612969565b612ac95760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606401611020565b7f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af901547f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af900904311612b45576040517f95628bbc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805460408051918252602082018490527f06829c36c32a24a199e4c4c18e4cf08af24d8301c3e4e500c08ae1dbc28498fe910160405180910390a18181555f612bc7670de0b6b3a7640000612bb87f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace025490565b612bc0610d68565b9190613f2d565b90505f612bd8836002015483613fdd565b90508260040154811115612bee57612bee613d07565b5060028201554360019091015550565b5f5f612c3a612c347f0773e532dfede91f04b12a73d3d2acd361424f41f76b4fb79f090161e36b4e00546001600160a01b031690565b84614024565b9050610fcd610b7f82856158d5565b612c5e335f356001600160e01b031916612969565b612c995760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606401611020565b7fdd3fd67aef415aded9493b31ad20a02d2991d4bb2760431cc729821271eaea0080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038316908117825560405133907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b6060612d32335f356001600160e01b031916612969565b612d6d5760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606401611020565b5f612d788486615976565b9050612dab7fdd3fd67aef415aded9493b31ad20a02d2991d4bb2760431cc729821271eaea01546001600160a01b031690565b6040517fb70096130000000000000000000000000000000000000000000000000000000081523360048201526001600160a01b0388811660248301526001600160e01b031984166044830152919091169063b700961390606401602060405180830381865afa158015612e20573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612e4491906159ac565b86829091612e99576040517ffb5630260000000000000000000000000000000000000000000000000000000081526001600160a01b0390921660048301526001600160e01b0319166024820152604401611020565b5050612ee585858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525050506001600160a01b038916919050856131df565b9695505050505050565b5f610fcd612efb610d68565b612f06906001615844565b612f115f600a615b2f565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0254612f3d9190615844565b85919085614031565b61106b8383836001614073565b5f610fcd838360018061419b565b5f610f60826001613ed1565b80516001600160a01b03165f9081527f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af9066020526040902060018101547f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af900919015801590612fe257508060010154836020015111155b613018576040517f01e3468e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80541580159061302d57508054604084015111155b613063576040517f3b83271300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8260200151816001015f82825461307a91906158d5565b90915550506040830151815482905f906130959084906158d5565b909155505060408301516003830180545f906130b29084906158d5565b925050819055506130d4835f01518460200151856040015186606001516142d3565b61106b835f01518460400151856020015186606001516143d9565b6040516001600160a01b0383811660248301526044820183905261106b91859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506144cc565b5f807ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00610f60565b613193614551565b61319d828261458f565b6131a6846145a1565b6131b0835f6145b2565b6131b86145c4565b6131c15f6145cc565b6131c96145dd565b6131d16145ed565b6131d96145fd565b50505050565b606081471015613224576040517fcf47918100000000000000000000000000000000000000000000000000000000815247600482015260248101839052604401611020565b5f5f856001600160a01b0316848660405161323f9190615b3d565b5f6040518083038185875af1925050503d805f8114613279576040519150601f19603f3d011682016040523d82523d5f602084013e61327e565b606091505b5091509150612ee5868383614654565b6001600160a01b038381165f9081527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0160209081526040808320938616835292905220545f198110156131d9578181101561332e576040517ffb8f41b20000000000000000000000000000000000000000000000000000000081526001600160a01b03841660048201526024810182905260448101839052606401611020565b6131d984848484035f614073565b6001600160a01b03831661337e576040517f96c6fd1e0000000000000000000000000000000000000000000000000000000081525f6004820152602401611020565b6001600160a01b0382166133c0576040517fec442f050000000000000000000000000000000000000000000000000000000081525f6004820152602401611020565b61106b8383836146c9565b815f03613404576040517fcbca5aa200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0381165f9081527f2bbdf87c296f0fc445d947563c77d7b805fc738a2e220084769a264d45deaf00602052604090205460ff16613474576040517f5ed3324c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6134886001600160a01b03841682846130ef565b806001600160a01b0316836001600160a01b0316336001600160a01b03167f92b6694567ccb3e850077b2848795b0dc9d5485503ac401c32f10a01d0e12cfc856040516134d791815260200190565b60405180910390a4505050565b6134ec6146dc565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001681557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a150565b7f4e0114f5bb788bf295d0ab17f602045fbe9841605d1e05a2674fbfa584e947005f61359e610e50565b82547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038581169182178555604080519184168252602082019290925291925033917feb7962da2115819e0ac9a926e8d3a292bc532effcbdf8d7cc3e60cc6eccca9a4910160405180910390a2505050565b5f5f613622610e50565b6040517f5d9c4f0f0000000000000000000000000000000000000000000000000000000081526001600160a01b03858116600483015291925090821690635d9c4f0f90602401602060405180830381865afa158015613683573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610fcd9190615b53565b5f610fcd838360015f61419b565b306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148061372557507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316613719614737565b6001600160a01b031614155b15611884576040517fe07c8dba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613771335f356001600160e01b031916612969565b6118df5760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606401611020565b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015613806575060408051601f3d908101601f1916820190925261380391810190615800565b60015b613847576040517f4c9c8ce30000000000000000000000000000000000000000000000000000000081526001600160a01b0383166004820152602401611020565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc81146138a3576040517faa1d49a400000000000000000000000000000000000000000000000000000000815260048101829052602401611020565b61106b838361475e565b306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611884576040517fe07c8dba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff1615611884576040517fd93c066500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0080547ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016139e6576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60029055565b5f613a1e7f0773e532dfede91f04b12a73d3d2acd361424f41f76b4fb79f090161e36b4e00546001600160a01b031690565b90505f613a2b8285614024565b90505f613a3783613618565b9050613a45878787876147b3565b5f82118015613a5c57506001600160a01b03811615155b15613a7557613a756001600160a01b03841682846130ef565b50505050505050565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b5f610fcd838360035f61419b565b6001600160a01b038216613af4576040517f96c6fd1e0000000000000000000000000000000000000000000000000000000081525f6004820152602401611020565b611828825f836146c9565b80515f90613b39576040517f840c364a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408201516001600160a01b03163314613b7f576040517fe7fe5cf400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81516040808401516001600160a01b03165f9081527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0060205220541015613bf2576040517f3999656700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f613bff835f0151610f55565b9050613c1d8360200151846040015183865f01518760600151614855565b604083015183517f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af90091613c5191309061333c565b81816003015f828254613c649190615844565b90915550506040805180820182526020808701516001600160a01b03165f9081526006850190915291909120548190613c9e908590615844565b815285516020878101516001600160a01b03165f9081526006860182526040902060010154920191613cd09190615844565b90526020948501516001600160a01b03165f9081526006909201855260408220815181559401516001909401939093555090919050565b613d0f61390f565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011781557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25833613556565b7f2bbdf87c296f0fc445d947563c77d7b805fc738a2e220084769a264d45deaf006001600160a01b038316613de1576040517f9fabe1c100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0383165f9081526020829052604090205482151560ff909116151503613e3a576040517faaed924400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0383165f818152602083815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016861515908117909155915191825233917fd9c6c3eabe38e3b9a606a66358d8f225489216a59eeba66facefb7d916635266910160405180910390a3505050565b5f610f60826001612eef565b5f610fcd83835f600161419b565b5f610fcd613ee082600a615b2f565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0254613f0c9190615844565b613f14610d68565b612f3d906001615844565b5f610fcd838360025f61419b565b5f5f5f613f3a868661492f565b91509150815f03613f5e57838181613f5457613f54615b6e565b0492505050610fcd565b818411613f7557613f75600385150260111861494b565b5f848688095f868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010185841190960395909502919093039390930492909217029150509392505050565b5f825f03613fec57505f610f60565b5f83831161400357613ffe83856158d5565b61400d565b61400d84846158d5565b905061226d81670de0b6b3a7640000866001614031565b5f610fcd83835f5f61419b565b5f61405e61403e8361495c565b801561405957505f848061405457614054615b6e565b868809115b151590565b614069868686613f2d565b612a709190615844565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace006001600160a01b0385166140d6576040517fe602df050000000000000000000000000000000000000000000000000000000081525f6004820152602401611020565b6001600160a01b038416614118576040517f94280d620000000000000000000000000000000000000000000000000000000081525f6004820152602401611020565b6001600160a01b038086165f9081526001830160209081526040808320938816835292905220839055811561124657836001600160a01b0316856001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258560405161418c91815260200190565b60405180910390a35050505050565b5f5f6141a5610e50565b90506001600160a01b0381166141f4576040517f2414b2d50000000000000000000000000000000000000000000000000000000081526001600160e01b03195f35166004820152602401611020565b821561428a576040517f4cfd82050000000000000000000000000000000000000000000000000000000081526001600160a01b03821690634cfd82059061424390899089908990600401615b9b565b602060405180830381865afa15801561425e573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906142829190615800565b91505061226d565b6040517fed5293050000000000000000000000000000000000000000000000000000000081526001600160a01b0382169063ed5293059061424390899089908990600401615b9b565b5f8160018111156142e6576142e66158a8565b036143355760408051848152602081018490526001600160a01b038616917f1165aa98d42fbaef9bacc273d7b5cca8edc94909519f8f949ec33562963c87e491015b60405180910390a26131d9565b6001816001811115614349576143496158a8565b0361438f5760408051848152602081018490526001600160a01b038616917f908b1a496603d6db727346172db92bbb94fb4434f93048b25a25c425d426f5829101614328565b8060018111156143a1576143a16158a8565b6040517f9caf260e00000000000000000000000000000000000000000000000000000000815260ff9091166004820152602401611020565b5f61440b7f0773e532dfede91f04b12a73d3d2acd361424f41f76b4fb79f090161e36b4e00546001600160a01b031690565b90505f80836001811115614421576144216158a8565b036144375761443082866136a7565b905061446c565b600183600181111561444b5761444b6158a8565b0361445a576144308286613f1f565b8260018111156143a1576143a16158a8565b5f61447782876158d5565b90505f61448384613618565b9050614492308930858a614988565b5f831180156144a957506001600160a01b03811615155b156144c2576144c26001600160a01b03851682856130ef565b5050505050505050565b5f5f60205f8451602086015f885af1806144eb576040513d5f823e3d81fd5b50505f513d9150811561450257806001141561450f565b6001600160a01b0384163b155b156131d9576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401611020565b614559614a58565b611884576040517fd7e6bcf800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b614597614551565b6118288282614a76565b6145a9614551565b6118df81614ad9565b6145ba614551565b6118288282614b9d565b611884614551565b6145d4614551565b6118df81614c8d565b6145e5614551565b6118846145c4565b6145f5614551565b611884614d29565b614605614551565b662386f26fc100007f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af904555f7f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af90555565b6060826146695761466482614d31565b610fcd565b815115801561468057506001600160a01b0384163b155b156146c2576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401611020565b5080610fcd565b6146d161390f565b61106b838383614d72565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff16611884576040517f8dfc202b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc610e73565b61476782614ec9565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a28051156147ab5761106b8282614f70565b611828614fd9565b6147ef6147e77f0773e532dfede91f04b12a73d3d2acd361424f41f76b4fb79f090161e36b4e00546001600160a01b031690565b853085615011565b6147f9838261504a565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d78484604051614847929190918252602082015260400190565b60405180910390a350505050565b5f816001811115614868576148686158a8565b036148c857836001600160a01b0316856001600160a01b03167f6d109ae63c8098a8b0ae2c1c6195469c03cbee2f45061230650bc1b31f3891db85856040516148bb929190918252602082015260400190565b60405180910390a3611246565b60018160018111156148dc576148dc6158a8565b0361438f57836001600160a01b0316856001600160a01b03167fd46caa0122af654d133b7a1fe5644d9594644f64c366834a6ee96ef23c3871fb85856040516148bb929190918252602082015260400190565b5f805f1983850993909202808410938190039390930393915050565b634e487b715f52806020526024601cfd5b5f6002826003811115614971576149716158a8565b61497b9190615bf5565b60ff166001149050919050565b826001600160a01b0316856001600160a01b0316146149ac576149ac83868361328e565b6149b68382613ab2565b6149f16149ea7f0773e532dfede91f04b12a73d3d2acd361424f41f76b4fb79f090161e36b4e00546001600160a01b031690565b85846130ef565b826001600160a01b0316846001600160a01b0316866001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db8585604051614a49929190918252602082015260400190565b60405180910390a45050505050565b5f614a61613163565b5468010000000000000000900460ff16919050565b614a7e614551565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace007f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace03614aca8482615c7f565b50600481016131d98382615c7f565b614ae1614551565b7f0773e532dfede91f04b12a73d3d2acd361424f41f76b4fb79f090161e36b4e005f80614b0d84615097565b9150915081614b1d576012614b1f565b805b83547fffffffffffffffffffffff000000000000000000000000000000000000000000167401000000000000000000000000000000000000000060ff92909216919091027fffffffffffffffffffffffff000000000000000000000000000000000000000016176001600160a01b0394909416939093179091555050565b614ba5614551565b7fdd3fd67aef415aded9493b31ad20a02d2991d4bb2760431cc729821271eaea0080547fffffffffffffffffffffffff00000000000000000000000000000000000000009081166001600160a01b0385811691821784557fdd3fd67aef415aded9493b31ad20a02d2991d4bb2760431cc729821271eaea0180549093169085161790915560405133907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a36040516001600160a01b0383169033907fa3396fd7f6e0a21b50e5089d2da70d5ac0a3bbbd1f617a93f134b76389980198905f90a3505050565b614c95614551565b7f4e0114f5bb788bf295d0ab17f602045fbe9841605d1e05a2674fbfa584e9470080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081178255604080515f81526020810192909252805133927feb7962da2115819e0ac9a926e8d3a292bc532effcbdf8d7cc3e60cc6eccca9a492908290030190a25050565b613a7e614551565b805115614d4057805160208201fd5b6040517fd6bda27500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace006001600160a01b038416614dbf5781816002015f828254614db49190615844565b90915550614e489050565b6001600160a01b0384165f9081526020829052604090205482811015614e2a576040517fe450d38c0000000000000000000000000000000000000000000000000000000081526001600160a01b03861660048201526024810182905260448101849052606401611020565b6001600160a01b0385165f9081526020839052604090209083900390555b6001600160a01b038316614e66576002810180548390039055614e84565b6001600160a01b0383165f9081526020829052604090208054830190555b826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161484791815260200190565b806001600160a01b03163b5f03614f17576040517f4c9c8ce30000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602401611020565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b60605f5f846001600160a01b031684604051614f8c9190615b3d565b5f60405180830381855af49150503d805f8114614fc4576040519150601f19603f3d011682016040523d82523d5f602084013e614fc9565b606091505b5091509150612a70858383614654565b3415611884576040517fb398979f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b0384811660248301528381166044830152606482018390526131d99186918216906323b872dd9060840161311c565b6001600160a01b03821661508c576040517fec442f050000000000000000000000000000000000000000000000000000000081525f6004820152602401611020565b6118285f83836146c9565b60408051600481526024810182526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f313ce5670000000000000000000000000000000000000000000000000000000017905290515f918291829182916001600160a01b0387169161510b91615b3d565b5f60405180830381855afa9150503d805f8114615143576040519150601f19603f3d011682016040523d82523d5f602084013e615148565b606091505b509150915081801561515c57506020815110155b1561518f575f818060200190518101906151769190615800565b905060ff811161518d576001969095509350505050565b505b505f9485945092505050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f610fcd602083018461519b565b5f602082840312156151eb575f5ffd5b5035919050565b6001600160a01b03811681146118df575f5ffd5b5f5f60408385031215615217575f5ffd5b8235615222816151f2565b946020939093013593505050565b5f5f5f60608486031215615242575f5ffd5b833561524d816151f2565b95602085013595506040909401359392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f5f67ffffffffffffffff8411156152a9576152a9615262565b50604051601f19601f85018116603f0116810181811067ffffffffffffffff821117156152d8576152d8615262565b6040528381529050808284018510156152ef575f5ffd5b838360208301375f60208583010152509392505050565b5f82601f830112615315575f5ffd5b610fcd8383356020850161528f565b5f5f5f5f60808587031215615337575f5ffd5b8435615342816151f2565b93506020850135615352816151f2565b9250604085013567ffffffffffffffff81111561536d575f5ffd5b61537987828801615306565b925050606085013567ffffffffffffffff811115615395575f5ffd5b6153a187828801615306565b91505092959194509250565b5f5f83601f8401126153bd575f5ffd5b50813567ffffffffffffffff8111156153d4575f5ffd5b6020830191508360208260051b85010111156153ee575f5ffd5b9250929050565b5f5f5f5f5f5f6060878903121561540a575f5ffd5b863567ffffffffffffffff811115615420575f5ffd5b61542c89828a016153ad565b909750955050602087013567ffffffffffffffff81111561544b575f5ffd5b61545789828a016153ad565b909550935050604087013567ffffffffffffffff811115615476575f5ffd5b61548289828a016153ad565b979a9699509497509295939492505050565b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b82811015615509577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08786030184526154f485835161519b565b945060209384019391909101906001016154ba565b50929695505050505050565b5f5f5f60608486031215615527575f5ffd5b8335615532816151f2565b92506020840135615542816151f2565b929592945050506040919091013590565b5f5f60408385031215615564575f5ffd5b823591506020830135615576816151f2565b809150509250929050565b5f60208284031215615591575f5ffd5b8135610fcd816151f2565b5f5f604083850312156155ad575f5ffd5b82356155b8816151f2565b9150602083013567ffffffffffffffff8111156155d3575f5ffd5b8301601f810185136155e3575f5ffd5b6155f28582356020840161528f565b9150509250929050565b5f5f83601f84011261560c575f5ffd5b50813567ffffffffffffffff811115615623575f5ffd5b6020830191508360208285010111156153ee575f5ffd5b5f5f5f5f5f5f60a0878903121561564f575f5ffd5b863561565a816151f2565b9550602087013561566a816151f2565b9450604087013561567a816151f2565b935060608701359250608087013567ffffffffffffffff81111561569c575f5ffd5b61548289828a016155fc565b5f5f5f606084860312156156ba575f5ffd5b8335925060208401356156cc816151f2565b915060408401356156dc816151f2565b809150509250925092565b5f5f5f606084860312156156f9575f5ffd5b833592506020840135615542816151f2565b80151581146118df575f5ffd5b5f5f60408385031215615729575f5ffd5b8235615734816151f2565b915060208301356155768161570b565b5f5f60408385031215615755575f5ffd5b8235615760816151f2565b915060208301356001600160e01b031981168114615576575f5ffd5b5f5f6040838503121561578d575f5ffd5b8235615798816151f2565b91506020830135615576816151f2565b5f5f5f5f606085870312156157bb575f5ffd5b84356157c6816151f2565b9350602085013567ffffffffffffffff8111156157e1575f5ffd5b6157ed878288016155fc565b9598909750949560400135949350505050565b5f60208284031215615810575f5ffd5b5051919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820180821115610f6057610f60615817565b600181811c9082168061586b57607f821691505b6020821081036158a2577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b50919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b81810381811115610f6057610f60615817565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f5f83357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112615948575f5ffd5b83018035915067ffffffffffffffff821115615962575f5ffd5b6020019150368190038213156153ee575f5ffd5b80356001600160e01b031981169060048410156159a5576001600160e01b0319808560040360031b1b82161691505b5092915050565b5f602082840312156159bc575f5ffd5b8151610fcd8161570b565b60ff8181168382160190811115610f6057610f60615817565b6001600160a01b03881681526001600160a01b03871660208201526001600160a01b038616604082015284606082015283608082015260c060a08201528160c0820152818360e08301375f81830160e090810191909152601f909201601f191601019695505050505050565b6001815b6001841115615a8757808504811115615a6b57615a6b615817565b6001841615615a7957908102905b60019390931c928002615a50565b935093915050565b5f82615a9d57506001610f60565b81615aa957505f610f60565b8160018114615abf5760028114615ac957615ae5565b6001915050610f60565b60ff841115615ada57615ada615817565b50506001821b610f60565b5060208310610133831016604e8410600b8410161715615b08575081810a610f60565b615b145f198484615a4c565b805f1904821115615b2757615b27615817565b029392505050565b5f610fcd60ff841683615a8f565b5f82518060208501845e5f920191825250919050565b5f60208284031215615b63575f5ffd5b8151610fcd816151f2565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b6001600160a01b0384168152602081018390526060810160048310615be7577f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b826040830152949350505050565b5f60ff831680615c2c577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b8060ff84160691505092915050565b601f82111561106b57805f5260205f20601f840160051c81016020851015615c605750805b601f840160051c820191505b81811015611246575f8155600101615c6c565b815167ffffffffffffffff811115615c9957615c99615262565b615cad81615ca78454615857565b84615c3b565b6020601f821160018114615cdf575f8315615cc85750848201515b5f19600385901b1c1916600184901b178455611246565b5f84815260208120601f198516915b82811015615d0e5787850151825560209485019460019092019101615cee565b5084821015615d2b57868401515f19600387901b60f8161c191681555b50505050600190811b0190555056fea2646970667358221220c77af930c048cc067948e17bd3ec8cf37d261dcd46a852d64d9267cf329b5db664736f6c634300081e0033
Deployed Bytecode
0x6080604052600436106103cd575f3560e01c80637d41c86e11610203578063b460af9411610122578063cfa40aed116100b7578063dd62ed3e11610087578063ef8b30f71161006d578063ef8b30f714610d0b578063f2fde38b14610d2a578063f6e715d014610d49575f5ffd5b8063dd62ed3e14610c89578063e3d00c5e14610cec575f5ffd5b8063cfa40aed14610bc2578063d237c54e14610bf5578063d905777e14610c4b578063d9972b9614610c6a575f5ffd5b8063c63d75b6116100f2578063c63d75b614610657578063c6e6f59214610b65578063ca1435f314610b84578063ce96cb7714610ba3575f5ffd5b8063b460af9414610aeb578063ba08765214610aeb578063bc157ac114610b0a578063bf7e214f14610b29575f5ffd5b806395d89b4111610198578063ac9dc9e811610168578063ac9dc9e814610a32578063ad3cb1cc14610a65578063af4b7d5d14610aad578063b3d7f6b914610acc575f5ffd5b806395d89b41146109ad578063985be808146109c1578063a9059cbb146109e0578063ab4f0f01146109ff575f5ffd5b80638d2ff937116101d35780638d2ff9371461093c5780638da5cb5b1461095b57806394bf804d1461096f57806395c5eaf51461098e575f5ffd5b80637d41c86e146108cb578063836a1040146108ea5780638456cb5914610909578063847802051461091d575f5ffd5b80633f4ba83a116102ef5780635c975abb1161028457806370a082311161025457806370a0823114610807578063757815e11461085a578063760f5f27146108795780637a9e5e4b146108ac575f5ffd5b80635c975abb146107605780636442b2ba14610796578063645006ca146107b55780636e553f65146107e8575f5ffd5b80634cdad506116102bf5780634cdad506146106aa5780634f1ef286146106c957806352d1902d146106dc57806353dc1dd3146106f0575f5ffd5b80633f4ba83a14610643578063402d267d1461065757806342dbe168146106775780634ccb20c014610696575f5ffd5b806318160ddd1161036557806323b872dd1161033557806323b872dd146105a3578063313ce567146105c257806338d52e0f146105e85780633e4d991214610624575f5ffd5b806318160ddd146105065780631cd1c8c3146105395780632016a0d214610558578063224d870314610577575f5ffd5b806307a2d13a116103a057806307a2d13a14610478578063095ea7b3146104975780630a28a477146104c657806314d7b912146104e5575f5ffd5b806301e1d114146103d157806303d4113b146103f857806306e297121461042b57806306fdde0314610457575b5f5ffd5b3480156103dc575f5ffd5b506103e5610d68565b6040519081526020015b60405180910390f35b348015610403575f5ffd5b507f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af900546103e5565b348015610436575f5ffd5b5061043f610e50565b6040516001600160a01b0390911681526020016103ef565b348015610462575f5ffd5b5061046b610e82565b6040516103ef91906151c9565b348015610483575f5ffd5b506103e56104923660046151db565b610f55565b3480156104a2575f5ffd5b506104b66104b1366004615206565b610f66565b60405190151581526020016103ef565b3480156104d1575f5ffd5b506103e56104e03660046151db565b610f7d565b3480156104f0575f5ffd5b506105046104ff366004615230565b610fd4565b005b348015610511575f5ffd5b507f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace02546103e5565b348015610544575f5ffd5b50610504610553366004615230565b611070565b348015610563575f5ffd5b50610504610572366004615324565b61124d565b348015610582575f5ffd5b506105966105913660046153f5565b6113bc565b6040516103ef9190615494565b3480156105ae575f5ffd5b506104b66105bd366004615515565b61172d565b3480156105cd575f5ffd5b506105d6611750565b60405160ff90911681526020016103ef565b3480156105f3575f5ffd5b507f0773e532dfede91f04b12a73d3d2acd361424f41f76b4fb79f090161e36b4e00546001600160a01b031661043f565b34801561062f575f5ffd5b5061050461063e366004615553565b61179d565b34801561064e575f5ffd5b5061050461182c565b348015610662575f5ffd5b506103e5610671366004615581565b505f1990565b348015610682575f5ffd5b50610504610691366004615581565b611886565b3480156106a1575f5ffd5b5061043f6118e2565b3480156106b5575f5ffd5b506103e56106c43660046151db565b611921565b6105046106d736600461559c565b611972565b3480156106e7575f5ffd5b506103e561198d565b3480156106fb575f5ffd5b5061074b61070a366004615581565b6001600160a01b03165f9081527f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af9066020526040902080546001909101549091565b604080519283526020830191909152016103ef565b34801561076b575f5ffd5b507fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff166104b6565b3480156107a1575f5ffd5b506105046107b0366004615230565b6119bb565b3480156107c0575f5ffd5b507f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af905546103e5565b3480156107f3575f5ffd5b506103e5610802366004615553565b611a46565b348015610812575f5ffd5b506103e5610821366004615581565b6001600160a01b03165f9081527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00602052604090205490565b348015610865575f5ffd5b5061050461087436600461563a565b611b27565b348015610884575f5ffd5b507f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af901546103e5565b3480156108b7575f5ffd5b506105046108c6366004615581565b6120a8565b3480156108d6575f5ffd5b506103e56108e53660046156a8565b612219565b3480156108f5575f5ffd5b506103e56109043660046156e7565b612275565b348015610914575f5ffd5b506105046122cf565b348015610928575f5ffd5b506105046109373660046151db565b612327565b348015610947575f5ffd5b50610504610956366004615718565b6123fa565b348015610966575f5ffd5b5061043f612454565b34801561097a575f5ffd5b506103e5610989366004615553565b61247b565b348015610999575f5ffd5b506105046109a83660046151db565b61255e565b3480156109b8575f5ffd5b5061046b612672565b3480156109cc575f5ffd5b506103e56109db3660046151db565b6126c3565b3480156109eb575f5ffd5b506104b66109fa366004615206565b61270a565b348015610a0a575f5ffd5b507f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af903546103e5565b348015610a3d575f5ffd5b507f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af902546103e5565b348015610a70575f5ffd5b5061046b6040518060400160405280600581526020017f352e302e3000000000000000000000000000000000000000000000000000000081525081565b348015610ab8575f5ffd5b506103e5610ac73660046156a8565b612717565b348015610ad7575f5ffd5b506103e5610ae63660046151db565b6127b4565b348015610af6575f5ffd5b506103e5610b053660046156a8565b612805565b348015610b15575f5ffd5b506103e5610b243660046156e7565b612840565b348015610b34575f5ffd5b507fdd3fd67aef415aded9493b31ad20a02d2991d4bb2760431cc729821271eaea01546001600160a01b031661043f565b348015610b70575f5ffd5b506103e5610b7f3660046151db565b61289a565b348015610b8f575f5ffd5b506103e5610b9e3660046151db565b6128a5565b348015610bae575f5ffd5b506103e5610bbd366004615581565b6128ec565b348015610bcd575f5ffd5b507f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af904546103e5565b348015610c00575f5ffd5b506104b6610c0f366004615581565b6001600160a01b03165f9081527f2bbdf87c296f0fc445d947563c77d7b805fc738a2e220084769a264d45deaf00602052604090205460ff1690565b348015610c56575f5ffd5b506103e5610c65366004615581565b61292d565b348015610c75575f5ffd5b506104b6610c84366004615744565b612969565b348015610c94575f5ffd5b506103e5610ca336600461577c565b6001600160a01b039182165f9081527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace016020908152604080832093909416825291909152205490565b348015610cf7575f5ffd5b50610504610d063660046151db565b612a79565b348015610d16575f5ffd5b506103e5610d253660046151db565b612bfe565b348015610d35575f5ffd5b50610504610d44366004615581565b612c49565b348015610d54575f5ffd5b5061046b610d633660046157a8565b612d1b565b7f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af90080545f9190610dbf7f0773e532dfede91f04b12a73d3d2acd361424f41f76b4fb79f090161e36b4e00546001600160a01b031690565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa158015610e1c573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e409190615800565b610e4a9190615844565b91505090565b5f7f4e0114f5bb788bf295d0ab17f602045fbe9841605d1e05a2674fbfa584e947005b546001600160a01b0316919050565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0380546060917f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0091610ed390615857565b80601f0160208091040260200160405190810160405280929190818152602001828054610eff90615857565b8015610f4a5780601f10610f2157610100808354040283529160200191610f4a565b820191905f5260205f20905b815481529060010190602001808311610f2d57829003601f168201915b505050505091505090565b5f610f60825f612eef565b92915050565b5f33610f73818585612f46565b5060019392505050565b5f5f610fb9610fb37f0773e532dfede91f04b12a73d3d2acd361424f41f76b4fb79f090161e36b4e00546001600160a01b031690565b84612f53565b9050610fcd610fc88285615844565b612f61565b9392505050565b610fe9335f356001600160e01b031916612969565b6110295760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b60448201526064015b60405180910390fd5b61106b6040518060800160405280856001600160a01b03168152602001848152602001838152602001600180811115611064576110646158a8565b9052612f6d565b505050565b611085335f356001600160e01b031916612969565b6110c05760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606401611020565b6001600160a01b0383165f9081527f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af9066020526040902060018101547f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af900919015801590611130575080600101548411155b611166576040517f01e3468e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805415801590611177575080548311155b6111ad576040517f3b83271300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83816001015f8282546111c091906158d5565b90915550508054839082905f906111d89084906158d5565b9250508190555082826003015f8282546111f291906158d5565b909155505060408051858152602081018590526001600160a01b038716917f55ec94ca0f01023d07c5752a75f44048cfbdb0e4cfedf5e7eacecf21fcde3587910160405180910390a26112463086866130ef565b5050505050565b5f611256613163565b805490915060ff68010000000000000000820416159067ffffffffffffffff165f811580156112825750825b90505f8267ffffffffffffffff16600114801561129e5750303b155b9050811580156112ac575080155b156112e3576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84547fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000016600117855583156113445784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff16680100000000000000001785555b6113508989898961318b565b83156113b15784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b505050505050505050565b60606113d3335f356001600160e01b031916612969565b61140e5760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606401611020565b85848114801561141d57508483145b6114695760405162461bcd60e51b815260206004820152601860248201527f4172726179206c656e67746873206d757374206d6174636800000000000000006044820152606401611020565b8067ffffffffffffffff81111561148257611482615262565b6040519080825280602002602001820160405280156114b557816020015b60608152602001906001900390816114a05790505b5091505f5b81811015611721575f8787838181106114d5576114d56158e8565b90506020028101906114e79190615915565b6114f091615976565b90506115237fdd3fd67aef415aded9493b31ad20a02d2991d4bb2760431cc729821271eaea01546001600160a01b031690565b6001600160a01b031663b7009613338c8c86818110611544576115446158e8565b90506020020160208101906115599190615581565b6040516001600160e01b031960e085901b811682526001600160a01b0393841660048301529290911660248201529084166044820152606401602060405180830381865afa1580156115ad573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115d191906159ac565b8a8a848181106115e3576115e36158e8565b90506020020160208101906115f89190615581565b82909161164c576040517ffb5630260000000000000000000000000000000000000000000000000000000081526001600160a01b0390921660048301526001600160e01b0319166024820152604401611020565b50506116fb888884818110611663576116636158e8565b90506020028101906116759190615915565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152508a92508991508690508181106116bd576116bd6158e8565b905060200201358c8c868181106116d6576116d66158e8565b90506020020160208101906116eb9190615581565b6001600160a01b031691906131df565b84838151811061170d5761170d6158e8565b6020908102919091010152506001016114ba565b50509695505050505050565b5f3361173a85828561328e565b61174585858561333c565b506001949350505050565b5f807f0773e532dfede91f04b12a73d3d2acd361424f41f76b4fb79f090161e36b4e0090505f8154610e4a919074010000000000000000000000000000000000000000900460ff166159c7565b6117b2335f356001600160e01b031916612969565b6117ed5760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606401611020565b6118286118217f0773e532dfede91f04b12a73d3d2acd361424f41f76b4fb79f090161e36b4e00546001600160a01b031690565b83836133cb565b5050565b611841335f356001600160e01b031916612969565b61187c5760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606401611020565b6118846134e4565b565b61189b335f356001600160e01b031916612969565b6118d65760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606401611020565b6118df81613574565b50565b5f61191c6119177f0773e532dfede91f04b12a73d3d2acd361424f41f76b4fb79f090161e36b4e00546001600160a01b031690565b613618565b905090565b5f5f61192c83610f55565b90506119686119627f0773e532dfede91f04b12a73d3d2acd361424f41f76b4fb79f090161e36b4e00546001600160a01b031690565b826136a7565b610fcd90826158d5565b61197a6136b5565b6119838261375c565b61182882826137ac565b5f6119966138ad565b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc90565b6119d0335f356001600160e01b031916612969565b611a0b5760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606401611020565b61106b6040518060800160405280856001600160a01b031681526020018481526020018381526020015f6001811115611064576110646158a8565b5f611a4f61390f565b611a5761396b565b5f197f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af905547f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af9009080861015611ae1576040517fc42971700000000000000000000000000000000000000000000000000000000081526004810187905260248101829052604401611020565b5f611aeb87612bfe565b9050611af9338789846139ec565b9350505050610f6060017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b611b2f61390f565b611b44335f356001600160e01b031916612969565b611b7f5760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606401611020565b611b8761396b565b5f8311611bc0576040517f840c364a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038416611c00576040517fa05ff47e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038516611c40576040517feb32d3bf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f611c727f0773e532dfede91f04b12a73d3d2acd361424f41f76b4fb79f090161e36b4e00546001600160a01b031690565b90505f611c7e85610f55565b90505f611c8b8383613aa4565b90505f611c9882846158d5565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529091505f906001600160a01b038616906370a0823190602401602060405180830381865afa158015611cf8573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611d1c9190615800565b905083811015611d58576040517f3b83271300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b305f9081527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0060205260409020547f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0254611dbc6001600160a01b0388168c866130ef565b8b6001600160a01b0316636b5fe49d8e308a8e898f8f6040518863ffffffff1660e01b8152600401611df497969594939291906159e0565b5f604051808303815f87803b158015611e0b575f5ffd5b505af1158015611e1d573d5f5f3e3d5ffd5b5050305f9081527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0060205260409020549150611e5b90508b84615844565b811015611e94576040517f7cabe4bc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50611e9f308b613ab2565b611ea98a826158d5565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace025414611f02576040517f596a843700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f906001600160a01b038916906370a0823190602401602060405180830381865afa158015611f5f573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f839190615800565b905080611f9088866158d5565b1115611fc8576040517f19c17f2f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505f611fd388613618565b90505f86118015611fec57506001600160a01b03811615155b15612005576120056001600160a01b03891682886130ef565b8b6001600160a01b03168d6001600160a01b03168f6001600160a01b03167f98ad0da4de20359d393d1dfaa8f15da86ac4e45a9108ab5582f871ee281a0f948e898b604051612067939291909283526020830191909152604082015260600190565b60405180910390a450505050505050506120a060017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b505050505050565b7fdd3fd67aef415aded9493b31ad20a02d2991d4bb2760431cc729821271eaea0080546001600160a01b0316331480612178575060018101546040517fb70096130000000000000000000000000000000000000000000000000000000081523360048201523060248201525f356001600160e01b03191660448201526001600160a01b039091169063b700961390606401602060405180830381865afa158015612154573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061217891906159ac565b6121b35760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606401611020565b6001810180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03841690811790915560405133907fa3396fd7f6e0a21b50e5089d2da70d5ac0a3bbbd1f617a93f134b76389980198905f90a35050565b5f61222261390f565b61226d6040518060800160405280868152602001856001600160a01b03168152602001846001600160a01b031681526020015f6001811115612266576122666158a8565b9052613aff565b949350505050565b5f61227e61390f565b5f612289858561247b565b90508281111561226d576040517f9bab65290000000000000000000000000000000000000000000000000000000081526004810182905260248101849052604401611020565b6122e4335f356001600160e01b031916612969565b61231f5760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606401611020565b611884613d07565b61233c335f356001600160e01b031916612969565b6123775760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606401611020565b7f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af90554604080519182526020820183905280517f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af900927f5fb4589fcdfab8bd40d9776abc10876bb1cb02c0edab28d05cc42869b40e032992908290030190a160050155565b61240f335f356001600160e01b031916612969565b61244a5760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606401611020565b6118288282613d80565b5f7fdd3fd67aef415aded9493b31ad20a02d2991d4bb2760431cc729821271eaea00610e73565b5f61248461390f565b61248c61396b565b5f195f612498856127b4565b7f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af905549091507f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af9009080831015612523576040517fc42971700000000000000000000000000000000000000000000000000000000081526004810184905260248101829052604401611020565b61252f3387858a6139ec565b509092505050610f6060017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b612573335f356001600160e01b031916612969565b6125ae5760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606401611020565b67016345785d8a000081106125ef576040517f5aede91d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af90454604080519182526020820183905280517f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af900927f5b1f8430a1675242d4a0bdb976ee1c8740d114671db54660aba42fb46293e5dd92908290030190a160040155565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0480546060917f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0091610ed390615857565b5f5f6126ce83610f55565b90506119686127047f0773e532dfede91f04b12a73d3d2acd361424f41f76b4fb79f090161e36b4e00546001600160a01b031690565b82613aa4565b5f33610f7381858561333c565b5f61272061390f565b612735335f356001600160e01b031916612969565b6127705760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606401611020565b61226d6040518060800160405280868152602001856001600160a01b03168152602001846001600160a01b03168152602001600180811115612266576122666158a8565b5f5f6127bf83613eb7565b90506127fb6127f57f0773e532dfede91f04b12a73d3d2acd361424f41f76b4fb79f090161e36b4e00546001600160a01b031690565b82613ec3565b610fcd9082615844565b5f61280e61390f565b6040517f797f246a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f61284961390f565b5f6128548585611a46565b90508281101561226d576040517fb305bf640000000000000000000000000000000000000000000000000000000081526004810182905260248101849052604401611020565b5f610f60825f613ed1565b5f5f6128b083610f55565b90506119686128e67f0773e532dfede91f04b12a73d3d2acd361424f41f76b4fb79f090161e36b4e00546001600160a01b031690565b82613f1f565b6001600160a01b0381165f9081527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace006020526040812054610f60905f612eef565b6001600160a01b0381165f9081527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace006020526040812054610f60565b7fdd3fd67aef415aded9493b31ad20a02d2991d4bb2760431cc729821271eaea01545f907fdd3fd67aef415aded9493b31ad20a02d2991d4bb2760431cc729821271eaea00906001600160a01b03168015801590612a5957506040517fb70096130000000000000000000000000000000000000000000000000000000081526001600160a01b0386811660048301523060248301526001600160e01b03198616604483015282169063b700961390606401602060405180830381865afa158015612a35573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612a5991906159ac565b80612a70575081546001600160a01b038681169116145b95945050505050565b612a8e335f356001600160e01b031916612969565b612ac95760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606401611020565b7f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af901547f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af900904311612b45576040517f95628bbc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805460408051918252602082018490527f06829c36c32a24a199e4c4c18e4cf08af24d8301c3e4e500c08ae1dbc28498fe910160405180910390a18181555f612bc7670de0b6b3a7640000612bb87f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace025490565b612bc0610d68565b9190613f2d565b90505f612bd8836002015483613fdd565b90508260040154811115612bee57612bee613d07565b5060028201554360019091015550565b5f5f612c3a612c347f0773e532dfede91f04b12a73d3d2acd361424f41f76b4fb79f090161e36b4e00546001600160a01b031690565b84614024565b9050610fcd610b7f82856158d5565b612c5e335f356001600160e01b031916612969565b612c995760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606401611020565b7fdd3fd67aef415aded9493b31ad20a02d2991d4bb2760431cc729821271eaea0080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038316908117825560405133907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b6060612d32335f356001600160e01b031916612969565b612d6d5760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606401611020565b5f612d788486615976565b9050612dab7fdd3fd67aef415aded9493b31ad20a02d2991d4bb2760431cc729821271eaea01546001600160a01b031690565b6040517fb70096130000000000000000000000000000000000000000000000000000000081523360048201526001600160a01b0388811660248301526001600160e01b031984166044830152919091169063b700961390606401602060405180830381865afa158015612e20573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612e4491906159ac565b86829091612e99576040517ffb5630260000000000000000000000000000000000000000000000000000000081526001600160a01b0390921660048301526001600160e01b0319166024820152604401611020565b5050612ee585858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525050506001600160a01b038916919050856131df565b9695505050505050565b5f610fcd612efb610d68565b612f06906001615844565b612f115f600a615b2f565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0254612f3d9190615844565b85919085614031565b61106b8383836001614073565b5f610fcd838360018061419b565b5f610f60826001613ed1565b80516001600160a01b03165f9081527f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af9066020526040902060018101547f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af900919015801590612fe257508060010154836020015111155b613018576040517f01e3468e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80541580159061302d57508054604084015111155b613063576040517f3b83271300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8260200151816001015f82825461307a91906158d5565b90915550506040830151815482905f906130959084906158d5565b909155505060408301516003830180545f906130b29084906158d5565b925050819055506130d4835f01518460200151856040015186606001516142d3565b61106b835f01518460400151856020015186606001516143d9565b6040516001600160a01b0383811660248301526044820183905261106b91859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506144cc565b5f807ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00610f60565b613193614551565b61319d828261458f565b6131a6846145a1565b6131b0835f6145b2565b6131b86145c4565b6131c15f6145cc565b6131c96145dd565b6131d16145ed565b6131d96145fd565b50505050565b606081471015613224576040517fcf47918100000000000000000000000000000000000000000000000000000000815247600482015260248101839052604401611020565b5f5f856001600160a01b0316848660405161323f9190615b3d565b5f6040518083038185875af1925050503d805f8114613279576040519150601f19603f3d011682016040523d82523d5f602084013e61327e565b606091505b5091509150612ee5868383614654565b6001600160a01b038381165f9081527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0160209081526040808320938616835292905220545f198110156131d9578181101561332e576040517ffb8f41b20000000000000000000000000000000000000000000000000000000081526001600160a01b03841660048201526024810182905260448101839052606401611020565b6131d984848484035f614073565b6001600160a01b03831661337e576040517f96c6fd1e0000000000000000000000000000000000000000000000000000000081525f6004820152602401611020565b6001600160a01b0382166133c0576040517fec442f050000000000000000000000000000000000000000000000000000000081525f6004820152602401611020565b61106b8383836146c9565b815f03613404576040517fcbca5aa200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0381165f9081527f2bbdf87c296f0fc445d947563c77d7b805fc738a2e220084769a264d45deaf00602052604090205460ff16613474576040517f5ed3324c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6134886001600160a01b03841682846130ef565b806001600160a01b0316836001600160a01b0316336001600160a01b03167f92b6694567ccb3e850077b2848795b0dc9d5485503ac401c32f10a01d0e12cfc856040516134d791815260200190565b60405180910390a4505050565b6134ec6146dc565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001681557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a150565b7f4e0114f5bb788bf295d0ab17f602045fbe9841605d1e05a2674fbfa584e947005f61359e610e50565b82547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038581169182178555604080519184168252602082019290925291925033917feb7962da2115819e0ac9a926e8d3a292bc532effcbdf8d7cc3e60cc6eccca9a4910160405180910390a2505050565b5f5f613622610e50565b6040517f5d9c4f0f0000000000000000000000000000000000000000000000000000000081526001600160a01b03858116600483015291925090821690635d9c4f0f90602401602060405180830381865afa158015613683573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610fcd9190615b53565b5f610fcd838360015f61419b565b306001600160a01b037f0000000000000000000000005f0d2ae761a5eed6d7106771db846aa67be153f616148061372557507f0000000000000000000000005f0d2ae761a5eed6d7106771db846aa67be153f66001600160a01b0316613719614737565b6001600160a01b031614155b15611884576040517fe07c8dba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613771335f356001600160e01b031916612969565b6118df5760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606401611020565b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015613806575060408051601f3d908101601f1916820190925261380391810190615800565b60015b613847576040517f4c9c8ce30000000000000000000000000000000000000000000000000000000081526001600160a01b0383166004820152602401611020565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc81146138a3576040517faa1d49a400000000000000000000000000000000000000000000000000000000815260048101829052602401611020565b61106b838361475e565b306001600160a01b037f0000000000000000000000005f0d2ae761a5eed6d7106771db846aa67be153f61614611884576040517fe07c8dba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff1615611884576040517fd93c066500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0080547ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016139e6576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60029055565b5f613a1e7f0773e532dfede91f04b12a73d3d2acd361424f41f76b4fb79f090161e36b4e00546001600160a01b031690565b90505f613a2b8285614024565b90505f613a3783613618565b9050613a45878787876147b3565b5f82118015613a5c57506001600160a01b03811615155b15613a7557613a756001600160a01b03841682846130ef565b50505050505050565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b5f610fcd838360035f61419b565b6001600160a01b038216613af4576040517f96c6fd1e0000000000000000000000000000000000000000000000000000000081525f6004820152602401611020565b611828825f836146c9565b80515f90613b39576040517f840c364a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408201516001600160a01b03163314613b7f576040517fe7fe5cf400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81516040808401516001600160a01b03165f9081527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0060205220541015613bf2576040517f3999656700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f613bff835f0151610f55565b9050613c1d8360200151846040015183865f01518760600151614855565b604083015183517f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af90091613c5191309061333c565b81816003015f828254613c649190615844565b90915550506040805180820182526020808701516001600160a01b03165f9081526006850190915291909120548190613c9e908590615844565b815285516020878101516001600160a01b03165f9081526006860182526040902060010154920191613cd09190615844565b90526020948501516001600160a01b03165f9081526006909201855260408220815181559401516001909401939093555090919050565b613d0f61390f565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011781557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25833613556565b7f2bbdf87c296f0fc445d947563c77d7b805fc738a2e220084769a264d45deaf006001600160a01b038316613de1576040517f9fabe1c100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0383165f9081526020829052604090205482151560ff909116151503613e3a576040517faaed924400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0383165f818152602083815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016861515908117909155915191825233917fd9c6c3eabe38e3b9a606a66358d8f225489216a59eeba66facefb7d916635266910160405180910390a3505050565b5f610f60826001612eef565b5f610fcd83835f600161419b565b5f610fcd613ee082600a615b2f565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0254613f0c9190615844565b613f14610d68565b612f3d906001615844565b5f610fcd838360025f61419b565b5f5f5f613f3a868661492f565b91509150815f03613f5e57838181613f5457613f54615b6e565b0492505050610fcd565b818411613f7557613f75600385150260111861494b565b5f848688095f868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010185841190960395909502919093039390930492909217029150509392505050565b5f825f03613fec57505f610f60565b5f83831161400357613ffe83856158d5565b61400d565b61400d84846158d5565b905061226d81670de0b6b3a7640000866001614031565b5f610fcd83835f5f61419b565b5f61405e61403e8361495c565b801561405957505f848061405457614054615b6e565b868809115b151590565b614069868686613f2d565b612a709190615844565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace006001600160a01b0385166140d6576040517fe602df050000000000000000000000000000000000000000000000000000000081525f6004820152602401611020565b6001600160a01b038416614118576040517f94280d620000000000000000000000000000000000000000000000000000000081525f6004820152602401611020565b6001600160a01b038086165f9081526001830160209081526040808320938816835292905220839055811561124657836001600160a01b0316856001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258560405161418c91815260200190565b60405180910390a35050505050565b5f5f6141a5610e50565b90506001600160a01b0381166141f4576040517f2414b2d50000000000000000000000000000000000000000000000000000000081526001600160e01b03195f35166004820152602401611020565b821561428a576040517f4cfd82050000000000000000000000000000000000000000000000000000000081526001600160a01b03821690634cfd82059061424390899089908990600401615b9b565b602060405180830381865afa15801561425e573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906142829190615800565b91505061226d565b6040517fed5293050000000000000000000000000000000000000000000000000000000081526001600160a01b0382169063ed5293059061424390899089908990600401615b9b565b5f8160018111156142e6576142e66158a8565b036143355760408051848152602081018490526001600160a01b038616917f1165aa98d42fbaef9bacc273d7b5cca8edc94909519f8f949ec33562963c87e491015b60405180910390a26131d9565b6001816001811115614349576143496158a8565b0361438f5760408051848152602081018490526001600160a01b038616917f908b1a496603d6db727346172db92bbb94fb4434f93048b25a25c425d426f5829101614328565b8060018111156143a1576143a16158a8565b6040517f9caf260e00000000000000000000000000000000000000000000000000000000815260ff9091166004820152602401611020565b5f61440b7f0773e532dfede91f04b12a73d3d2acd361424f41f76b4fb79f090161e36b4e00546001600160a01b031690565b90505f80836001811115614421576144216158a8565b036144375761443082866136a7565b905061446c565b600183600181111561444b5761444b6158a8565b0361445a576144308286613f1f565b8260018111156143a1576143a16158a8565b5f61447782876158d5565b90505f61448384613618565b9050614492308930858a614988565b5f831180156144a957506001600160a01b03811615155b156144c2576144c26001600160a01b03851682856130ef565b5050505050505050565b5f5f60205f8451602086015f885af1806144eb576040513d5f823e3d81fd5b50505f513d9150811561450257806001141561450f565b6001600160a01b0384163b155b156131d9576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401611020565b614559614a58565b611884576040517fd7e6bcf800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b614597614551565b6118288282614a76565b6145a9614551565b6118df81614ad9565b6145ba614551565b6118288282614b9d565b611884614551565b6145d4614551565b6118df81614c8d565b6145e5614551565b6118846145c4565b6145f5614551565b611884614d29565b614605614551565b662386f26fc100007f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af904555f7f5c514b81e93a4e64ed3b3d78d8355319d5f0f527b3964e825d59f3a9d74af90555565b6060826146695761466482614d31565b610fcd565b815115801561468057506001600160a01b0384163b155b156146c2576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401611020565b5080610fcd565b6146d161390f565b61106b838383614d72565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff16611884576040517f8dfc202b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc610e73565b61476782614ec9565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a28051156147ab5761106b8282614f70565b611828614fd9565b6147ef6147e77f0773e532dfede91f04b12a73d3d2acd361424f41f76b4fb79f090161e36b4e00546001600160a01b031690565b853085615011565b6147f9838261504a565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d78484604051614847929190918252602082015260400190565b60405180910390a350505050565b5f816001811115614868576148686158a8565b036148c857836001600160a01b0316856001600160a01b03167f6d109ae63c8098a8b0ae2c1c6195469c03cbee2f45061230650bc1b31f3891db85856040516148bb929190918252602082015260400190565b60405180910390a3611246565b60018160018111156148dc576148dc6158a8565b0361438f57836001600160a01b0316856001600160a01b03167fd46caa0122af654d133b7a1fe5644d9594644f64c366834a6ee96ef23c3871fb85856040516148bb929190918252602082015260400190565b5f805f1983850993909202808410938190039390930393915050565b634e487b715f52806020526024601cfd5b5f6002826003811115614971576149716158a8565b61497b9190615bf5565b60ff166001149050919050565b826001600160a01b0316856001600160a01b0316146149ac576149ac83868361328e565b6149b68382613ab2565b6149f16149ea7f0773e532dfede91f04b12a73d3d2acd361424f41f76b4fb79f090161e36b4e00546001600160a01b031690565b85846130ef565b826001600160a01b0316846001600160a01b0316866001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db8585604051614a49929190918252602082015260400190565b60405180910390a45050505050565b5f614a61613163565b5468010000000000000000900460ff16919050565b614a7e614551565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace007f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace03614aca8482615c7f565b50600481016131d98382615c7f565b614ae1614551565b7f0773e532dfede91f04b12a73d3d2acd361424f41f76b4fb79f090161e36b4e005f80614b0d84615097565b9150915081614b1d576012614b1f565b805b83547fffffffffffffffffffffff000000000000000000000000000000000000000000167401000000000000000000000000000000000000000060ff92909216919091027fffffffffffffffffffffffff000000000000000000000000000000000000000016176001600160a01b0394909416939093179091555050565b614ba5614551565b7fdd3fd67aef415aded9493b31ad20a02d2991d4bb2760431cc729821271eaea0080547fffffffffffffffffffffffff00000000000000000000000000000000000000009081166001600160a01b0385811691821784557fdd3fd67aef415aded9493b31ad20a02d2991d4bb2760431cc729821271eaea0180549093169085161790915560405133907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a36040516001600160a01b0383169033907fa3396fd7f6e0a21b50e5089d2da70d5ac0a3bbbd1f617a93f134b76389980198905f90a3505050565b614c95614551565b7f4e0114f5bb788bf295d0ab17f602045fbe9841605d1e05a2674fbfa584e9470080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081178255604080515f81526020810192909252805133927feb7962da2115819e0ac9a926e8d3a292bc532effcbdf8d7cc3e60cc6eccca9a492908290030190a25050565b613a7e614551565b805115614d4057805160208201fd5b6040517fd6bda27500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace006001600160a01b038416614dbf5781816002015f828254614db49190615844565b90915550614e489050565b6001600160a01b0384165f9081526020829052604090205482811015614e2a576040517fe450d38c0000000000000000000000000000000000000000000000000000000081526001600160a01b03861660048201526024810182905260448101849052606401611020565b6001600160a01b0385165f9081526020839052604090209083900390555b6001600160a01b038316614e66576002810180548390039055614e84565b6001600160a01b0383165f9081526020829052604090208054830190555b826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161484791815260200190565b806001600160a01b03163b5f03614f17576040517f4c9c8ce30000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602401611020565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b60605f5f846001600160a01b031684604051614f8c9190615b3d565b5f60405180830381855af49150503d805f8114614fc4576040519150601f19603f3d011682016040523d82523d5f602084013e614fc9565b606091505b5091509150612a70858383614654565b3415611884576040517fb398979f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b0384811660248301528381166044830152606482018390526131d99186918216906323b872dd9060840161311c565b6001600160a01b03821661508c576040517fec442f050000000000000000000000000000000000000000000000000000000081525f6004820152602401611020565b6118285f83836146c9565b60408051600481526024810182526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f313ce5670000000000000000000000000000000000000000000000000000000017905290515f918291829182916001600160a01b0387169161510b91615b3d565b5f60405180830381855afa9150503d805f8114615143576040519150601f19603f3d011682016040523d82523d5f602084013e615148565b606091505b509150915081801561515c57506020815110155b1561518f575f818060200190518101906151769190615800565b905060ff811161518d576001969095509350505050565b505b505f9485945092505050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f610fcd602083018461519b565b5f602082840312156151eb575f5ffd5b5035919050565b6001600160a01b03811681146118df575f5ffd5b5f5f60408385031215615217575f5ffd5b8235615222816151f2565b946020939093013593505050565b5f5f5f60608486031215615242575f5ffd5b833561524d816151f2565b95602085013595506040909401359392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f5f67ffffffffffffffff8411156152a9576152a9615262565b50604051601f19601f85018116603f0116810181811067ffffffffffffffff821117156152d8576152d8615262565b6040528381529050808284018510156152ef575f5ffd5b838360208301375f60208583010152509392505050565b5f82601f830112615315575f5ffd5b610fcd8383356020850161528f565b5f5f5f5f60808587031215615337575f5ffd5b8435615342816151f2565b93506020850135615352816151f2565b9250604085013567ffffffffffffffff81111561536d575f5ffd5b61537987828801615306565b925050606085013567ffffffffffffffff811115615395575f5ffd5b6153a187828801615306565b91505092959194509250565b5f5f83601f8401126153bd575f5ffd5b50813567ffffffffffffffff8111156153d4575f5ffd5b6020830191508360208260051b85010111156153ee575f5ffd5b9250929050565b5f5f5f5f5f5f6060878903121561540a575f5ffd5b863567ffffffffffffffff811115615420575f5ffd5b61542c89828a016153ad565b909750955050602087013567ffffffffffffffff81111561544b575f5ffd5b61545789828a016153ad565b909550935050604087013567ffffffffffffffff811115615476575f5ffd5b61548289828a016153ad565b979a9699509497509295939492505050565b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b82811015615509577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08786030184526154f485835161519b565b945060209384019391909101906001016154ba565b50929695505050505050565b5f5f5f60608486031215615527575f5ffd5b8335615532816151f2565b92506020840135615542816151f2565b929592945050506040919091013590565b5f5f60408385031215615564575f5ffd5b823591506020830135615576816151f2565b809150509250929050565b5f60208284031215615591575f5ffd5b8135610fcd816151f2565b5f5f604083850312156155ad575f5ffd5b82356155b8816151f2565b9150602083013567ffffffffffffffff8111156155d3575f5ffd5b8301601f810185136155e3575f5ffd5b6155f28582356020840161528f565b9150509250929050565b5f5f83601f84011261560c575f5ffd5b50813567ffffffffffffffff811115615623575f5ffd5b6020830191508360208285010111156153ee575f5ffd5b5f5f5f5f5f5f60a0878903121561564f575f5ffd5b863561565a816151f2565b9550602087013561566a816151f2565b9450604087013561567a816151f2565b935060608701359250608087013567ffffffffffffffff81111561569c575f5ffd5b61548289828a016155fc565b5f5f5f606084860312156156ba575f5ffd5b8335925060208401356156cc816151f2565b915060408401356156dc816151f2565b809150509250925092565b5f5f5f606084860312156156f9575f5ffd5b833592506020840135615542816151f2565b80151581146118df575f5ffd5b5f5f60408385031215615729575f5ffd5b8235615734816151f2565b915060208301356155768161570b565b5f5f60408385031215615755575f5ffd5b8235615760816151f2565b915060208301356001600160e01b031981168114615576575f5ffd5b5f5f6040838503121561578d575f5ffd5b8235615798816151f2565b91506020830135615576816151f2565b5f5f5f5f606085870312156157bb575f5ffd5b84356157c6816151f2565b9350602085013567ffffffffffffffff8111156157e1575f5ffd5b6157ed878288016155fc565b9598909750949560400135949350505050565b5f60208284031215615810575f5ffd5b5051919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820180821115610f6057610f60615817565b600181811c9082168061586b57607f821691505b6020821081036158a2577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b50919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b81810381811115610f6057610f60615817565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f5f83357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112615948575f5ffd5b83018035915067ffffffffffffffff821115615962575f5ffd5b6020019150368190038213156153ee575f5ffd5b80356001600160e01b031981169060048410156159a5576001600160e01b0319808560040360031b1b82161691505b5092915050565b5f602082840312156159bc575f5ffd5b8151610fcd8161570b565b60ff8181168382160190811115610f6057610f60615817565b6001600160a01b03881681526001600160a01b03871660208201526001600160a01b038616604082015284606082015283608082015260c060a08201528160c0820152818360e08301375f81830160e090810191909152601f909201601f191601019695505050505050565b6001815b6001841115615a8757808504811115615a6b57615a6b615817565b6001841615615a7957908102905b60019390931c928002615a50565b935093915050565b5f82615a9d57506001610f60565b81615aa957505f610f60565b8160018114615abf5760028114615ac957615ae5565b6001915050610f60565b60ff841115615ada57615ada615817565b50506001821b610f60565b5060208310610133831016604e8410600b8410161715615b08575081810a610f60565b615b145f198484615a4c565b805f1904821115615b2757615b27615817565b029392505050565b5f610fcd60ff841683615a8f565b5f82518060208501845e5f920191825250919050565b5f60208284031215615b63575f5ffd5b8151610fcd816151f2565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b6001600160a01b0384168152602081018390526060810160048310615be7577f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b826040830152949350505050565b5f60ff831680615c2c577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b8060ff84160691505092915050565b601f82111561106b57805f5260205f20601f840160051c81016020851015615c605750805b601f840160051c820191505b81811015611246575f8155600101615c6c565b815167ffffffffffffffff811115615c9957615c99615262565b615cad81615ca78454615857565b84615c3b565b6020601f821160018114615cdf575f8315615cc85750848201515b5f19600385901b1c1916600184901b178455611246565b5f84815260208120601f198516915b82811015615d0e5787850151825560209485019460019092019101615cee565b5084821015615d2b57868401515f19600387901b60f8161c191681555b50505050600190811b0190555056fea2646970667358221220c77af930c048cc067948e17bd3ec8cf37d261dcd46a852d64d9267cf329b5db664736f6c634300081e0033
Deployed Bytecode Sourcemap
2052:38860:7:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;24481:228;;;;;;;;;;;;;:::i;:::-;;;160:25:37;;;148:2;133:18;24481:228:7;;;;;;;;22759:149;;;;;;;;;;-1:-1:-1;40451:31:7;22846:55;22759:149;;2391:128:2;;;;;;;;;;;;;:::i;:::-;;;-1:-1:-1;;;;;386:55:37;;;368:74;;356:2;341:18;2391:128:2;196:252:37;2697:144:9;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;7404:148:10:-;;;;;;;;;;-1:-1:-1;7404:148:10;;;;;:::i;:::-;;:::i;5114:186:9:-;;;;;;;;;;-1:-1:-1;5114:186:9;;;;;:::i;:::-;;:::i;:::-;;;1958:14:37;;1951:22;1933:41;;1921:2;1906:18;5114:186:9;1793:187:37;31048:207:7;;;;;;;;;;-1:-1:-1;31048:207:7;;;;;:::i;:::-;;:::i;14016:263::-;;;;;;;;;;-1:-1:-1;14016:263:7;;;;;:::i;:::-;;:::i;:::-;;3850:152:9;;;;;;;;;;-1:-1:-1;3981:14:9;;3850:152;;17896:818:7;;;;;;;;;;-1:-1:-1;17896:818:7;;;;;:::i;:::-;;:::i;6459:241::-;;;;;;;;;;-1:-1:-1;6459:241:7;;;;;:::i;:::-;;:::i;9633:822::-;;;;;;;;;;-1:-1:-1;9633:822:7;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;5892:244:9:-;;;;;;;;;;-1:-1:-1;5892:244:9;;;;;:::i;:::-;;:::i;6617:221:10:-;;;;;;;;;;;;;:::i;:::-;;;7583:4:37;7571:17;;;7553:36;;7541:2;7526:18;6617:221:10;7411:184:37;6873:153:10;;;;;;;;;;-1:-1:-1;4209:22:10;7010:8;-1:-1:-1;;;;;7010:8:10;6873:153;;11608:119:7;;;;;;;;;;-1:-1:-1;11608:119:7;;;;;:::i;:::-;;:::i;10838:66::-;;;;;;;;;;;;;:::i;7587:108:10:-;;;;;;;;;;-1:-1:-1;7587:108:10;;;;;:::i;:::-;-1:-1:-1;;;7671:17:10;7587:108;20388:136:7;;;;;;;;;;-1:-1:-1;20388:136:7;;;;;:::i;:::-;;:::i;20659:106::-;;;;;;;;;;;;;:::i;31463:211::-;;;;;;;;;;-1:-1:-1;31463:211:7;;;;;:::i;:::-;;:::i;3895:214:23:-;;;;;;:::i;:::-;;:::i;3442:134::-;;;;;;;;;;;;;:::i;22331:285:7:-;;;;;;;;;;-1:-1:-1;22331:285:7;;;;;:::i;:::-;-1:-1:-1;;;;;22550:21:7;22420:14;22550:21;;;:15;:21;;;;;:28;;22580;;;;;22550;;22331:285;;;;;9679:25:37;;;9735:2;9720:18;;9713:34;;;;9652:18;22331:285:7;9505:248:37;2496:145:12;;;;;;;;;;-1:-1:-1;1270:23:12;2625:9;;;2496:145;;13436:255:7;;;;;;;;;;-1:-1:-1;13436:255:7;;;;;:::i;:::-;;:::i;24077:125::-;;;;;;;;;;-1:-1:-1;24152:43:7;;24077:125;;25048:768;;;;;;;;;;-1:-1:-1;25048:768:7;;;;;:::i;:::-;;:::i;4035:171:9:-;;;;;;;;;;-1:-1:-1;4035:171:9;;;;;:::i;:::-;-1:-1:-1;;;;;4179:20:9;4100:7;4179:20;;;2064;4179;;;;;;;4035:171;14839:2691:7;;;;;;;;;;-1:-1:-1;14839:2691:7;;;;;:::i;:::-;;:::i;23053:125::-;;;;;;;;;;-1:-1:-1;23128:43:7;;23053:125;;3996:361:0;;;;;;;;;;-1:-1:-1;3996:361:0;;;;;:::i;:::-;;:::i;12118:274:7:-;;;;;;;;;;-1:-1:-1;12118:274:7;;;;;:::i;:::-;;:::i;28778:357::-;;;;;;;;;;-1:-1:-1;28778:357:7;;;;;:::i;:::-;;:::i;10621:62::-;;;;;;;;;;;;;:::i;21696:288::-;;;;;;;;;;-1:-1:-1;21696:288:7;;;;;:::i;:::-;;:::i;11190:149::-;;;;;;;;;;-1:-1:-1;11190:149:7;;;;;:::i;:::-;;:::i;3463:102:0:-;;;;;;;;;;;;;:::i;27279:756:7:-;;;;;;;;;;-1:-1:-1;27279:756:7;;;;;:::i;:::-;;:::i;21052:404::-;;;;;;;;;;-1:-1:-1;21052:404:7;;;;;:::i;:::-;;:::i;2954:148:9:-;;;;;;;;;;;;;:::i;32340:208:7:-;;;;;;;;;;-1:-1:-1;32340:208:7;;;;;:::i;:::-;;:::i;4401:178:9:-;;;;;;;;;;-1:-1:-1;4401:178:9;;;;;:::i;:::-;;:::i;23549:129:7:-;;;;;;;;;;-1:-1:-1;23626:45:7;;23549:129;;23295:127;;;;;;;;;;-1:-1:-1;23371:44:7;;23295:127;;1708:58:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;12808:303:7;;;;;;;;;;-1:-1:-1;12808:303:7;;;;;:::i;:::-;;:::i;30644:202::-;;;;;;;;;;-1:-1:-1;30644:202:7;;;;;:::i;:::-;;:::i;29291:142::-;;;;;;;;;;-1:-1:-1;29291:142:7;;;;;:::i;:::-;;:::i;26578:366::-;;;;;;;;;;-1:-1:-1;26578:366:7;;;;;:::i;:::-;;:::i;3694:112:0:-;;;;;;;;;;-1:-1:-1;3772:27:0;;-1:-1:-1;;;;;3772:27:0;3694:112;;7221:148:10;;;;;;;;;;-1:-1:-1;7221:148:10;;;;;:::i;:::-;;:::i;31900:216:7:-;;;;;;;;;;-1:-1:-1;31900:216:7;;;;;:::i;:::-;;:::i;7870:153:10:-;;;;;;;;;;-1:-1:-1;7870:153:10;;;;;:::i;:::-;;:::i;23827:131:7:-;;;;;;;;;;-1:-1:-1;23905:46:7;;23827:131;;3997:219:1;;;;;;;;;;-1:-1:-1;3997:219:1;;;;;:::i;:::-;-1:-1:-1;;;;;4180:29:1;4064:18;4180:29;;;6375:30;4180:29;;;;;;;;;3997:219;8058:112:10;;;;;;;;;;-1:-1:-1;8058:112:10;;;;;:::i;:::-;;:::i;3032:314:0:-;;;;;;;;;;-1:-1:-1;3032:314:0;;;;;:::i;:::-;;:::i;4612:195:9:-;;;;;;;;;;-1:-1:-1;4612:195:9;;;;;:::i;:::-;-1:-1:-1;;;;;4771:20:9;;;4692:7;4771:20;;;:13;:20;;;;;;;;:29;;;;;;;;;;;;;4612:195;19078:1103:7;;;;;;;;;;-1:-1:-1;19078:1103:7;;;;;:::i;:::-;;:::i;30246:204::-;;;;;;;;;;-1:-1:-1;30246:204:7;;;;;:::i;:::-;;:::i;4543:216:0:-;;;;;;;;;;-1:-1:-1;4543:216:0;;;;;:::i;:::-;;:::i;8721:449:7:-;;;;;;;;;;-1:-1:-1;8721:449:7;;;;;:::i;:::-;;:::i;24481:228::-;40451:31;24672:30;;24534:7;;40451:31;24636:7;4209:22:10;7010:8;-1:-1:-1;;;;;7010:8:10;;6873:153;24636:7:7;24629:40;;;;;24663:4;24629:40;;;368:74:37;-1:-1:-1;;;;;24629:25:7;;;;;;;341:18:37;;24629:40:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:73;;;;:::i;:::-;24622:80;;;24481:228;:::o;2391:128:2:-;2443:17;1539:23;2479:21;:33;-1:-1:-1;;;;;2479:33:2;;2391:128;-1:-1:-1;2391:128:2:o;2697:144:9:-;2827:7;2820:14;;2742:13;;2064:20;;2820:14;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2697:144;:::o;7404:148:10:-;7474:7;7500:45;7517:6;7525:19;7500:16;:45::i;:::-;7493:52;7404:148;-1:-1:-1;;7404:148:10:o;5114:186:9:-;5187:4;966:10:11;5241:31:9;966:10:11;5257:7:9;5266:5;5241:8;:31::i;:::-;-1:-1:-1;5289:4:9;;5114:186;-1:-1:-1;;;5114:186:9:o;31048:207:7:-;31127:7;31146:11;31160:36;31180:7;4209:22:10;7010:8;-1:-1:-1;;;;;7010:8:10;;6873:153;31180:7:7;31189:6;31160:19;:36::i;:::-;31146:50;-1:-1:-1;31213:35:7;31235:12;31146:50;31235:6;:12;:::i;:::-;31213:21;:35::i;:::-;31206:42;31048:207;-1:-1:-1;;;31048:207:7:o;14016:263::-;2703:33:0;2716:10;2728:7;;-1:-1:-1;;;;;;2728:7:0;2703:12;:33::i;:::-;2695:58;;;;-1:-1:-1;;;2695:58:0;;16016:2:37;2695:58:0;;;15998:21:37;16055:2;16035:18;;;16028:30;-1:-1:-1;;;16074:18:37;;;16067:42;16126:18;;2695:58:0;;;;;;;;;14185:87:7::1;14205:66;;;;;;;;14219:8;-1:-1:-1::0;;;;;14205:66:7::1;;;;;14229:6;14205:66;;;;14237:13;14205:66;;;;14252:18;14205:66:::0;::::1;;;;;;;:::i;:::-;::::0;;14185:19:::1;:87::i;:::-;14016:263:::0;;;:::o;17896:818::-;2703:33:0;2716:10;2728:7;;-1:-1:-1;;;;;;2728:7:0;2703:12;:33::i;:::-;2695:58;;;;-1:-1:-1;;;2695:58:0;;16016:2:37;2695:58:0;;;15998:21:37;16055:2;16035:18;;;16028:30;-1:-1:-1;;;16074:18:37;;;16067:42;16126:18;;2695:58:0;15814:336:37;2695:58:0;-1:-1:-1;;;;;18158:25:7;::::1;18057:30;18158:25:::0;;;:15;:25:::1;::::0;;;;18202:14:::1;::::0;::::1;::::0;40451:31;;18158:25;18202:19;;::::1;::::0;:47:::1;;;18235:7;:14;;;18225:6;:24;;18202:47;18194:86;;;;;;;;;;;;;;;;;18311:14:::0;;:19;;::::1;::::0;:54:::1;;-1:-1:-1::0;18351:14:7;;18334:31;::::1;;18311:54;18290:115;;;;;;;;;;;;;;;;;18434:6;18416:7;:14;;;:24;;;;;;;:::i;:::-;::::0;;;-1:-1:-1;;18450:31:7;;18468:13;;18450:7;;:14:::1;::::0;:31:::1;::::0;18468:13;;18450:31:::1;:::i;:::-;;;;;;;;18515:13;18491:1;:20;;;:37;;;;;;;:::i;:::-;::::0;;;-1:-1:-1;;18544:49:7::1;::::0;;9679:25:37;;;9735:2;9720:18;;9713:34;;;-1:-1:-1;;;;;18544:49:7;::::1;::::0;::::1;::::0;9652:18:37;18544:49:7::1;;;;;;;18655:52;18670:4;18690:8:::0;18700:6;18655:34:::1;:52::i;:::-;18047:667;;17896:818:::0;;;:::o;6459:241::-;4158:30:8;4191:26;:24;:26::i;:::-;4302:15;;4158:59;;-1:-1:-1;4302:15:8;;;;;4301:16;;4348:14;;4279:19;4724:16;;:34;;;;;4744:14;4724:34;4704:54;;4768:17;4788:11;:16;;4803:1;4788:16;:50;;;;-1:-1:-1;4816:4:8;4808:25;:30;4788:50;4768:70;;4854:12;4853:13;:30;;;;;4871:12;4870:13;4853:30;4849:91;;;4906:23;;;;;;;;;;;;;;4849:91;4949:18;;;;4966:1;4949:18;;;4977:67;;;;5011:22;;;;;;;;4977:67;6641:52:7::1;6662:6;6670;6678:5;6685:7;6641:20;:52::i;:::-;5068:14:8::0;5064:101;;;5098:23;;;;;;5140:14;;-1:-1:-1;16630:50:37;;5140:14:8;;16618:2:37;16603:18;5140:14:8;;;;;;;5064:101;4092:1079;;;;;6459:241:7;;;;:::o;9633:822::-;9812:22;2703:33:0;2716:10;2728:7;;-1:-1:-1;;;;;;2728:7:0;2703:12;:33::i;:::-;2695:58;;;;-1:-1:-1;;;2695:58:0;;16016:2:37;2695:58:0;;;15998:21:37;16055:2;16035:18;;;16028:30;-1:-1:-1;;;16074:18:37;;;16067:42;16126:18;;2695:58:0;15814:336:37;2695:58:0;9874:7:7;9919:28;;::::1;:60:::0;::::1;;;-1:-1:-1::0;9951:28:7;;::::1;9919:60;9898:131;;;::::0;-1:-1:-1;;;9898:131:7;;16893:2:37;9898:131:7::1;::::0;::::1;16875:21:37::0;16932:2;16912:18;;;16905:30;16971:26;16951:18;;;16944:54;17015:18;;9898:131:7::1;16691:348:37::0;9898:131:7::1;10061:13;10049:26;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;10039:36;;10090:9;10085:364;10105:13;10101:1;:17;10085:364;;;10139:18;10167:4;;10172:1;10167:7;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;10160:15;::::0;::::1;:::i;:::-;10139:36;;10214:11;3772:27:0::0;;-1:-1:-1;;;;;3772:27:0;;3694:112;10214:11:7::1;-1:-1:-1::0;;;;;10214:19:7::1;;10234:10;10246:7;;10254:1;10246:10;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;10214:56;::::0;-1:-1:-1;;;;;;10214:56:7::1;::::0;;;;;;;-1:-1:-1;;;;;18517:55:37;;;10214:56:7::1;::::0;::::1;18499:74:37::0;18609:55;;;;18589:18;;;18582:83;18701:79;;;18681:18;;;18674:107;18472:18;;10214:56:7::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;10321:7;;10329:1;10321:10;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;10333:11;10189:170;;;;;::::0;::::1;::::0;;-1:-1:-1;;;;;19232:55:37;;;10189:170:7::1;::::0;::::1;19214:74:37::0;-1:-1:-1;;;;;;19324:79:37;19304:18;;;19297:107;19187:18;;10189:170:7::1;19042:368:37::0;10189:170:7::1;;;10386:52;10419:4;;10424:1;10419:7;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;10386:52;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;::::0;;;;-1:-1:-1;10428:6:7;;-1:-1:-1;10428:6:7;;-1:-1:-1;10435:1:7;;-1:-1:-1;10428:9:7;;::::1;;;;;:::i;:::-;;;;;;;10386:7;;10394:1;10386:10;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;10386:32:7::1;::::0;:52;:32:::1;:52::i;:::-;10373:7;10381:1;10373:10;;;;;;;;:::i;:::-;;::::0;;::::1;::::0;;;;;:65;-1:-1:-1;10120:3:7::1;;10085:364;;;;9840:615;9633:822:::0;;;;;;;;:::o;5892:244:9:-;5979:4;966:10:11;6035:37:9;6051:4;966:10:11;6066:5:9;6035:15;:37::i;:::-;6082:26;6092:4;6098:2;6102:5;6082:9;:26::i;:::-;-1:-1:-1;6125:4:9;;5892:244;-1:-1:-1;;;;5892:244:9:o;6617:221:10:-;6709:5;;4209:22;6726:47;-1:-1:-1;13258:5:10;6790:21;;:41;;;:21;;;;;:41;:::i;11608:119:7:-;2703:33:0;2716:10;2728:7;;-1:-1:-1;;;;;;2728:7:0;2703:12;:33::i;:::-;2695:58;;;;-1:-1:-1;;;2695:58:0;;16016:2:37;2695:58:0;;;15998:21:37;16055:2;16035:18;;;16028:30;-1:-1:-1;;;16074:18:37;;;16067:42;16126:18;;2695:58:0;15814:336:37;2695:58:0;11687:33:7::1;11700:7;4209:22:10::0;7010:8;-1:-1:-1;;;;;7010:8:10;;6873:153;11700:7:7::1;11709:6;11717:2;11687:12;:33::i;:::-;11608:119:::0;;:::o;10838:66::-;2703:33:0;2716:10;2728:7;;-1:-1:-1;;;;;;2728:7:0;2703:12;:33::i;:::-;2695:58;;;;-1:-1:-1;;;2695:58:0;;16016:2:37;2695:58:0;;;15998:21:37;16055:2;16035:18;;;16028:30;-1:-1:-1;;;16074:18:37;;;16067:42;16126:18;;2695:58:0;15814:336:37;2695:58:0;10887:10:7::1;:8;:10::i;:::-;10838:66::o:0;20388:136::-;2703:33:0;2716:10;2728:7;;-1:-1:-1;;;;;;2728:7:0;2703:12;:33::i;:::-;2695:58;;;;-1:-1:-1;;;2695:58:0;;16016:2:37;2695:58:0;;;15998:21:37;16055:2;16035:18;;;16028:30;-1:-1:-1;;;16074:18:37;;;16067:42;16126:18;;2695:58:0;15814:336:37;2695:58:0;20483:34:7::1;20504:12;20483:20;:34::i;:::-;20388:136:::0;:::o;20659:106::-;20707:7;20733:25;20750:7;4209:22:10;7010:8;-1:-1:-1;;;;;7010:8:10;;6873:153;20750:7:7;20733:16;:25::i;:::-;20726:32;;20659:106;:::o;31463:211::-;31540:7;31559:14;31576:27;31596:6;31576:19;:27::i;:::-;31559:44;;31629:38;31651:7;4209:22:10;7010:8;-1:-1:-1;;;;;7010:8:10;;6873:153;31651:7:7;31660:6;31629:21;:38::i;:::-;31620:47;;:6;:47;:::i;3895:214:23:-;2544:13;:11;:13::i;:::-;4010:36:::1;4028:17;4010;:36::i;:::-;4056:46;4078:17;4097:4;4056:21;:46::i;3442:134::-:0;3511:7;2815:20;:18;:20::i;:::-;-1:-1:-1;811:66:21::1;3442:134:23::0;:::o;13436:255:7:-;2703:33:0;2716:10;2728:7;;-1:-1:-1;;;;;;2728:7:0;2703:12;:33::i;:::-;2695:58;;;;-1:-1:-1;;;2695:58:0;;16016:2:37;2695:58:0;;;15998:21:37;16055:2;16035:18;;;16028:30;-1:-1:-1;;;16074:18:37;;;16067:42;16126:18;;2695:58:0;15814:336:37;2695:58:0;13598:86:7::1;13618:65;;;;;;;;13632:8;-1:-1:-1::0;;;;;13618:65:7::1;;;;;13642:6;13618:65;;;;13650:13;13618:65;;;;13665:17;13618:65;;;;;;;;:::i;25048:768::-:0;25213:7;1979:19:12;:17;:19::i;:::-;3395:21:13::1;:19;:21::i;:::-;-1:-1:-1::0;;25509:18:7;;40451:31;;25542:32;;::::2;25538:140;;;25597:70;::::0;::::2;::::0;;::::2;::::0;::::2;9679:25:37::0;;;9720:18;;;9713:34;;;9652:18;;25597:70:7::2;9505:248:37::0;25538:140:7::2;25688:14;25705:22;25720:6;25705:14;:22::i;:::-;25688:39:::0;-1:-1:-1;25737:48:7::2;966:10:11::0;25760:8:7::2;25770:6;25778;25737:8;:48::i;:::-;25803:6:::0;-1:-1:-1;;;;3437:20:13::1;1949:1:::0;2532:30;4113:23;3860:283;14839:2691:7;1979:19:12;:17;:19::i;:::-;2703:33:0::1;2716:10;2728:7;;-1:-1:-1::0;;;;;;2728:7:0::1;2703:12;:33::i;:::-;2695:58;;;::::0;-1:-1:-1;;;2695:58:0;;16016:2:37;2695:58:0::1;::::0;::::1;15998:21:37::0;16055:2;16035:18;;;16028:30;-1:-1:-1;;;16074:18:37;;;16067:42;16126:18;;2695:58:0::1;15814:336:37::0;2695:58:0::1;3395:21:13::2;:19;:21::i;:::-;15138:1:7::3;15129:6;:10;15121:46;;;;;;;;;;;;;;;;;-1:-1:-1::0;;;;;15185:22:7;::::3;15177:64;;;;;;;;;;;;;;;;;-1:-1:-1::0;;;;;15259:22:7;::::3;15251:64;;;;;;;;;;;;;;;;;15326:13;15342:7;4209:22:10::0;7010:8;-1:-1:-1;;;;;7010:8:10;;6873:153;15342:7:7::3;15326:23;;15397:21;15421:23;15437:6;15421:15;:23::i;:::-;15397:47;;15454:11;15468:48;15495:5;15502:13;15468:26;:48::i;:::-;15454:62:::0;-1:-1:-1;15561:24:7::3;15588:19;15454:62:::0;15588:13;:19:::3;:::i;:::-;15689:38;::::0;;;;15721:4:::3;15689:38;::::0;::::3;368:74:37::0;15561:46:7;;-1:-1:-1;15666:20:7::3;::::0;-1:-1:-1;;;;;15689:23:7;::::3;::::0;::::3;::::0;341:18:37;;15689:38:7::3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;15666:61;;15761:13;15745:12;:29;;15737:68;;;;;;;;;;;;;;;;;15863:4;15816:26;4179:20:9::0;;;2064;4179;;;;;;3981:14;;15982:54:7::3;-1:-1:-1::0;;;;;15982:26:7;::::3;16009:8:::0;16019:16;15982:26:::3;:54::i;:::-;16140:8;-1:-1:-1::0;;;;;16119:52:7::3;;16185:9;16204:4;16211:5;16218:6;16226:16;16244:4;;16119:139;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1::0;;16393:4:7::3;16347:25;4179:20:9::0;;;2064;4179;;;;;;;-1:-1:-1;16442:27:7::3;::::0;-1:-1:-1;16463:6:7;16442:18;:27:::3;:::i;:::-;16421:17;:48;;16413:85;;;;;;;;;;;;;;;;;16269:240;16583:28;16597:4;16604:6;16583:5;:28::i;:::-;16865:26;16885:6:::0;16865:17;:26:::3;:::i;:::-;3981:14:9::0;;16848:43:7::3;16840:82;;;;;;;;;;;;;;;;;17024:38;::::0;;;;17056:4:::3;17024:38;::::0;::::3;368:74:37::0;16996:25:7::3;::::0;-1:-1:-1;;;;;17024:23:7;::::3;::::0;::::3;::::0;341:18:37;;17024:38:7::3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;16996:66:::0;-1:-1:-1;16996:66:7;17101:28:::3;17116:13:::0;17101:12;:28:::3;:::i;:::-;:49;;17076:119;;;;;;;;;;;;;;;;;16622:584;17257:20;17280:23;17297:5;17280:16;:23::i;:::-;17257:46;;17323:1;17317:3;:7;:37;;;;-1:-1:-1::0;;;;;;17328:26:7;::::3;::::0;::::3;17317:37;17313:113;;;17370:45;-1:-1:-1::0;;;;;17370:26:7;::::3;17397:12:::0;17411:3;17370:26:::3;:45::i;:::-;17483:8;-1:-1:-1::0;;;;;17441:82:7::3;17473:8;-1:-1:-1::0;;;;;17441:82:7::3;17462:9;-1:-1:-1::0;;;;;17441:82:7::3;;17493:6;17501:16;17519:3;17441:82;;;;;;;21104:25:37::0;;;21160:2;21145:18;;21138:34;;;;21203:2;21188:18;;21181:34;21092:2;21077:18;;20902:319;17441:82:7::3;;;;;;;;15083:2447;;;;;;;;3437:20:13::2;1949:1:::0;2532:30;4113:23;3860:283;3437:20:::2;14839:2691:7::0;;;;;;:::o;3996:361:0:-;1727:19;4153:7;;-1:-1:-1;;;;;4153:7:0;4139:10;:21;;:80;;-1:-1:-1;4164:11:0;;;;:55;;;;;4184:10;4164:55;;;18499:74:37;4204:4:0;18589:18:37;;;18582:83;4164:11:0;4211:7;-1:-1:-1;;;;;;4211:7:0;18681:18:37;;;18674:107;-1:-1:-1;;;;;4164:11:0;;;;:19;;18472:18:37;;4164:55:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;4118:139;;;;-1:-1:-1;;;4118:139:0;;16016:2:37;4118:139:0;;;15998:21:37;16055:2;16035:18;;;16028:30;-1:-1:-1;;;16074:18:37;;;16067:42;16126:18;;4118:139:0;15814:336:37;4118:139:0;4267:11;;;:26;;;;-1:-1:-1;;;;;4267:26:0;;;;;;;;4308:42;;4325:10;;4308:42;;-1:-1:-1;;4308:42:0;4057:300;3996:361;:::o;12118:274:7:-;12276:7;1979:19:12;:17;:19::i;:::-;12306:79:7::1;12328:56;;;;;;;;12341:6;12328:56;;;;12349:8;-1:-1:-1::0;;;;;12328:56:7::1;;;;;12359:5;-1:-1:-1::0;;;;;12328:56:7::1;;;;;12366:17;12328:56;;;;;;;;:::i;:::-;::::0;;12306:21:::1;:79::i;:::-;12299:86:::0;12118:274;-1:-1:-1;;;;12118:274:7:o;28778:357::-;28929:7;1979:19:12;:17;:19::i;:::-;28952:14:7::1;28969:22;28974:6;28982:8;28969:4;:22::i;:::-;28952:39;;29014:9;29005:6;:18;29001:105;;;29046:49;::::0;::::1;::::0;;::::1;::::0;::::1;9679:25:37::0;;;9720:18;;;9713:34;;;9652:18;;29046:49:7::1;9505:248:37::0;10621:62:7;2703:33:0;2716:10;2728:7;;-1:-1:-1;;;;;;2728:7:0;2703:12;:33::i;:::-;2695:58;;;;-1:-1:-1;;;2695:58:0;;16016:2:37;2695:58:0;;;15998:21:37;16055:2;16035:18;;;16028:30;-1:-1:-1;;;16074:18:37;;;16067:42;16126:18;;2695:58:0;15814:336:37;2695:58:0;10668:8:7::1;:6;:8::i;21696:288::-:0;2703:33:0;2716:10;2728:7;;-1:-1:-1;;;;;;2728:7:0;2703:12;:33::i;:::-;2695:58;;;;-1:-1:-1;;;2695:58:0;;16016:2:37;2695:58:0;;;15998:21:37;16055:2;16035:18;;;16028:30;-1:-1:-1;;;16074:18:37;;;16067:42;16126:18;;2695:58:0;15814:336:37;2695:58:0;21887:18:7;;21863:64:::1;::::0;;9679:25:37;;;9735:2;9720:18;;9713:34;;;21863:64:7;;40451:31;;21863:64:::1;::::0;;;;;;;::::1;21937:18;;:40:::0;21696:288::o;11190:149::-;2703:33:0;2716:10;2728:7;;-1:-1:-1;;;;;;2728:7:0;2703:12;:33::i;:::-;2695:58;;;;-1:-1:-1;;;2695:58:0;;16016:2:37;2695:58:0;;;15998:21:37;16055:2;16035:18;;;16028:30;-1:-1:-1;;;16074:18:37;;;16067:42;16126:18;;2695:58:0;15814:336:37;2695:58:0;11287:45:7::1;11319:4;11325:6;11287:31;:45::i;3463:102:0:-:0;3509:7;1727:19;3535:17;1612:150;27279:756:7;27441:7;1979:19:12;:17;:19::i;:::-;3395:21:13::1;:19;:21::i;:::-;-1:-1:-1::0;;27627:14:7::2;27644:19;27656:6;27644:11;:19::i;:::-;27777:18:::0;;27627:36;;-1:-1:-1;40451:31:7;;27810:32;;::::2;27806:140;;;27865:70;::::0;::::2;::::0;;::::2;::::0;::::2;9679:25:37::0;;;9720:18;;;9713:34;;;9652:18;;27865:70:7::2;9505:248:37::0;27806:140:7::2;27956:48;966:10:11::0;27979:8:7::2;27989:6;27997;27956:8;:48::i;:::-;-1:-1:-1::0;28022:6:7;;-1:-1:-1;;;3437:20:13::1;1949:1:::0;2532:30;4113:23;3860:283;21052:404:7;2703:33:0;2716:10;2728:7;;-1:-1:-1;;;;;;2728:7:0;2703:12;:33::i;:::-;2695:58;;;;-1:-1:-1;;;2695:58:0;;16016:2:37;2695:58:0;;;15998:21:37;16055:2;16035:18;;;16028:30;-1:-1:-1;;;16074:18:37;;;16067:42;16126:18;;2695:58:0;15814:336:37;2695:58:0;5493:4:7::1;21159:22;:49;21151:89;;;;;;;;;;;;;;;;;21347:21:::0;;21326:67:::1;::::0;;9679:25:37;;;9735:2;9720:18;;9713:34;;;21326:67:7;;40451:31;;21326:67:::1;::::0;;;;;;;::::1;21403:21;;:46:::0;21052:404::o;2954:148:9:-;3086:9;3079:16;;3001:13;;2064:20;;3079:16;;;:::i;32340:208:7:-;32413:7;32432:14;32449:23;32465:6;32449:15;:23::i;:::-;32432:40;;32498:43;32525:7;4209:22:10;7010:8;-1:-1:-1;;;;;7010:8:10;;6873:153;32525:7:7;32534:6;32498:26;:43::i;4401:178:9:-;4470:4;966:10:11;4524:27:9;966:10:11;4541:2:9;4545:5;4524:9;:27::i;12808:303:7:-;12994:7;1979:19:12;:17;:19::i;:::-;2703:33:0::1;2716:10;2728:7;;-1:-1:-1::0;;;;;;2728:7:0::1;2703:12;:33::i;:::-;2695:58;;;::::0;-1:-1:-1;;;2695:58:0;;16016:2:37;2695:58:0::1;::::0;::::1;15998:21:37::0;16055:2;16035:18;;;16028:30;-1:-1:-1;;;16074:18:37;;;16067:42;16126:18;;2695:58:0::1;15814:336:37::0;2695:58:0::1;13024:80:7::2;13046:57;;;;;;;;13059:6;13046:57;;;;13067:8;-1:-1:-1::0;;;;;13046:57:7::2;;;;;13077:5;-1:-1:-1::0;;;;;13046:57:7::2;;;;;13084:18;13046:57:::0;::::2;;;;;;;:::i;30644:202::-:0;30719:7;30738:14;30755:25;30773:6;30755:17;:25::i;:::-;30738:42;;30806:33;30823:7;4209:22:10;7010:8;-1:-1:-1;;;;;7010:8:10;;6873:153;30823:7:7;30832:6;30806:16;:33::i;:::-;30797:42;;:6;:42;:::i;29291:142::-;29375:7;1979:19:12;:17;:19::i;:::-;29401:25:7::1;;;;;;;;;;;;;;26578:366:::0;26732:7;1979:19:12;:17;:19::i;:::-;26755:14:7::1;26772:25;26780:6;26788:8;26772:7;:25::i;:::-;26755:42;;26820:9;26811:6;:18;26807:108;;;26852:52;::::0;::::1;::::0;;::::1;::::0;::::1;9679:25:37::0;;;9720:18;;;9713:34;;;9652:18;;26852:52:7::1;9505:248:37::0;7221:148:10;7291:7;7317:45;7334:6;7342:19;7317:16;:45::i;31900:216:7:-;31975:7;31994:14;32011:27;32031:6;32011:19;:27::i;:::-;31994:44;;32064:45;32093:7;4209:22:10;7010:8;-1:-1:-1;;;;;7010:8:10;;6873:153;32093:7:7;32102:6;32064:28;:45::i;7870:153:10:-;-1:-1:-1;;;;;4179:20:9;;7935:7:10;4179:20:9;;;2064;4179;;;;;;7961:55:10;;7996:19;7961:16;:55::i;8058:112::-;-1:-1:-1;;;;;4179:20:9;;8121:7:10;4179:20:9;;;2064;4179;;;;;;8147:16:10;4035:171:9;3032:314:0;3201:11;;3117:4;;1727:19;;-1:-1:-1;;;;;3201:11:0;3230:27;;;;;:77;;-1:-1:-1;3261:46:0;;;;;-1:-1:-1;;;;;18517:55:37;;;3261:46:0;;;18499:74:37;3288:4:0;18589:18:37;;;18582:83;-1:-1:-1;;;;;;18701:79:37;;18681:18;;;18674:107;3261:12:0;;;;;18472:18:37;;3261:46:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;3229:110;;;-1:-1:-1;3332:7:0;;-1:-1:-1;;;;;3324:15:0;;;3332:7;;3324:15;3229:110;3222:117;3032:314;-1:-1:-1;;;;;3032:314:0:o;19078:1103:7:-;2703:33:0;2716:10;2728:7;;-1:-1:-1;;;;;;2728:7:0;2703:12;:33::i;:::-;2695:58;;;;-1:-1:-1;;;2695:58:0;;16016:2:37;2695:58:0;;;15998:21:37;16055:2;16035:18;;;16028:30;-1:-1:-1;;;16074:18:37;;;16067:42;16126:18;;2695:58:0;15814:336:37;2695:58:0;19337:18:7;;40451:31;;19322:12:::1;:33;19314:86;;;;;;;;;;;;;;;;;19441:30:::0;;19416:78:::1;::::0;;9679:25:37;;;9735:2;9720:18;;9713:34;;;19416:78:7::1;::::0;9652:18:37;19416:78:7::1;;;;;;;19504:53:::0;;;:30:::1;19741:48;5323:4;19775:13;3981:14:9::0;;;3850:152;19775:13:7::1;19741;:11;:13::i;:::-;:20:::0;:48;:20:::1;:48::i;:::-;19714:75;;19800:24;19827:65;19854:1;:19;;;19875:16;19827:26;:65::i;:::-;19800:92;;20027:1;:21;;;20008:16;:40;20004:79;;;20064:8;:6;:8::i;:::-;-1:-1:-1::0;20093:19:7::1;::::0;::::1;:38:::0;20162:12:::1;20141:18;::::0;;::::1;:33:::0;-1:-1:-1;19078:1103:7:o;30246:204::-;30324:7;30343:11;30357:35;30376:7;4209:22:10;7010:8;-1:-1:-1;;;;;7010:8:10;;6873:153;30376:7:7;30385:6;30357:18;:35::i;:::-;30343:49;-1:-1:-1;30409:34:7;30430:12;30343:49;30430:6;:12;:::i;4543:216:0:-;2703:33;2716:10;2728:7;;-1:-1:-1;;;;;;2728:7:0;2703:12;:33::i;:::-;2695:58;;;;-1:-1:-1;;;2695:58:0;;16016:2:37;2695:58:0;;;15998:21:37;16055:2;16035:18;;;16028:30;-1:-1:-1;;;16074:18:37;;;16067:42;16126:18;;2695:58:0;15814:336:37;2695:58:0;1727:19;4677:18;;;::::1;-1:-1:-1::0;;;;;4677:18:0;::::1;::::0;;::::1;::::0;;4710:42:::1;::::0;4731:10:::1;::::0;4710:42:::1;::::0;-1:-1:-1;;4710:42:0::1;4616:143;4543:216:::0;:::o;8721:449:7:-;8874:19;2703:33:0;2716:10;2728:7;;-1:-1:-1;;;;;;2728:7:0;2703:12;:33::i;:::-;2695:58;;;;-1:-1:-1;;;2695:58:0;;16016:2:37;2695:58:0;;;15998:21:37;16055:2;16035:18;;;16028:30;-1:-1:-1;;;16074:18:37;;;16067:42;16126:18;;2695:58:0;15814:336:37;2695:58:0;8909:18:7::1;8930:12;8937:4:::0;;8930:12:::1;:::i;:::-;8909:33;;8973:11;3772:27:0::0;;-1:-1:-1;;;;;3772:27:0;;3694:112;8973:11:7::1;:52;::::0;;;;8993:10:::1;8973:52;::::0;::::1;18499:74:37::0;-1:-1:-1;;;;;18609:55:37;;;18589:18;;;18582:83;-1:-1:-1;;;;;;18701:79:37;;18681:18;;;18674:107;8973:19:7;;;::::1;::::0;::::1;::::0;18472:18:37;;8973:52:7::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;9072:6;9080:11;8952:150;;;;;::::0;::::1;::::0;;-1:-1:-1;;;;;19232:55:37;;;8952:150:7::1;::::0;::::1;19214:74:37::0;-1:-1:-1;;;;;;19324:79:37;19304:18;;;19297:107;19187:18;;8952:150:7::1;19042:368:37::0;8952:150:7::1;;;9122:41;9151:4;;9122:41;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;::::0;;;;-1:-1:-1;;;;;;;;9122:28:7;::::1;::::0;;-1:-1:-1;9157:5:7;9122:28:::1;:41::i;:::-;9113:50:::0;8721:449;-1:-1:-1;;;;;;8721:449:7:o;11084:213:10:-;11181:7;11207:83;11221:13;:11;:13::i;:::-;:17;;11237:1;11221:17;:::i;:::-;11256:23;13258:5;11256:2;:23;:::i;:::-;3981:14:9;;11240:39:10;;;;:::i;:::-;11207:6;;:83;11281:8;11207:13;:83::i;9905:128:9:-;9989:37;9998:5;10005:7;10014:5;10021:4;9989:8;:37::i;4893:259:2:-;5038:7;5068:77;5082:5;5089:6;5097:41;5140:4;5068:13;:77::i;8565:147:10:-;8635:7;8661:44;8678:6;8686:18;8661:16;:44::i;36871:983:7:-;37066:15;;-1:-1:-1;;;;;37050:32:7;36948:30;37050:32;;;:15;:32;;;;;37113:14;;;;40451:31;;37050:32;37113:19;;;;:54;;;37153:7;:14;;;37136:6;:13;;;:31;;37113:54;37092:115;;;;;;;;;;;;;;;;;37238:14;;:19;;;;:61;;-1:-1:-1;37285:14:7;;37261:20;;;;:38;;37238:61;37217:134;;;;;;;;;;;;;;;;;37380:6;:13;;;37362:7;:14;;;:31;;;;;;;:::i;:::-;;;;-1:-1:-1;;37421:20:7;;;;37403:38;;:7;;:14;;:38;;37421:20;;37403:38;:::i;:::-;;;;-1:-1:-1;;37475:20:7;;;;37451;;;:44;;:20;;:44;;37475:20;;37451:44;:::i;:::-;;;;;;;;37565:116;37600:6;:15;;;37617:6;:13;;;37632:6;:20;;;37654:6;:17;;;37565:21;:116::i;:::-;37756:91;37775:6;:15;;;37792:6;:20;;;37814:6;:13;;;37829:6;:17;;;37756:18;:91::i;1219:160:27:-;1328:43;;-1:-1:-1;;;;;22970:55:37;;;1328:43:27;;;22952:74:37;23042:18;;;23035:34;;;1301:71:27;;1321:5;;1343:14;;;;;22925:18:37;;1328:43:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1301:19;:71::i;9071:205:8:-;9129:30;;3147:66;9186:27;8819:122;7064:525:7;6929:20:8;:18;:20::i;:::-;7263:28:7::1;7276:5;7283:7;7263:12;:28::i;:::-;7301:22;7316:6;7301:14;:22::i;:::-;7333:42;7345:6;7371:1;7333:11;:42::i;:::-;7385:17;:15;:17::i;:::-;7412:57;7465:1;7412:26;:57::i;:::-;7479:27;:25;:27::i;:::-;7516:24;:22;:24::i;:::-;7550:32;:30;:32::i;:::-;7064:525:::0;;;;:::o;2975:407:28:-;3074:12;3126:5;3102:21;:29;3098:123;;;3154:56;;;;;3181:21;3154:56;;;9679:25:37;9720:18;;;9713:34;;;9652:18;;3154:56:28;9505:248:37;3098:123:28;3231:12;3245:23;3272:6;-1:-1:-1;;;;;3272:11:28;3291:5;3298:4;3272:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3230:73;;;;3320:55;3347:6;3355:7;3364:10;3320:26;:55::i;11649:476:9:-;-1:-1:-1;;;;;4771:20:9;;;11748:24;4771:20;;;:13;:20;;;;;;;;:29;;;;;;;;;;-1:-1:-1;;11814:36:9;;11810:309;;;11889:5;11870:16;:24;11866:130;;;11921:60;;;;;-1:-1:-1;;;;;19788:55:37;;11921:60:9;;;19770:74:37;19860:18;;;19853:34;;;19903:18;;;19896:34;;;19743:18;;11921:60:9;19568:368:37;11866:130:9;12037:57;12046:5;12053:7;12081:5;12062:16;:24;12088:5;12037:8;:57::i;6509:300::-;-1:-1:-1;;;;;6592:18:9;;6588:86;;6633:30;;;;;6660:1;6633:30;;;368:74:37;341:18;;6633:30:9;196:252:37;6588:86:9;-1:-1:-1;;;;;6687:16:9;;6683:86;;6726:32;;;;;6755:1;6726:32;;;368:74:37;341:18;;6726:32:9;196:252:37;6683:86:9;6778:24;6786:4;6792:2;6796:5;6778:7;:24::i;5562:393:1:-;5665:6;5675:1;5665:11;5661:61;;5699:12;;;;;;;;;;;;;;5661:61;-1:-1:-1;;;;;4180:29:1;;4064:18;4180:29;;;6375:30;4180:29;;;;;;;;5731:97;;5792:25;;;;;;;;;;;;;;5731:97;5838:45;-1:-1:-1;;;;;5838:26:1;;5865:9;5876:6;5838:26;:45::i;:::-;5938:9;-1:-1:-1;;;;;5898:50:1;5923:5;-1:-1:-1;;;;;5898:50:1;5911:10;-1:-1:-1;;;;;5898:50:1;;5930:6;5898:50;;;;160:25:37;;148:2;133:18;;14:177;5898:50:1;;;;;;;;5562:393;;;:::o;3478:178:12:-;2226:16;:14;:16::i;:::-;1270:23;3595:17;;;::::1;::::0;;3627:22:::1;966:10:11::0;3636:12:12::1;3627:22;::::0;-1:-1:-1;;;;;386:55:37;;;368:74;;356:2;341:18;3627:22:12::1;;;;;;;3526:130;3478:178::o:0;2694:326:2:-;1539:23;2775:25;2869:13;:11;:13::i;:::-;2892:28;;;;-1:-1:-1;;;;;2892:28:2;;;;;;;;2935:78;;;23578:55:37;;;23560:74;;23665:2;23650:18;;23643:83;;;;2834:48:2;;-1:-1:-1;2954:10:2;;2935:78;;23533:18:37;2935:78:2;;;;;;;2765:255;;2694:326;:::o;3026:202::-;3098:7;3117:33;3153:13;:11;:13::i;:::-;3183:38;;;;;-1:-1:-1;;;;;386:55:37;;;3183:38:2;;;368:74:37;3117:49:2;;-1:-1:-1;3183:31:2;;;;;;341:18:37;;3183:38:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;6277:262::-;6424:7;6454:78;6468:5;6475:6;6483:41;6526:5;6454:13;:78::i;4312:312:23:-;4392:4;-1:-1:-1;;;;;4401:6:23;4384:23;;;:120;;;4498:6;-1:-1:-1;;;;;4462:42:23;:32;:30;:32::i;:::-;-1:-1:-1;;;;;4462:42:23;;;4384:120;4367:251;;;4578:29;;;;;;;;;;;;;;40814:96:7;2703:33:0;2716:10;2728:7;;-1:-1:-1;;;;;;2728:7:0;2703:12;:33::i;:::-;2695:58;;;;-1:-1:-1;;;2695:58:0;;16016:2:37;2695:58:0;;;15998:21:37;16055:2;16035:18;;;16028:30;-1:-1:-1;;;16074:18:37;;;16067:42;16126:18;;2695:58:0;15814:336:37;5766:538:23;5883:17;-1:-1:-1;;;;;5865:50:23;;:52;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;5865:52:23;;;;;;;;-1:-1:-1;;5865:52:23;;;;;;;;;;;;:::i;:::-;;;5861:437;;6227:60;;;;;-1:-1:-1;;;;;386:55:37;;6227:60:23;;;368:74:37;341:18;;6227:60:23;196:252:37;5861:437:23;811:66:21;5959:40:23;;5955:120;;6026:34;;;;;;;;160:25:37;;;133:18;;6026:34:23;14:177:37;5955:120:23;6088:54;6118:17;6137:4;6088:29;:54::i;4741:213::-;4815:4;-1:-1:-1;;;;;4824:6:23;4807:23;;4803:145;;4908:29;;;;;;;;;;;;;;2709:128:12;1270:23;2625:9;;;2770:61;;;2805:15;;;;;;;;;;;;;;3470:384:13;2532:30;3670:9;;:20;;3666:88;;3713:30;;;;;;;;;;;;;;3666:88;1991:1;3828:19;;3470:384::o;33005:505:7:-;33175:13;33191:7;4209:22:10;7010:8;-1:-1:-1;;;;;7010:8:10;;6873:153;33191:7:7;33175:23;;33208:17;33228:33;33247:5;33254:6;33228:18;:33::i;:::-;33208:53;;33272:17;33292:23;33309:5;33292:16;:23::i;:::-;33272:43;;33326:48;33341:6;33349:8;33359:6;33367;33326:14;:48::i;:::-;33401:1;33389:9;:13;:40;;;;-1:-1:-1;;;;;;33406:23:7;;;;33389:40;33385:119;;;33445:48;-1:-1:-1;;;;;33445:26:7;;33472:9;33483;33445:26;:48::i;:::-;33165:345;;;33005:505;;;;:::o;3860:283:13:-;1949:1;2532:30;4113:23;3860:283::o;7242:367:2:-;7394:7;7522:80;7536:5;7543:6;7551:43;7596:5;7522:13;:80::i;9163:206:9:-;-1:-1:-1;;;;;9233:21:9;;9229:89;;9277:30;;;;;9304:1;9277:30;;;368:74:37;341:18;;9277:30:9;196:252:37;9229:89:9;9327:35;9335:7;9352:1;9356:5;9327:7;:35::i;33802:1059:7:-;33914:13;;33887:7;;33906:53;;;;;;;;;;;;;;;;;33977:12;;;;-1:-1:-1;;;;;33977:26:7;33993:10;33977:26;33969:60;;;;;;;;;;;;;;;;;34074:13;;34057:12;;;;;-1:-1:-1;;;;;4179:20:9;4100:7;4179:20;;;2064;4179;;;;34047:40:7;;34039:78;;;;;;;;;;;;;;;;;34128:21;34152:34;34172:6;:13;;;34152:19;:34::i;:::-;34128:58;;34256:125;34293:6;:15;;;34310:6;:12;;;34324:13;34339:6;:13;;;34354:6;:17;;;34256:23;:125::i;:::-;34512:12;;;;34541:13;;40451:31;;34502:53;;34534:4;;34502:9;:53::i;:::-;34589:13;34565:1;:20;;;:37;;;;;;;:::i;:::-;;;;-1:-1:-1;;34647:179:7;;;;;;;;34776:15;;;;;-1:-1:-1;;;;;34760:32:7;-1:-1:-1;34760:32:7;;;:15;;;:32;;;;;;;:39;34647:179;;34760:55;;34802:13;;34760:55;:::i;:::-;34647:179;;34725:13;;34647:179;34699:15;;;;-1:-1:-1;;;;;34683:32:7;34725:13;34683:32;;;:15;;;:32;;;;;:39;;;34647:179;;;34683:55;;34725:13;34683:55;:::i;:::-;34647:179;;34628:15;;;;;-1:-1:-1;;;;;34612:32:7;;;;;:15;;;;:32;;;;;:214;;;;;;;;;;;;;;;-1:-1:-1;34612:32:7;;33802:1059;-1:-1:-1;33802:1059:7:o;3170:176:12:-;1979:19;:17;:19::i;:::-;1270:23;3288:16;;;::::1;3300:4;3288:16;::::0;;3319:20:::1;966:10:11::0;3326:12:12::1;887:96:11::0;4655:498:1;6375:30;-1:-1:-1;;;;;4841:18:1;;4837:69;;4882:13;;;;;;;;;;;;;;4837:69;-1:-1:-1;;;;;4920:29:1;;:23;:29;;;;;;;;;;;:46;;;:29;;;;:46;;;4916:111;;4989:27;;;;;;;;;;;;;;4916:111;-1:-1:-1;;;;;5037:29:1;;:23;:29;;;;;;;;;;;;:45;;;;;;;;;;;;;5097:49;;1933:41:37;;;5114:10:1;;5097:49;;1906:18:37;5097:49:1;;;;;;;4747:406;4655:498;;:::o;8387:143:10:-;8453:7;8479:44;8496:6;8504:18;8479:16;:44::i;4445:253:2:-;4587:7;4617:74;4631:5;4638:6;4646:38;4686:4;4617:13;:74::i;10747:213:10:-;10844:7;10870:83;10900:23;10844:7;10900:2;:23;:::i;:::-;3981:14:9;;10884:39:10;;;;:::i;:::-;10925:13;:11;:13::i;:::-;:17;;10941:1;10925:17;:::i;6746:289:2:-;6900:7;6942:86;6956:5;6963:6;6971:49;7022:5;6942:13;:86::i;7242:3683:34:-;7324:14;7375:12;7389:11;7404:12;7411:1;7414;7404:6;:12::i;:::-;7374:42;;;;7498:4;7506:1;7498:9;7494:365;;7833:11;7827:3;:17;;;;;:::i;:::-;;7820:24;;;;;;7494:365;7984:4;7969:11;:19;7965:142;;8008:84;5312:5;8028:16;;5311:36;940:4:31;5306:42:34;8008:11;:84::i;:::-;8359:17;8510:11;8507:1;8504;8497:25;8902:12;8932:15;;;8917:31;;9067:22;;;;;9800:1;9781;:15;;9780:21;;10033;;;10029:25;;10018:36;10103:21;;;10099:25;;10088:36;10175:21;;;10171:25;;10160:36;10246:21;;;10242:25;;10231:36;10319:21;;;10315:25;;10304:36;10393:21;;;10389:25;;;10378:36;9309:12;;;;9305:23;;;9330:1;9301:31;8622:18;;;8612:29;;;9416:11;;;;8665:19;;;;9160:14;;;;9409:18;;;;10868:13;;-1:-1:-1;;7242:3683:34;;;;;:::o;39712:380:7:-;39852:7;39879:8;39891:1;39879:13;39875:52;;-1:-1:-1;39915:1:7;39908:8;;39875:52;39936:12;39962:8;39951;:19;:63;;39995:19;40006:8;39995;:19;:::i;:::-;39951:63;;;39973:19;39984:8;39973;:19;:::i;:::-;39936:78;-1:-1:-1;40031:54:7;39936:78;5323:4;40056:8;40066:18;40031:11;:54::i;5822:256:2:-;5966:7;5996:75;6010:5;6017:6;6025:38;6065:5;5996:13;:75::i;11054:238:34:-;11155:7;11209:76;11225:26;11242:8;11225:16;:26::i;:::-;:59;;;;;11283:1;11268:11;11255:25;;;;;:::i;:::-;11265:1;11262;11255:25;:29;11225:59;34914:9:35;34907:17;;34795:145;11209:76:34;11181:25;11188:1;11191;11194:11;11181:6;:25::i;:::-;:104;;;;:::i;10880:487:9:-;2064:20;-1:-1:-1;;;;;11045:19:9;;11041:89;;11087:32;;;;;11116:1;11087:32;;;368:74:37;341:18;;11087:32:9;196:252:37;11041:89:9;-1:-1:-1;;;;;11143:21:9;;11139:90;;11187:31;;;;;11215:1;11187:31;;;368:74:37;341:18;;11187:31:9;196:252:37;11139:90:9;-1:-1:-1;;;;;11238:20:9;;;;;;;:13;;;:20;;;;;;;;:29;;;;;;;;;:37;;;11285:76;;;;11335:7;-1:-1:-1;;;;;11319:31:9;11328:5;-1:-1:-1;;;;;11319:31:9;;11344:5;11319:31;;;;160:25:37;;148:2;133:18;;14:177;11319:31:9;;;;;;;;10978:389;10880:487;;;;:::o;3647:609:2:-;3862:7;3885:33;3921:13;:11;:13::i;:::-;3885:49;-1:-1:-1;;;;;;3949:38:2;;3945:106;;4010:30;;;;;-1:-1:-1;;;;;;4032:7:2;;;4010:30;;;24515:98:37;24488:18;;4010:30:2;24371:248:37;3945:106:2;4065:11;4061:189;;;4099:50;;;;;-1:-1:-1;;;;;4099:24:2;;;;;:50;;4124:5;;4131:6;;4139:9;;4099:50;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;4092:57;;;;;4061:189;4187:52;;;;;-1:-1:-1;;;;;4187:26:2;;;;;:52;;4214:5;;4221:6;;4229:9;;4187:52;;;:::i;36124:517:7:-;36322:17;36308:10;:31;;;;;;;;:::i;:::-;;36304:331;;36360:49;;;9679:25:37;;;9735:2;9720:18;;9713:34;;;-1:-1:-1;;;;;36360:49:7;;;;;9652:18:37;36360:49:7;;;;;;;;36304:331;;;36444:18;36430:10;:32;;;;;;;;:::i;:::-;;36426:209;;36483:56;;;9679:25:37;;;9735:2;9720:18;;9713:34;;;-1:-1:-1;;;;;36483:56:7;;;;;9652:18:37;36483:56:7;9505:248:37;36426:209:7;36612:10;36606:17;;;;;;;;:::i;:::-;36577:47;;;;;7583:4:37;7571:17;;;36577:47:7;;;7553:36:37;7526:18;;36577:47:7;7411:184:37;38290:1034:7;38467:13;38483:7;4209:22:10;7010:8;-1:-1:-1;;;;;7010:8:10;;6873:153;38483:7:7;38467:23;-1:-1:-1;38500:17:7;;38582:10;:31;;;;;;;;:::i;:::-;;38578:333;;38641:43;38663:5;38670:13;38641:21;:43::i;:::-;38629:55;;38578:333;;;38719:18;38705:10;:32;;;;;;;;:::i;:::-;;38701:210;;38765:50;38794:5;38801:13;38765:28;:50::i;38701:210::-;38888:10;38882:17;;;;;;;;:::i;38701:210::-;38921:14;38938:25;38954:9;38938:13;:25;:::i;:::-;38921:42;;38973:17;38993:23;39010:5;38993:16;:23::i;:::-;38973:43;;39061:71;39085:4;39092:8;39110:4;39117:6;39125;39061:15;:71::i;:::-;39215:1;39203:9;:13;:40;;;;-1:-1:-1;;;;;;39220:23:7;;;;39203:40;39199:119;;;39259:48;-1:-1:-1;;;;;39259:26:7;;39286:9;39297;39259:26;:48::i;:::-;38457:867;;;;38290:1034;;;;:::o;8370:720:27:-;8450:18;8478:19;8616:4;8613:1;8606:4;8600:11;8593:4;8587;8583:15;8580:1;8573:5;8566;8561:60;8673:7;8663:176;;8717:4;8711:11;8762:16;8759:1;8754:3;8739:40;8808:16;8803:3;8796:29;8663:176;-1:-1:-1;;8916:1:27;8910:8;8866:16;;-1:-1:-1;8942:15:27;;:68;;8994:11;9009:1;8994:16;;8942:68;;;-1:-1:-1;;;;;8960:26:27;;;:31;8942:68;8938:146;;;9033:40;;;;;-1:-1:-1;;;;;386:55:37;;9033:40:27;;;368:74:37;341:18;;9033:40:27;196:252:37;7082:141:8;7149:17;:15;:17::i;:::-;7144:73;;7189:17;;;;;;;;;;;;;;2263:147:9;6929:20:8;:18;:20::i;:::-;2365:38:9::1;2388:5;2395:7;2365:22;:38::i;5095:114:10:-:0;6929:20:8;:18;:20::i;:::-;5170:32:10::1;5195:6;5170:24;:32::i;2053:143:0:-:0;6929:20:8;:18;:20::i;:::-;2148:41:0::1;2170:6;2178:10;2148:21;:41::i;2266:60:12:-:0;6929:20:8;:18;:20::i;1799:161:2:-;6929:20:8;:18;:20::i;:::-;1903:50:2::1;1940:12;1903:36;:50::i;3312:117:1:-:0;6929:20:8;:18;:20::i;:::-;3385:37:1::1;:35;:37::i;2684:111:13:-:0;6929:20:8;:18;:20::i;:::-;2754:34:13::1;:32;:34::i;7963:220:7:-:0;6929:20:8;:18;:20::i;:::-;8134:4:7::1;8110:21:::0;:28;8041:30:::1;8154:18:::0;:22;7963:220::o;4437:582:28:-;4581:12;4610:7;4605:408;;4633:19;4641:10;4633:7;:19::i;:::-;4605:408;;;4857:17;;:22;:49;;;;-1:-1:-1;;;;;;4883:18:28;;;:23;4857:49;4853:119;;;4933:24;;;;;-1:-1:-1;;;;;386:55:37;;4933:24:28;;;368:74:37;341:18;;4933:24:28;196:252:37;4853:119:28;-1:-1:-1;4992:10:28;4985:17;;29907:137:7;1979:19:12;:17;:19::i;:::-;30007:30:7::1;30021:4;30027:2;30031:5;30007:13;:30::i;2909:126:12:-:0;1270:23;2625:9;;;2967:62;;3003:15;;;;;;;;;;;;;;1441:138:21;1493:7;811:66;1519:47;1899:163:32;2264:344:21;2355:37;2374:17;2355:18;:37::i;:::-;2407:36;;-1:-1:-1;;;;;2407:36:21;;;;;;;;2458:11;;:15;2454:148;;2489:53;2518:17;2537:4;2489:28;:53::i;2454:148::-;2573:18;:16;:18::i;11361:841:10:-;12031:74;12065:7;4209:22;7010:8;-1:-1:-1;;;;;7010:8:10;;6873:153;12065:7;12075:6;12091:4;12098:6;12031:26;:74::i;:::-;12115:23;12121:8;12131:6;12115:5;:23::i;:::-;12170:8;-1:-1:-1;;;;;12154:41:10;12162:6;-1:-1:-1;;;;;12154:41:10;;12180:6;12188;12154:41;;;;;;9679:25:37;;;9735:2;9720:18;;9713:34;9667:2;9652:18;;9505:248;12154:41:10;;;;;;;;11361:841;;;;:::o;35250:550:7:-;35473:17;35459:10;:31;;;;;;;;:::i;:::-;;35455:339;;35535:5;-1:-1:-1;;;;;35511:53:7;35525:8;-1:-1:-1;;;;;35511:53:7;;35542:13;35557:6;35511:53;;;;;;9679:25:37;;;9735:2;9720:18;;9713:34;9667:2;9652:18;;9505:248;35511:53:7;;;;;;;;35455:339;;;35599:18;35585:10;:32;;;;;;;;:::i;:::-;;35581:213;;35669:5;-1:-1:-1;;;;;35638:60:7;35659:8;-1:-1:-1;;;;;35638:60:7;;35676:13;35691:6;35638:60;;;;;;9679:25:37;;;9735:2;9720:18;;9713:34;9667:2;9652:18;;9505:248;1027:550:34;1088:12;;-1:-1:-1;;1471:1:34;1468;1461:20;1501:9;;;;1549:11;;;1535:12;;;;1531:30;;;;;1027:550;-1:-1:-1;;1027:550:34:o;1776:194:31:-;1881:10;1875:4;1868:24;1918:4;1912;1905:18;1949:4;1943;1936:18;32020:122:34;32088:4;32129:1;32117:8;32111:15;;;;;;;;:::i;:::-;:19;;;;:::i;:::-;:24;;32134:1;32111:24;32104:31;;32020:122;;;:::o;12269:925:10:-;12456:5;-1:-1:-1;;;;;12446:15:10;:6;-1:-1:-1;;;;;12446:15:10;;12442:84;;12477:38;12493:5;12500:6;12508;12477:15;:38::i;:::-;13035:20;13041:5;13048:6;13035:5;:20::i;:::-;13065:57;13095:7;4209:22;7010:8;-1:-1:-1;;;;;7010:8:10;;6873:153;13095:7;13105:8;13115:6;13065:22;:57::i;:::-;13165:5;-1:-1:-1;;;;;13138:49:10;13155:8;-1:-1:-1;;;;;13138:49:10;13147:6;-1:-1:-1;;;;;13138:49:10;;13172:6;13180;13138:49;;;;;;9679:25:37;;;9735:2;9720:18;;9713:34;9667:2;9652:18;;9505:248;13138:49:10;;;;;;;;12269:925;;;;;:::o;8485:120:8:-;8535:4;8558:26;:24;:26::i;:::-;:40;;;;;;;;-1:-1:-1;8485:120:8:o;2416:216:9:-;6929:20:8;:18;:20::i;:::-;2064::9;2581:7;:15:::1;2591:5:::0;2581:7;:15:::1;:::i;:::-;-1:-1:-1::0;2606:9:9::1;::::0;::::1;:19;2618:7:::0;2606:9;:19:::1;:::i;5215:304:10:-:0;6929:20:8;:18;:20::i;:::-;4209:22:10;5300:24:::1;::::0;5395:28:::1;5416:6:::0;5395:20:::1;:28::i;:::-;5357:66;;;;5457:7;:28;;5483:2;5457:28;;;5467:13;5457:28;5433:52:::0;;5495:17;;5433:52;::::1;::::0;;;::::1;::::0;;;::::1;5495:17:::0;;;-1:-1:-1;;;;;5495:17:10;;;::::1;::::0;;;::::1;::::0;;;-1:-1:-1;;5215:304:10:o;2202:365:0:-;6929:20:8;:18;:20::i;:::-;1727:19:0;2400:16;;;;;::::1;-1:-1:-1::0;;;;;2400:16:0;;::::1;::::0;;::::1;::::0;;2426:11;:24;;;;::::1;::::0;;::::1;;::::0;;;2465:40:::1;::::0;2486:10:::1;::::0;2465:40:::1;::::0;-1:-1:-1;;2465:40:0::1;2520;::::0;-1:-1:-1;;;;;2520:40:0;::::1;::::0;2537:10:::1;::::0;2520:40:::1;::::0;;;::::1;2339:228;2202:365:::0;;:::o;1966:308:2:-;6929:20:8;:18;:20::i;:::-;1539:23:2;2159:28;;;::::1;-1:-1:-1::0;;;;;2159:28:2;::::1;::::0;;::::1;::::0;;2202:65:::1;::::0;;-1:-1:-1;23560:74:37;;23665:2;23650:18;;23643:83;;;;2202:65:2;;2221:10:::1;::::0;2202:65:::1;::::0;;;;;;;::::1;2090:184;1966:308:::0;:::o;2801:183:13:-;6929:20:8;:18;:20::i;5559:434:28:-;5690:17;;:21;5686:301;;5894:10;5888:17;5881:4;5869:10;5865:21;5858:48;5686:301;5957:19;;;;;;;;;;;;;;7124:1170:9;2064:20;-1:-1:-1;;;;;7266:18:9;;7262:546;;7420:5;7402:1;:14;;;:23;;;;;;;:::i;:::-;;;;-1:-1:-1;7262:546:9;;-1:-1:-1;7262:546:9;;-1:-1:-1;;;;;7478:17:9;;7456:19;7478:17;;;;;;;;;;;7513:19;;;7509:115;;;7559:50;;;;;-1:-1:-1;;;;;19788:55:37;;7559:50:9;;;19770:74:37;19860:18;;;19853:34;;;19903:18;;;19896:34;;;19743:18;;7559:50:9;19568:368:37;7509:115:9;-1:-1:-1;;;;;7744:17:9;;:11;:17;;;;;;;;;;7764:19;;;;7744:39;;7262:546;-1:-1:-1;;;;;7822:16:9;;7818:429;;7985:14;;;:23;;;;;;;7818:429;;;-1:-1:-1;;;;;8198:15:9;;:11;:15;;;;;;;;;;:24;;;;;;7818:429;8277:2;-1:-1:-1;;;;;8262:25:9;8271:4;-1:-1:-1;;;;;8262:25:9;;8281:5;8262:25;;;;160::37;;148:2;133:18;;14:177;1671:281:21;1748:17;-1:-1:-1;;;;;1748:29:21;;1781:1;1748:34;1744:119;;1805:47;;;;;-1:-1:-1;;;;;386:55:37;;1805:47:21;;;368:74:37;341:18;;1805:47:21;196:252:37;1744:119:21;811:66;1872:73;;;;-1:-1:-1;;;;;1872:73:21;;;;;;;;;;1671:281::o;3916:253:28:-;3999:12;4024;4038:23;4065:6;-1:-1:-1;;;;;4065:19:28;4085:4;4065:25;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4023:67;;;;4107:55;4134:6;4142:7;4151:10;4107:26;:55::i;6113:122:21:-;6163:9;:13;6159:70;;6199:19;;;;;;;;;;;;;;1618:188:27;1745:53;;-1:-1:-1;;;;;28061:55:37;;;1745:53:27;;;28043:74:37;28153:55;;;28133:18;;;28126:83;28225:18;;;28218:34;;;1718:81:27;;1738:5;;1760:18;;;;;28016::37;;1745:53:27;27841:417:37;8637:208:9;-1:-1:-1;;;;;8707:21:9;;8703:91;;8751:32;;;;;8780:1;8751:32;;;368:74:37;341:18;;8751:32:9;196:252:37;8703:91:9;8803:35;8819:1;8823:7;8832:5;8803:7;:35::i;5662:550:10:-;5856:43;;;;;;;;;;;;;;;;;;;;;;5816:93;;5729:7;;;;;;;;-1:-1:-1;;;;;5816:26:10;;;:93;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5769:140;;;;5923:7;:39;;;;;5960:2;5934:15;:22;:28;;5923:39;5919:260;;;5978:24;6016:15;6005:38;;;;;;;;;;;;:::i;:::-;5978:65;-1:-1:-1;6081:15:10;6061:35;;6057:112;;6124:4;;6136:16;;-1:-1:-1;5662:550:10;-1:-1:-1;;;;5662:550:10:o;6057:112::-;5964:215;5919:260;-1:-1:-1;6196:5:10;;;;-1:-1:-1;5662:550:10;-1:-1:-1;;;5662:550:10:o;453:348:37:-;495:3;533:5;527:12;560:6;555:3;548:19;616:6;609:4;602:5;598:16;591:4;586:3;582:14;576:47;668:1;661:4;652:6;647:3;643:16;639:27;632:38;790:4;-1:-1:-1;;715:2:37;707:6;703:15;699:88;694:3;690:98;686:109;679:116;;;453:348;;;;:::o;806:220::-;955:2;944:9;937:21;918:4;975:45;1016:2;1005:9;1001:18;993:6;975:45;:::i;1031:226::-;1090:6;1143:2;1131:9;1122:7;1118:23;1114:32;1111:52;;;1159:1;1156;1149:12;1111:52;-1:-1:-1;1204:23:37;;1031:226;-1:-1:-1;1031:226:37:o;1262:154::-;-1:-1:-1;;;;;1341:5:37;1337:54;1330:5;1327:65;1317:93;;1406:1;1403;1396:12;1421:367;1489:6;1497;1550:2;1538:9;1529:7;1525:23;1521:32;1518:52;;;1566:1;1563;1556:12;1518:52;1605:9;1592:23;1624:31;1649:5;1624:31;:::i;:::-;1674:5;1752:2;1737:18;;;;1724:32;;-1:-1:-1;;;1421:367:37:o;1985:487::-;2062:6;2070;2078;2131:2;2119:9;2110:7;2106:23;2102:32;2099:52;;;2147:1;2144;2137:12;2099:52;2186:9;2173:23;2205:31;2230:5;2205:31;:::i;:::-;2255:5;2333:2;2318:18;;2305:32;;-1:-1:-1;2436:2:37;2421:18;;;2408:32;;1985:487;-1:-1:-1;;;1985:487:37:o;2477:184::-;2529:77;2526:1;2519:88;2626:4;2623:1;2616:15;2650:4;2647:1;2640:15;2666:834;2731:5;2763:1;2787:18;2779:6;2776:30;2773:56;;;2809:18;;:::i;:::-;-1:-1:-1;3023:2:37;3017:9;-1:-1:-1;;2868:2:37;2856:15;;2852:88;;3081:2;3069:15;3065:88;3053:101;;3205:22;;;3184:18;3169:34;;3166:62;3163:88;;;3231:18;;:::i;:::-;3267:2;3260:22;3315;;;3300:6;-1:-1:-1;3300:6:37;3352:16;;;3349:25;-1:-1:-1;3346:45:37;;;3387:1;3384;3377:12;3346:45;3437:6;3432:3;3425:4;3417:6;3413:17;3400:44;3492:1;3485:4;3476:6;3468;3464:19;3460:30;3453:41;;2666:834;;;;;:::o;3505:222::-;3548:5;3601:3;3594:4;3586:6;3582:17;3578:27;3568:55;;3619:1;3616;3609:12;3568:55;3641:80;3717:3;3708:6;3695:20;3688:4;3680:6;3676:17;3641:80;:::i;3732:830::-;3853:6;3861;3869;3877;3930:3;3918:9;3909:7;3905:23;3901:33;3898:53;;;3947:1;3944;3937:12;3898:53;3986:9;3973:23;4005:31;4030:5;4005:31;:::i;:::-;4055:5;-1:-1:-1;4112:2:37;4097:18;;4084:32;4125:33;4084:32;4125:33;:::i;:::-;4177:7;-1:-1:-1;4235:2:37;4220:18;;4207:32;4262:18;4251:30;;4248:50;;;4294:1;4291;4284:12;4248:50;4317;4359:7;4350:6;4339:9;4335:22;4317:50;:::i;:::-;4307:60;;;4420:2;4409:9;4405:18;4392:32;4449:18;4439:8;4436:32;4433:52;;;4481:1;4478;4471:12;4433:52;4504;4548:7;4537:8;4526:9;4522:24;4504:52;:::i;:::-;4494:62;;;3732:830;;;;;;;:::o;4567:367::-;4630:8;4640:6;4694:3;4687:4;4679:6;4675:17;4671:27;4661:55;;4712:1;4709;4702:12;4661:55;-1:-1:-1;4735:20:37;;4778:18;4767:30;;4764:50;;;4810:1;4807;4800:12;4764:50;4847:4;4839:6;4835:17;4823:29;;4907:3;4900:4;4890:6;4887:1;4883:14;4875:6;4871:27;4867:38;4864:47;4861:67;;;4924:1;4921;4914:12;4861:67;4567:367;;;;;:::o;4939:1110::-;5108:6;5116;5124;5132;5140;5148;5201:2;5189:9;5180:7;5176:23;5172:32;5169:52;;;5217:1;5214;5207:12;5169:52;5257:9;5244:23;5290:18;5282:6;5279:30;5276:50;;;5322:1;5319;5312:12;5276:50;5361:70;5423:7;5414:6;5403:9;5399:22;5361:70;:::i;:::-;5450:8;;-1:-1:-1;5335:96:37;-1:-1:-1;;5538:2:37;5523:18;;5510:32;5567:18;5554:32;;5551:52;;;5599:1;5596;5589:12;5551:52;5638:72;5702:7;5691:8;5680:9;5676:24;5638:72;:::i;:::-;5729:8;;-1:-1:-1;5612:98:37;-1:-1:-1;;5817:2:37;5802:18;;5789:32;5846:18;5833:32;;5830:52;;;5878:1;5875;5868:12;5830:52;5917:72;5981:7;5970:8;5959:9;5955:24;5917:72;:::i;:::-;4939:1110;;;;-1:-1:-1;4939:1110:37;;-1:-1:-1;4939:1110:37;;6008:8;;4939:1110;-1:-1:-1;;;4939:1110:37:o;6054:839::-;6214:4;6262:2;6251:9;6247:18;6292:2;6281:9;6274:21;6315:6;6350;6344:13;6381:6;6373;6366:22;6419:2;6408:9;6404:18;6397:25;;6481:2;6471:6;6468:1;6464:14;6453:9;6449:30;6445:39;6431:53;;6519:2;6511:6;6507:15;6540:1;6550:314;6564:6;6561:1;6558:13;6550:314;;;6653:66;6641:9;6633:6;6629:22;6625:95;6620:3;6613:108;6744:40;6777:6;6768;6762:13;6744:40;:::i;:::-;6734:50;-1:-1:-1;6819:2:37;6842:12;;;;6807:15;;;;;6586:1;6579:9;6550:314;;;-1:-1:-1;6881:6:37;;6054:839;-1:-1:-1;;;;;;6054:839:37:o;6898:508::-;6975:6;6983;6991;7044:2;7032:9;7023:7;7019:23;7015:32;7012:52;;;7060:1;7057;7050:12;7012:52;7099:9;7086:23;7118:31;7143:5;7118:31;:::i;:::-;7168:5;-1:-1:-1;7225:2:37;7210:18;;7197:32;7238:33;7197:32;7238:33;:::i;:::-;6898:508;;7290:7;;-1:-1:-1;;;7370:2:37;7355:18;;;;7342:32;;6898:508::o;7831:367::-;7899:6;7907;7960:2;7948:9;7939:7;7935:23;7931:32;7928:52;;;7976:1;7973;7966:12;7928:52;8021:23;;;-1:-1:-1;8120:2:37;8105:18;;8092:32;8133:33;8092:32;8133:33;:::i;:::-;8185:7;8175:17;;;7831:367;;;;;:::o;8203:247::-;8262:6;8315:2;8303:9;8294:7;8290:23;8286:32;8283:52;;;8331:1;8328;8321:12;8283:52;8370:9;8357:23;8389:31;8414:5;8389:31;:::i;8733:585::-;8810:6;8818;8871:2;8859:9;8850:7;8846:23;8842:32;8839:52;;;8887:1;8884;8877:12;8839:52;8926:9;8913:23;8945:31;8970:5;8945:31;:::i;:::-;8995:5;-1:-1:-1;9051:2:37;9036:18;;9023:32;9078:18;9067:30;;9064:50;;;9110:1;9107;9100:12;9064:50;9133:22;;9186:4;9178:13;;9174:27;-1:-1:-1;9164:55:37;;9215:1;9212;9205:12;9164:55;9238:74;9304:7;9299:2;9286:16;9281:2;9277;9273:11;9238:74;:::i;:::-;9228:84;;;8733:585;;;;;:::o;9758:347::-;9809:8;9819:6;9873:3;9866:4;9858:6;9854:17;9850:27;9840:55;;9891:1;9888;9881:12;9840:55;-1:-1:-1;9914:20:37;;9957:18;9946:30;;9943:50;;;9989:1;9986;9979:12;9943:50;10026:4;10018:6;10014:17;10002:29;;10078:3;10071:4;10062:6;10054;10050:19;10046:30;10043:39;10040:59;;;10095:1;10092;10085:12;10110:948;10216:6;10224;10232;10240;10248;10256;10309:3;10297:9;10288:7;10284:23;10280:33;10277:53;;;10326:1;10323;10316:12;10277:53;10365:9;10352:23;10384:31;10409:5;10384:31;:::i;:::-;10434:5;-1:-1:-1;10491:2:37;10476:18;;10463:32;10504:33;10463:32;10504:33;:::i;:::-;10556:7;-1:-1:-1;10615:2:37;10600:18;;10587:32;10628:33;10587:32;10628:33;:::i;:::-;10680:7;-1:-1:-1;10760:2:37;10745:18;;10732:32;;-1:-1:-1;10841:3:37;10826:19;;10813:33;10869:18;10858:30;;10855:50;;;10901:1;10898;10891:12;10855:50;10940:58;10990:7;10981:6;10970:9;10966:22;10940:58;:::i;11334:508::-;11411:6;11419;11427;11480:2;11468:9;11459:7;11455:23;11451:32;11448:52;;;11496:1;11493;11486:12;11448:52;11541:23;;;-1:-1:-1;11640:2:37;11625:18;;11612:32;11653:33;11612:32;11653:33;:::i;:::-;11705:7;-1:-1:-1;11764:2:37;11749:18;;11736:32;11777:33;11736:32;11777:33;:::i;:::-;11829:7;11819:17;;;11334:508;;;;;:::o;11847:487::-;11924:6;11932;11940;11993:2;11981:9;11972:7;11968:23;11964:32;11961:52;;;12009:1;12006;11999:12;11961:52;12054:23;;;-1:-1:-1;12153:2:37;12138:18;;12125:32;12166:33;12125:32;12166:33;:::i;12339:118::-;12425:5;12418:13;12411:21;12404:5;12401:32;12391:60;;12447:1;12444;12437:12;12462:382;12527:6;12535;12588:2;12576:9;12567:7;12563:23;12559:32;12556:52;;;12604:1;12601;12594:12;12556:52;12643:9;12630:23;12662:31;12687:5;12662:31;:::i;:::-;12712:5;-1:-1:-1;12769:2:37;12754:18;;12741:32;12782:30;12741:32;12782:30;:::i;13099:475::-;13166:6;13174;13227:2;13215:9;13206:7;13202:23;13198:32;13195:52;;;13243:1;13240;13233:12;13195:52;13282:9;13269:23;13301:31;13326:5;13301:31;:::i;:::-;13351:5;-1:-1:-1;13408:2:37;13393:18;;13380:32;-1:-1:-1;;;;;;13443:80:37;;13431:93;;13421:121;;13538:1;13535;13528:12;13579:388;13647:6;13655;13708:2;13696:9;13687:7;13683:23;13679:32;13676:52;;;13724:1;13721;13714:12;13676:52;13763:9;13750:23;13782:31;13807:5;13782:31;:::i;:::-;13832:5;-1:-1:-1;13889:2:37;13874:18;;13861:32;13902:33;13861:32;13902:33;:::i;13972:664::-;14060:6;14068;14076;14084;14137:2;14125:9;14116:7;14112:23;14108:32;14105:52;;;14153:1;14150;14143:12;14105:52;14192:9;14179:23;14211:31;14236:5;14211:31;:::i;:::-;14261:5;-1:-1:-1;14317:2:37;14302:18;;14289:32;14344:18;14333:30;;14330:50;;;14376:1;14373;14366:12;14330:50;14415:58;14465:7;14456:6;14445:9;14441:22;14415:58;:::i;:::-;13972:664;;14492:8;;-1:-1:-1;14389:84:37;;14600:2;14585:18;14572:32;;13972:664;-1:-1:-1;;;;13972:664:37:o;14864:184::-;14934:6;14987:2;14975:9;14966:7;14962:23;14958:32;14955:52;;;15003:1;15000;14993:12;14955:52;-1:-1:-1;15026:16:37;;14864:184;-1:-1:-1;14864:184:37:o;15053:::-;15105:77;15102:1;15095:88;15202:4;15199:1;15192:15;15226:4;15223:1;15216:15;15242:125;15307:9;;;15328:10;;;15325:36;;;15341:18;;:::i;15372:437::-;15451:1;15447:12;;;;15494;;;15515:61;;15569:4;15561:6;15557:17;15547:27;;15515:61;15622:2;15614:6;15611:14;15591:18;15588:38;15585:218;;15659:77;15656:1;15649:88;15760:4;15757:1;15750:15;15788:4;15785:1;15778:15;15585:218;;15372:437;;;:::o;16155:184::-;16207:77;16204:1;16197:88;16304:4;16301:1;16294:15;16328:4;16325:1;16318:15;16344:128;16411:9;;;16432:11;;;16429:37;;;16446:18;;:::i;17044:184::-;17096:77;17093:1;17086:88;17193:4;17190:1;17183:15;17217:4;17214:1;17207:15;17233:580;17310:4;17316:6;17376:11;17363:25;17466:66;17455:8;17439:14;17435:29;17431:102;17411:18;17407:127;17397:155;;17548:1;17545;17538:12;17397:155;17575:33;;17627:20;;;-1:-1:-1;17670:18:37;17659:30;;17656:50;;;17702:1;17699;17692:12;17656:50;17735:4;17723:17;;-1:-1:-1;17766:14:37;17762:27;;;17752:38;;17749:58;;;17803:1;17800;17793:12;17818:476;17938:19;;-1:-1:-1;;;;;;17975:75:37;;;18070:1;18062:10;;18059:229;;;-1:-1:-1;;;;;;18141:66:37;18134:3;18131:1;18127:11;18124:1;18120:19;18116:92;18112:2;18108:101;18104:174;18095:183;;18059:229;;17818:476;;;;:::o;18792:245::-;18859:6;18912:2;18900:9;18891:7;18887:23;18883:32;18880:52;;;18928:1;18925;18918:12;18880:52;18960:9;18954:16;18979:28;19001:5;18979:28;:::i;19415:148::-;19503:4;19482:12;;;19496;;;19478:31;;19521:13;;19518:39;;;19537:18;;:::i;19941:956::-;-1:-1:-1;;;;;20242:6:37;20238:55;20227:9;20220:74;-1:-1:-1;;;;;20334:6:37;20330:55;20325:2;20314:9;20310:18;20303:83;-1:-1:-1;;;;;20426:6:37;20422:55;20417:2;20406:9;20402:18;20395:83;20514:6;20509:2;20498:9;20494:18;20487:34;20558:6;20552:3;20541:9;20537:19;20530:35;20602:3;20596;20585:9;20581:19;20574:32;20643:6;20637:3;20626:9;20622:19;20615:35;20701:6;20693;20687:3;20676:9;20672:19;20659:49;20758:1;20728:22;;;20752:3;20724:32;;;20717:43;;;;20812:2;20800:15;;;-1:-1:-1;;20796:88:37;20781:104;20777:114;;19941:956;-1:-1:-1;;;;;;19941:956:37:o;21226:375::-;21314:1;21332:5;21346:249;21367:1;21357:8;21354:15;21346:249;;;21417:4;21412:3;21408:14;21402:4;21399:24;21396:50;;;21426:18;;:::i;:::-;21476:1;21466:8;21462:16;21459:49;;;21490:16;;;;21459:49;21573:1;21569:16;;;;;21529:15;;21346:249;;;21226:375;;;;;;:::o;21606:1022::-;21655:5;21685:8;21675:80;;-1:-1:-1;21726:1:37;21740:5;;21675:80;21774:4;21764:76;;-1:-1:-1;21811:1:37;21825:5;;21764:76;21856:4;21874:1;21869:59;;;;21942:1;21937:174;;;;21849:262;;21869:59;21899:1;21890:10;;21913:5;;;21937:174;21974:3;21964:8;21961:17;21958:43;;;21981:18;;:::i;:::-;-1:-1:-1;;22037:1:37;22023:16;;22096:5;;21849:262;;22195:2;22185:8;22182:16;22176:3;22170:4;22167:13;22163:36;22157:2;22147:8;22144:16;22139:2;22133:4;22130:12;22126:35;22123:77;22120:203;;;-1:-1:-1;22232:19:37;;;22308:5;;22120:203;22355:102;-1:-1:-1;;22380:8:37;22374:4;22355:102;:::i;:::-;22553:6;-1:-1:-1;;22481:79:37;22472:7;22469:92;22466:118;;;22564:18;;:::i;:::-;22602:20;;21606:1022;-1:-1:-1;;;21606:1022:37:o;22633:140::-;22691:5;22720:47;22761:4;22751:8;22747:19;22741:4;22720:47;:::i;23080:301::-;23209:3;23247:6;23241:13;23293:6;23286:4;23278:6;23274:17;23269:3;23263:37;23355:1;23319:16;;23344:13;;;-1:-1:-1;23319:16:37;23080:301;-1:-1:-1;23080:301:37:o;23737:251::-;23807:6;23860:2;23848:9;23839:7;23835:23;23831:32;23828:52;;;23876:1;23873;23866:12;23828:52;23908:9;23902:16;23927:31;23952:5;23927:31;:::i;24182:184::-;24234:77;24231:1;24224:88;24331:4;24328:1;24321:15;24355:4;24352:1;24345:15;24624:593;-1:-1:-1;;;;;24859:55:37;;24841:74;;24946:2;24931:18;;24924:34;;;24829:2;24814:18;;24988:1;24977:13;;24967:201;;25024:77;25021:1;25014:88;25125:4;25122:1;25115:15;25153:4;25150:1;25143:15;24967:201;25204:6;25199:2;25188:9;25184:18;25177:34;24624:593;;;;;;:::o;25222:311::-;25252:1;25286:4;25283:1;25279:12;25310:3;25300:191;;25347:77;25344:1;25337:88;25448:4;25445:1;25438:15;25476:4;25473:1;25466:15;25300:191;25523:3;25516:4;25513:1;25509:12;25505:22;25500:27;;;25222:311;;;;:::o;25664:518::-;25766:2;25761:3;25758:11;25755:421;;;25802:5;25799:1;25792:16;25846:4;25843:1;25833:18;25916:2;25904:10;25900:19;25897:1;25893:27;25887:4;25883:38;25952:4;25940:10;25937:20;25934:47;;;-1:-1:-1;25975:4:37;25934:47;26030:2;26025:3;26021:12;26018:1;26014:20;26008:4;26004:31;25994:41;;26085:81;26103:2;26096:5;26093:13;26085:81;;;26162:1;26148:16;;26129:1;26118:13;26085:81;;26418:1418;26544:3;26538:10;26571:18;26563:6;26560:30;26557:56;;;26593:18;;:::i;:::-;26622:97;26712:6;26672:38;26704:4;26698:11;26672:38;:::i;:::-;26666:4;26622:97;:::i;:::-;26768:4;26799:2;26788:14;;26816:1;26811:768;;;;27623:1;27640:6;27637:89;;;-1:-1:-1;27692:19:37;;;27686:26;27637:89;-1:-1:-1;;26315:1:37;26311:11;;;26307:84;26303:89;26293:100;26399:1;26395:11;;;26290:117;27739:81;;26781:1049;;26811:768;25611:1;25604:14;;;25648:4;25635:18;;-1:-1:-1;;26847:79:37;;;27024:222;27038:7;27035:1;27032:14;27024:222;;;27120:19;;;27114:26;27099:42;;27227:4;27212:20;;;;27180:1;27168:14;;;;27054:12;27024:222;;;27028:3;27274:6;27265:7;27262:19;27259:261;;;27335:19;;;27329:26;-1:-1:-1;;27418:1:37;27414:14;;;27430:3;27410:24;27406:97;27402:102;27387:118;27372:134;;27259:261;-1:-1:-1;;;;27566:1:37;27550:14;;;27546:22;27533:36;;-1:-1:-1;26418:1418:37:o
Swarm Source
ipfs://c77af930c048cc067948e17bd3ec8cf37d261dcd46a852d64d9267cf329b5db6
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in MON
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.