Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
StudioProV1
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 10000 runs
Other Settings:
shanghai EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.20;
import { StudioProV1Storage } from './StudioProV1Storage.sol';
import { BoostStorage } from './storages/BoostStorage.sol';
import { Initializable } from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol';
import { ERC20ScaleBoostUpgradeable } from './ERC20ScaleBoostUpgradeable.sol';
import { UUPSUpgradeable } from '@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol';
import { OwnableUpgradeable } from '@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol';
import { ERC1967Utils } from '@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol';
import { Modularity } from './Modularity.sol';
import { IStudioProV1Factory } from './interfaces/IStudioProV1Factory.sol';
import { IERC20 } from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import { InitializeModule } from './modules/InitializeModule.sol';
import { RiskManagementModule } from './modules/RiskManagementModule.sol';
import { ExecutesModule } from './modules/ExecutesModule.sol';
contract StudioProV1 is Initializable, UUPSUpgradeable, ERC20ScaleBoostUpgradeable, OwnableUpgradeable, Modularity {
// errors
error VAULT__SigNotFound(bytes4 sig);
error VAULT__AdapterNotFound(address adapter);
error UPGRADE__UpgradeNotReady();
error UPGRADE__InvalidUpgrade();
error UPGRADE__NotUpgradeable();
error UPGRADE__ImplementationNotExist();
// events
event NewProposedVaultUpgrade(address newImplementation, uint256 proposedTime);
///////////////////////////////////////////////////////////////////////////////////////////////
// CONSTRUCTOR, INIT, FALLBACKS //
///////////////////////////////////////////////////////////////////////////////////////////////
constructor(Modularity.Modules memory modules, address nativeWrapper) Modularity(modules, nativeWrapper) {
_disableInitializers();
}
function initialize(
string memory name_,
string memory symbol_,
InitializeModule.VaultParams memory vaultParams,
InitializeModule.FeeParams memory feeParams
) public useModuleWrite(MODULE_INITIALIZE) {}
///////////////////////////////////////////////////////////////////////////////////////////////
// Fallback //
///////////////////////////////////////////////////////////////////////////////////////////////
/// @notice Allows the contract to receive ETH
/// @dev This empty receive function is required to accept ETH transfers
receive() external payable {}
fallback() external {
if (!StudioProV1Storage.s().funcSelectors[msg.sig].isActive) revert VAULT__SigNotFound(msg.sig);
address adapter = StudioProV1Storage.s().funcSelectors[msg.sig].adapter;
if (adapter == address(0)) revert VAULT__AdapterNotFound(adapter);
assembly {
// copy function selector and any arguments
calldatacopy(0, 0, calldatasize())
// execute function call using the facet
let result := delegatecall(gas(), adapter, 0, calldatasize(), 0, 0)
// get any return value
returndatacopy(0, 0, returndatasize())
// return any return value or error back to the caller
switch result
case 0 {
revert(0, returndatasize())
}
default {
return(0, returndatasize())
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////
// Executes //
///////////////////////////////////////////////////////////////////////////////////////////////
function executeByManager(
address[] calldata adapters,
bytes[] calldata paramsList
) external payable useModuleWrite(MODULE_EXECUTIONS) {}
function executeByOwner(
address[] calldata adapters,
bytes[] calldata paramsList
) external payable useModuleWrite(MODULE_EXECUTIONS) {}
function executeBySelf(
address[] calldata adapters,
bytes[] calldata paramsList
) external payable useModuleWrite(MODULE_EXECUTIONS) {}
function executeByManagerAndRead(
address[] calldata adapters,
bytes[] calldata paramsList,
address[] calldata readAdapters,
bytes[] calldata readDatas
) external payable useModuleWrite(MODULE_EXECUTIONS) returns (ExecutesModule.Result[] memory results) {}
///////////////////////////////////////////////////////////////////////////////////////////////
// Deposit & Withdraw //
///////////////////////////////////////////////////////////////////////////////////////////////
function deposit(
address depositAsset,
uint256 amount,
address receiver
) public payable useModuleWrite(MODULE_DEPOSIT) returns (uint256) {}
function depositAndExecute(
address depositAsset,
uint256 amount,
address receiver
) public payable useModuleWrite(MODULE_DEPOSIT) returns (uint256 shares) {}
function depositWithPermit(
address depositAsset,
uint256 amount,
address receiver,
bytes calldata params
) public useModuleWrite(MODULE_DEPOSIT) returns (uint256) {}
function withdraw(
address withdrawAsset,
uint256 shares,
address receiver,
address owner
) public useModuleWrite(MODULE_WITHDRAW) returns (uint256) {}
function rawWithdraw(
uint256 shares,
address receiver,
address owner,
address[] calldata adapters,
bytes[] calldata paramsList,
bool[] calldata isWithdraw
) public useModuleWrite(MODULE_WITHDRAW) {}
///////////////////////////////////////////////////////////////////////////////////////////////
// Vault Metadata //
///////////////////////////////////////////////////////////////////////////////////////////////
function getDenominator() public view returns (address) {
return address(StudioProV1Storage.s().denominator);
}
function getUnderlyingAssets() public view returns (address[] memory) {
return StudioProV1Storage.s().underlyingAssets;
}
function getUnderlyingDebts() public view returns (address[] memory) {
return StudioProV1Storage.s().underlyingDebts;
}
function isUpgradeable() public view useModuleView(MODULE_RESOLVER) returns (bool) {}
function getTimelock() public view useModuleView(MODULE_RESOLVER) returns (uint256) {}
function getCooldownTime() public view useModuleView(MODULE_RESOLVER) returns (uint256) {}
function getFactory() external view useModuleView(MODULE_RESOLVER) returns (address) {}
function version() public pure returns (string memory) {
return '1.0';
}
///////////////////////////////////////////////////////////////////////////////////////////////
// Roles //
///////////////////////////////////////////////////////////////////////////////////////////////
function addManager(address manager) public useModuleWrite(MODULE_ROLES) {}
function removeManager(address manager) public useModuleWrite(MODULE_ROLES) {}
function setRiskManager(address manager) public useModuleWrite(MODULE_ROLES) {}
function isManager(address manager) public view useModuleView(MODULE_RESOLVER) returns (bool) {}
///////////////////////////////////////////////////////////////////////////////////////////////
// Fees //
///////////////////////////////////////////////////////////////////////////////////////////////
function setDepositFee(uint256 depositFee) public useModuleWrite(MODULE_FEES) {}
function setWithdrawFee(uint256 withdrawFee) public useModuleWrite(MODULE_FEES) {}
function chargePerformanceFee() public useModuleWrite(MODULE_FEES) {}
function setPerformanceFee(uint256 performanceFee) public useModuleWrite(MODULE_FEES) {}
function setManagementFee(uint256 managementFee) public useModuleWrite(MODULE_FEES) {}
function setFeeReceiver(address feeReceiver) public useModuleWrite(MODULE_FEES) {}
///////////////////////////////////////////////////////////////////////////////////////////////
// Vault Value //
///////////////////////////////////////////////////////////////////////////////////////////////
function getAssetDebtValue()
public
view
useModuleView(MODULE_VAULT_VALUE)
returns (uint256 totalAsset, uint256 totalDebt)
{}
function getNetVaultValue() public view useModuleView(MODULE_VAULT_VALUE) returns (uint256) {}
function getNetVaultValueInAsset(address asset) public view useModuleView(MODULE_VAULT_VALUE) returns (uint256) {}
function getTotalAssetValue() public view useModuleView(MODULE_VAULT_VALUE) returns (uint256) {}
function getTotalDebtValue() public view useModuleView(MODULE_VAULT_VALUE) returns (uint256) {}
function getAssetValueByAmount(
address asset,
uint256 amount
) public view useModuleView(MODULE_VAULT_VALUE) returns (uint256) {}
///////////////////////////////////////////////////////////////////////////////////////////////
// Wrapper Uniswap V3 //
///////////////////////////////////////////////////////////////////////////////////////////////
function getNftToWrapper(uint256 tokenId) public view returns (address) {
return StudioProV1Storage.s().nftToWrapper[tokenId];
}
function getWrapperToNft(address wrapper) public view returns (uint256) {
return StudioProV1Storage.s().wrapperToNft[wrapper];
}
///////////////////////////////////////////////////////////////////////////////////////////////
// Risk Management //
///////////////////////////////////////////////////////////////////////////////////////////////
function getCumulativePriceDeviationAllowance()
public
view
useModuleView(MODULE_RISK_MANAGEMENT)
returns (uint256)
{}
function getDailyPriceDeviation() public view useModuleView(MODULE_RISK_MANAGEMENT) returns (uint256) {}
function setCumulativePriceDeviationAllowance(uint256 newAllowance) public useModuleWrite(MODULE_RISK_MANAGEMENT) {}
function getMaxCap() external view useModuleView(MODULE_RISK_MANAGEMENT) returns (uint256) {}
function getMaxDebtRatio() external view useModuleView(MODULE_RISK_MANAGEMENT) returns (uint256) {}
function setMaxCap(uint256 maxCap) external useModuleWrite(MODULE_RISK_MANAGEMENT) {}
function setMaxDebtRatio(uint256 maxDebtRatio) external useModuleWrite(MODULE_RISK_MANAGEMENT) {}
///////////////////////////////////////////////////////////////////////////////////////////////
// Fees //
///////////////////////////////////////////////////////////////////////////////////////////////
function getFeeReceiver() public view useModuleView(MODULE_RESOLVER) returns (address) {}
function getDepositFee() public view useModuleView(MODULE_RESOLVER) returns (uint256) {}
function getWithdrawFee() public view useModuleView(MODULE_RESOLVER) returns (uint256) {}
function getPerformanceFee() public view useModuleView(MODULE_RESOLVER) returns (uint256) {}
function getManagementFee() public view useModuleView(MODULE_RESOLVER) returns (uint256) {}
///////////////////////////////////////////////////////////////////////////////////////////////
// ERC4626 //
///////////////////////////////////////////////////////////////////////////////////////////////
function asset() public view useModuleView(MODULE_ERC4626) returns (address) {}
function totalAssets() external view useModuleView(MODULE_ERC4626) returns (uint256 totalManagedAssets) {}
function convertToShares(uint256 assets) external view useModuleView(MODULE_ERC4626) returns (uint256 shares) {}
function convertToAssets(uint256 shares) external view useModuleView(MODULE_ERC4626) returns (uint256 assets) {}
function maxDeposit(address receiver) external view useModuleView(MODULE_ERC4626) returns (uint256 maxAssets) {}
function previewDeposit(uint256 assets) external view useModuleView(MODULE_ERC4626) returns (uint256 shares) {}
function deposit(
uint256 assets,
address receiver
) external useModuleWrite(MODULE_ERC4626) returns (uint256 shares) {}
function maxMint(address receiver) external view useModuleView(MODULE_ERC4626) returns (uint256 maxShares) {}
function previewMint(uint256 shares) external view useModuleView(MODULE_ERC4626) returns (uint256 assets) {}
function mint(uint256 shares, address receiver) external useModuleWrite(MODULE_ERC4626) returns (uint256 assets) {}
function maxWithdraw(address owner) external view useModuleView(MODULE_ERC4626) returns (uint256 maxAssets) {}
function previewWithdraw(uint256 assets) external view useModuleView(MODULE_ERC4626) returns (uint256 shares) {}
function withdraw(
uint256 assets,
address receiver,
address owner
) external useModuleWrite(MODULE_ERC4626) returns (uint256 shares) {}
function maxRedeem(address owner) external view useModuleView(MODULE_ERC4626) returns (uint256 maxShares) {}
function previewRedeem(uint256 shares) external view useModuleView(MODULE_ERC4626) returns (uint256 assets) {}
function redeem(
uint256 shares,
address receiver,
address owner
) external useModuleWrite(MODULE_ERC4626) returns (uint256 assets) {}
///////////////////////////////////////////////////////////////////////////////////////////////
// Deposit Policy //
///////////////////////////////////////////////////////////////////////////////////////////////
function isDepositWhitelistEnabled() public view useModuleView(MODULE_RESOLVER) returns (bool) {}
function isDepositMinimumEnabled() public view useModuleView(MODULE_RESOLVER) returns (bool) {}
function getDepositMinimum(address asset) public view useModuleView(MODULE_RESOLVER) returns (uint256) {}
function isDepositorWhitelisted(address depositor) public view useModuleView(MODULE_RESOLVER) returns (bool) {}
///////////////////////////////////////////////////////////////////////////////////////////////
// Resolver //
///////////////////////////////////////////////////////////////////////////////////////////////
function estimateRawWithdrawEndState(
uint256 shares
)
public
virtual
useModuleView(MODULE_RESOLVER)
returns (uint256, uint256, address[] memory, uint256[] memory, address[] memory, uint256[] memory)
{}
function estimateRawWithdrawExpectedAmount(
uint256 shares
)
public
useModuleView(MODULE_RESOLVER)
returns (uint256, uint256, address[] memory, uint256[] memory, address[] memory, uint256[] memory)
{}
function isDirectWithdraw(
address withdrawAsset,
uint256 shares
) public view useModuleView(MODULE_RESOLVER) returns (bool) {}
function getDebtRatio() public virtual useModuleView(MODULE_RESOLVER) returns (uint256) {}
function isDepositAsset(address asset) public view useModuleView(MODULE_RESOLVER) returns (bool) {}
function isWithdrawAsset(address asset) public view useModuleView(MODULE_RESOLVER) returns (bool) {}
function isUnderlyingAsset(address asset) public view useModuleView(MODULE_RESOLVER) returns (bool) {}
function isUnderlyingDebt(address asset) public view useModuleView(MODULE_RESOLVER) returns (bool) {}
function getDenominatorBalance() public view useModuleView(MODULE_RESOLVER) returns (uint256) {}
function getUnderlyingAssetsBalance() public view useModuleView(MODULE_RESOLVER) returns (uint256[] memory) {}
function getUnderlyingDebtsBalance() public view useModuleView(MODULE_RESOLVER) returns (uint256[] memory) {}
function getUnderlyingAssetBalance(address asset) public view useModuleView(MODULE_RESOLVER) returns (uint256) {}
function getUnderlyingDebtBalance(address debt) public view useModuleView(MODULE_RESOLVER) returns (uint256) {}
function getPricePerShare() public view useModuleView(MODULE_RESOLVER) returns (uint256) {}
function getAssetAccounting(address asset) public view useModuleView(MODULE_RESOLVER) returns (address) {}
function getDebtAccounting(address asset) public view useModuleView(MODULE_RESOLVER) returns (address) {}
function isManagerAdapter(address asset) public view useModuleView(MODULE_RESOLVER) returns (bool) {}
function isOwnerAdapter(address asset) public view useModuleView(MODULE_RESOLVER) returns (bool) {}
function readFromStorage(bytes32 slot) public view useModuleView(MODULE_RESOLVER) returns (bytes32) {}
function previewDeposit(
address depositAsset,
uint256 amount
) public view useModuleView(MODULE_RESOLVER) returns (uint256) {}
function previewWithdraw(
address withdrawAsset,
uint256 shares
) public view useModuleView(MODULE_RESOLVER) returns (uint256) {}
///////////////////////////////////////////////////////////////////////////////////////////////
// Strategy //
///////////////////////////////////////////////////////////////////////////////////////////////
function executePublicStrategy(uint256 id) external useModuleWrite(MODULE_STRATEGY) {}
function setDepositStrategy(
address[] memory adapters,
bytes[] memory params
) external useModuleWrite(MODULE_STRATEGY) {}
function setPublicStrategy(
uint256 id,
address[] memory adapters,
bytes[] memory params
) external useModuleWrite(MODULE_STRATEGY) {}
function removePublicStrategy(uint256 id) external useModuleWrite(MODULE_STRATEGY) {}
function removeDepositStrategy() external useModuleWrite(MODULE_STRATEGY) {}
///////////////////////////////////////////////////////////////////////////////////////////////
// Scale //
///////////////////////////////////////////////////////////////////////////////////////////////
function activeBalance(address user) public view override useModuleView(MODULE_SCALEBOOST) returns (uint256) {}
function totalActiveSupply() public view override useModuleView(MODULE_SCALEBOOST) returns (uint256) {}
function getRewardTokens() external view useModuleView(MODULE_SCALEBOOST) returns (address[] memory) {}
function redeemRewards(address user) external useModuleWrite(MODULE_SCALEBOOST) returns (uint256[] memory) {}
function redeemRewardsAndGetReward(address user) external useModuleWrite(MODULE_SCALEBOOST) {}
///////////////////////////////////////////////////////////////////////////////////////////////
// Boost //
///////////////////////////////////////////////////////////////////////////////////////////////
function getAllRewardTokens() external view useModuleView(MODULE_SCALEBOOST) returns (address[] memory) {
return _getAllRewardTokens();
}
function boostMinAmount(address _rewardsToken) external view useModuleView(MODULE_SCALEBOOST) returns (uint256) {}
function getRewardTokensCount() external view useModuleView(MODULE_SCALEBOOST) returns (uint256) {
return _getRewardTokensCount();
}
function rewardDuration() external view useModuleView(MODULE_SCALEBOOST) returns (uint256) {}
function userRewardPerTokenPaid(
address _user,
address _rewardsToken
) external view useModuleView(MODULE_SCALEBOOST) returns (uint256) {}
function rewardData(
address _rewardsToken
) external view useModuleView(MODULE_SCALEBOOST) returns (BoostStorage.Reward memory) {}
function lastTimeRewardApplicable(
address _rewardsToken
) external view useModuleView(MODULE_SCALEBOOST) returns (uint256) {}
function rewardPerToken(address _rewardsToken) external view useModuleView(MODULE_SCALEBOOST) returns (uint256) {}
function earned(
address account,
address _rewardsToken
) external view useModuleView(MODULE_SCALEBOOST) returns (uint256) {}
function getRewardForDuration(
address _rewardsToken
) external view useModuleView(MODULE_SCALEBOOST) returns (uint256) {}
function redeemBoostReward(address user, address[] calldata rewardTokens) external {
_redeemBoostReward(user, rewardTokens);
}
function redeemBoostRewardAll(address user) external useModuleWrite(MODULE_SCALEBOOST) {}
function notifyRewardAmount(address _rewardsToken, uint256 reward) external useModuleWrite(MODULE_SCALEBOOST) {}
///////////////////////////////////////////////////////////////////////////////////////////////
// Upgrades //
///////////////////////////////////////////////////////////////////////////////////////////////
function proposeVaultUpgrade(address newImplementation) public onlyOwner {
if (!StudioProV1Storage.s().upgradeable) revert UPGRADE__NotUpgradeable();
if (
!IStudioProV1Factory(StudioProV1Storage.s().factory).isRegisteredUpgrade(
ERC1967Utils.getImplementation(),
newImplementation
)
) revert UPGRADE__ImplementationNotExist();
StudioProV1Storage.s().proposedVaultImplementation = newImplementation;
StudioProV1Storage.s().proposedVaultUpgradeTime = block.timestamp;
emit NewProposedVaultUpgrade(newImplementation, block.timestamp);
}
function _authorizeUpgrade(address newImplementation) internal view override onlyOwner {
if (!StudioProV1Storage.s().upgradeable) revert UPGRADE__NotUpgradeable();
if (StudioProV1Storage.s().proposedVaultUpgradeTime + StudioProV1Storage.s().upgradeTimelock > block.timestamp)
revert UPGRADE__UpgradeNotReady();
if (StudioProV1Storage.s().proposedVaultImplementation != newImplementation) revert UPGRADE__InvalidUpgrade();
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
library StudioProV1Storage {
struct SelectorAdapter {
bool isActive;
address adapter;
}
struct Strategy {
address[] adapters;
bytes[] params;
}
struct StudioProV1DS {
// Vault configuration
address factory;
bool upgradeable;
uint256 upgradeTimelock;
uint256 cooldownTime;
IERC20 denominator;
address denominatorAccounting;
// Assets and debts
address[] underlyingAssets;
address[] underlyingDebts;
mapping(address => bool) depositAssetsMapping;
mapping(address => bool) underlyingAssetsMapping;
mapping(address => bool) underlyingDebtsMapping;
// accounting
mapping(address => address) assetAccountings;
mapping(address => address) debtAccountings;
// Managers and adapters
mapping(address => bool) isManager;
mapping(address => bool) withdrawAssetsMapping;
mapping(address => bool) managerAdapters;
mapping(address => bool) ownerAdapters;
mapping(address => bool) withdrawAdapters;
// roles
address riskManager;
// Function selectors and adapters
mapping(bytes4 => SelectorAdapter) funcSelectors;
// fees
uint256 depositFee;
uint256 withdrawFee;
uint256 performanceFee;
uint256 managementFee;
uint256 highWatermark;
uint256 lastFeeChargeTime;
address feeReceiver;
// User data
mapping(address => uint256) lastDepositTime;
// upgrades
address proposedVaultImplementation;
uint256 proposedVaultUpgradeTime;
// Price deviation tracking
uint256 dailyPriceDeviationBps;
uint256 lastPriceDeviationResetTime;
uint256 cumulativePriceDeviationAllowanceBps;
// cap
uint256 maxCap;
uint256 maxDebtRatio;
// simulation
bool isSimulation;
// wrapper
mapping(uint256 => address) nftToWrapper;
mapping(address => uint256) wrapperToNft;
// strategy
Strategy depositStrategy;
mapping(uint256 => Strategy) publicStrategies;
}
// keccak256(abi.encode(uint256(keccak256("factordao.studio.pro.vault")) - 1)) & bytes32(uint256(0xff))
bytes32 private constant STORAGE_SLOT = 0xeb5bb3420d9366368c64688d6df836957f2c655b917ed6671c4a93199009bc00;
function s() internal pure returns (StudioProV1DS storage ds) {
bytes32 slot = STORAGE_SLOT;
assembly {
ds.slot := slot
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import '@openzeppelin/contracts/utils/structs/EnumerableSet.sol';
library BoostStorage {
using EnumerableSet for EnumerableSet.AddressSet;
struct Reward {
uint256 periodFinish;
uint256 rewardRate;
uint256 lastUpdateTime;
uint256 rewardPerTokenStored;
}
struct BoostDS {
uint256 rewardDuration;
mapping(address => Reward) rewardData;
// user -> reward token -> amount
mapping(address => mapping(address => uint256)) userRewardPerTokenPaid;
mapping(address => mapping(address => uint256)) rewards;
mapping(address => bool) whitelisted;
EnumerableSet.AddressSet rewardTokens;
mapping(address => uint256) minAmount;
}
// keccak256(abi.encode(uint256(keccak256("factordao.studio.pro.module.boost")) - 1)) & bytes32(uint256(0xff))
bytes32 private constant STORAGE_SLOT = 0x0437d4a732399ef7f2c8fca6343f4e97d989d30f9900ddd012da8b53d6c89000;
function s() internal pure returns (BoostDS storage ds) {
bytes32 slot = STORAGE_SLOT;
assembly {
ds.slot := slot
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.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 reininitialization) 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 Returns a pointer to the storage namespace.
*/
// solhint-disable-next-line var-name-mixedcase
function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
assembly {
$.slot := INITIALIZABLE_STORAGE
}
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.20;
import { Initializable } from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol';
import { ERC20Upgradeable } from '@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol';
import { FactorGauge } from '../../scale/FactorGauge.sol';
import { FactorBoost } from './FactorBoost.sol';
abstract contract ERC20ScaleBoostUpgradeable is Initializable, ERC20Upgradeable, FactorGauge, FactorBoost {
function __ERC20ScaleBoost_init(
string memory name_,
string memory symbol_,
address _veFctr,
address _gaugeController,
uint256 _rewardDuration
) internal onlyInitializing {
__ERC20_init(name_, symbol_);
__FactorGauge_init(_veFctr, _gaugeController);
__FactorBoost_init(_rewardDuration);
}
function _stakedBalance(address user) internal view override(FactorGauge, FactorBoost) returns (uint256) {
return balanceOf(user);
}
function _totalStaked() internal view override(FactorGauge, FactorBoost) returns (uint256) {
return totalSupply();
}
function _beforeTokenTransfer(
address from,
address to,
uint256 amount
) internal override(FactorGauge, FactorBoost) {
FactorGauge._beforeTokenTransfer(from, to, amount);
FactorBoost._beforeTokenTransfer(from, to, amount);
}
function _afterTokenTransfer(address from, address to, uint256 amount) internal override(FactorGauge) {
FactorGauge._afterTokenTransfer(from, to, amount);
}
function _update(address from, address to, uint256 amount) internal override {
FactorGauge._beforeTokenTransfer(from, to, amount);
FactorBoost._beforeTokenTransfer(from, to, amount);
super._update(from, to, amount);
FactorGauge._afterTokenTransfer(from, to, amount);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/UUPSUpgradeable.sol)
pragma solidity ^0.8.20;
import {IERC1822Proxiable} from "@openzeppelin/contracts/interfaces/draft-IERC1822.sol";
import {ERC1967Utils} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol";
import {Initializable} from "./Initializable.sol";
/**
* @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
* {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
*
* A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
* reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
* `UUPSUpgradeable` with a custom implementation of upgrades.
*
* The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
*/
abstract contract UUPSUpgradeable is Initializable, 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 ERC1967) pointing to self. This should only be the case
* for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
* function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
* fail.
*/
modifier onlyProxy() {
_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();
_;
}
function __UUPSUpgradeable_init() internal onlyInitializing {
}
function __UUPSUpgradeable_init_unchained() internal onlyInitializing {
}
/**
* @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the
* implementation. It is used to validate the implementation's compatibility when performing an upgrade.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
*/
function proxiableUUID() external view virtual 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 ERC1967-compliant implementation pointing to self.
* See {_onlyProxy}.
*/
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 ERC1967.
*
* 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: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
/// @custom:storage-location erc7201:openzeppelin.storage.Ownable
struct OwnableStorage {
address _owner;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300;
function _getOwnableStorage() private pure returns (OwnableStorage storage $) {
assembly {
$.slot := OwnableStorageLocation
}
}
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
function __Ownable_init(address initialOwner) internal onlyInitializing {
__Ownable_init_unchained(initialOwner);
}
function __Ownable_init_unchained(address initialOwner) internal onlyInitializing {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
OwnableStorage storage $ = _getOwnableStorage();
return $._owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
OwnableStorage storage $ = _getOwnableStorage();
address oldOwner = $._owner;
$._owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Utils.sol)
pragma solidity ^0.8.20;
import {IBeacon} from "../beacon/IBeacon.sol";
import {Address} from "../../utils/Address.sol";
import {StorageSlot} from "../../utils/StorageSlot.sol";
/**
* @dev This abstract contract provides getters and event emitting update functions for
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
*/
library ERC1967Utils {
// We re-declare ERC-1967 events here because they can't be used directly from IERC1967.
// This will be fixed in Solidity 0.8.21. At that point we should remove these events.
/**
* @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);
/**
* @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 EIP1967 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 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 EIP1967) 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 EIP1967 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 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 EIP1967 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 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: BUSL-1.1
pragma solidity ^0.8.17;
abstract contract Modularity {
error MODULARITY_NotSelf();
struct Modules {
address initialize;
address deposit;
address withdraw;
address roles;
address fees;
address executions;
address vaultValue;
address resolver;
address erc4626;
address scaleBoost;
address riskManagement;
address strategy;
}
address public immutable MODULE_INITIALIZE;
address public immutable MODULE_DEPOSIT;
address public immutable MODULE_WITHDRAW;
address public immutable MODULE_ROLES;
address public immutable MODULE_FEES;
address public immutable MODULE_EXECUTIONS;
address public immutable MODULE_VAULT_VALUE;
address public immutable MODULE_RESOLVER;
address public immutable MODULE_ERC4626;
address public immutable MODULE_SCALEBOOST;
address public immutable nativeWrapper;
address public immutable MODULE_RISK_MANAGEMENT;
address public immutable MODULE_STRATEGY;
/**
* @notice Initializes the Modularity contract with module addresses and native wrapper
*/
constructor(Modules memory modules, address _nativeWrapper) {
MODULE_INITIALIZE = modules.initialize;
MODULE_DEPOSIT = modules.deposit;
MODULE_WITHDRAW = modules.withdraw;
MODULE_ROLES = modules.roles;
MODULE_FEES = modules.fees;
MODULE_EXECUTIONS = modules.executions;
MODULE_VAULT_VALUE = modules.vaultValue;
MODULE_RESOLVER = modules.resolver;
MODULE_ERC4626 = modules.erc4626;
MODULE_SCALEBOOST = modules.scaleBoost;
nativeWrapper = _nativeWrapper;
MODULE_RISK_MANAGEMENT = modules.riskManagement;
MODULE_STRATEGY = modules.strategy;
}
/**
* @notice Modifier to execute a function and then delegate to a module
* @dev This modifier is used to execute a function and then delegate the result to a specific module.
* @param module The address of the module to delegate to.
*/
modifier useModuleWrite(address module) {
_;
delegateToModule(module);
}
/**
* @notice Modifier to execute a view function and then delegate to a module
*/
modifier useModuleView(address module) {
_;
delegateToModuleView(module);
}
/**
* @notice Delegates a view call to the contract itself
* @dev This function works as follows:
* 1. It checks if the caller is the contract itself
* 2. If not, it reverts with a MODULARITY_NotSelf error
* 3. If the caller is the contract, it executes a delegatecall with the provided calldata
* 4. The result of the delegatecall is then returned or reverted based on its success
*/
function delegateView() external payable {
if (msg.sender != address(this)) revert MODULARITY_NotSelf();
assembly {
let size := sub(calldatasize(), 36)
calldatacopy(0, 36, size)
let result := delegatecall(gas(), calldataload(4), 0, size, 0, 0)
returndatacopy(0, 0, returndatasize())
switch result
case 0 {
revert(0, returndatasize())
}
default {
return(0, returndatasize())
}
}
}
/**
* @notice Delegates a view call to a specific module
* @dev because no delegatecall view so we need to use staticcall
*/
function delegateToModuleView(address module) private view {
// [signature of viewDelegate 4B] + [module address 32B] + [original calldata]
// 0-4 bytes = viewDelegate() signature -> 0x535c370c
// 4-36 bytes = module address
// > 36 = original calldata
assembly {
mstore(0, 0x535c370c00000000000000000000000000000000000000000000000000000000)
mstore(4, module)
calldatacopy(36, 0, calldatasize())
// Calldatasize + 36 (signature and module address)
let result := staticcall(gas(), address(), 0, add(calldatasize(), 36), 0, 0)
returndatacopy(0, 0, returndatasize())
switch result
case 0 {
revert(0, returndatasize())
}
default {
return(0, returndatasize())
}
}
}
/**
* @notice Delegates a call to a specific module
*/
function delegateToModule(address module) private {
assembly {
calldatacopy(0, 0, calldatasize())
let result := delegatecall(gas(), module, 0, calldatasize(), 0, 0)
returndatacopy(0, 0, returndatasize())
switch result
case 0 {
revert(0, returndatasize())
}
default {
return(0, returndatasize())
}
}
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.17;
interface IStudioProV1Factory {
function getProtocolFee() external view returns (address, uint256, uint256);
function isRegisteredUpgrade(address, address) external view returns (bool);
function isAsset(address asset, address assetAccounting) external view returns (bool);
function isDebt(address debt, address debtAccounting) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.17;
import { StudioProV1Storage } from '../StudioProV1Storage.sol';
import { Initializable } from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol';
import { ERC20ScaleBoostUpgradeable } from '../ERC20ScaleBoostUpgradeable.sol';
import { ReentrancyGuardUpgradeable } from '@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol';
import { OwnableUpgradeable } from '@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol';
import { IERC20 } from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
contract InitializeModule is Initializable, ReentrancyGuardUpgradeable, ERC20ScaleBoostUpgradeable, OwnableUpgradeable {
uint256 private constant FEE_SCALE = 1e18;
error INITIALIZE__InvalidAssetAndAcountingLength(uint256 assetLength, uint256 accountingLength);
error INITIALIZE__InvalidDebtAndAcountingLength(uint256 debtLength, uint256 accountingLength);
error INITIALIZE__DepositFeeExceedMax(uint256 depositFee);
error INITIALIZE__WithdrawFeeExceedMax(uint256 withdrawFee);
error INITIALIZE__PerformanceFeeExceedMax(uint256 performanceFee);
error INITIALIZE__ManagementFeeExceedMax(uint256 managementFee);
error INITIALIZE__DenominatorNotExistInAsset(address denominator);
error INITIALIZE__DenominatorNotExistInDepositAsset(address denominator);
error INITIALIZE__DepositAssetNotExistInAsset(address depositAsset);
error INITIALIZE__WithdrawAssetNotExistInAsset(address withdrawAsset);
error INITIALIZE__DebtRatioExceedMax(uint256 maxDebtRatio);
// Structs
struct VaultParams {
address denominator;
address denominatorAccounting;
uint256 upgradeTimelock;
uint256 cooldownTime;
bool upgradeable;
uint256 maxCap;
uint256 maxDebtRatio;
uint256 cumulativePriceDeviationAllowanceBps;
address[] initialAssets;
address[] initialDepositAssets;
address[] initialWithdrawAssets;
address[] initialDebts;
address[] initialAssetAccountings;
address[] initialDebtAccountings;
address[] initialManagerAdapters;
address[] initialOwnerAdapters;
address[] initialWithdrawAdapters;
}
struct FeeParams {
address feeReceiver;
uint256 depositFee;
uint256 withdrawFee;
uint256 performanceFee;
uint256 managementFee;
}
address public immutable GAUGE_CONTROLLER;
address public immutable VE_TOKEN;
uint256 public immutable BOOST_DURATION;
///////////////////////////////////////////////////////////////////////////////////////////////
// CONSTRUCTOR, INIT, FALLBACKS //
///////////////////////////////////////////////////////////////////////////////////////////////
constructor(address _veToken, address _gaugeController) {
VE_TOKEN = _veToken;
GAUGE_CONTROLLER = _gaugeController;
BOOST_DURATION = 7 days;
_disableInitializers();
}
/**
* @dev Initializes the contract with provided parameters.
* @notice This function performs the following steps:
* 1. Initializes ERC20ScaleBoost with provided name, symbol, and other parameters.
* 2. Initializes Ownable with the message sender as the owner.
* 3. Initializes ReentrancyGuard.
* 4. Calls _initializeVault to set up the vault with provided parameters.
*/
function initialize(
string memory name_,
string memory symbol_,
VaultParams memory vaultParams,
FeeParams memory feeParams
) public virtual initializer {
__ERC20ScaleBoost_init(name_, symbol_, VE_TOKEN, GAUGE_CONTROLLER, BOOST_DURATION);
__Ownable_init(msg.sender);
__ReentrancyGuard_init();
_initializeVault(vaultParams, feeParams);
}
///////////////////////////////////////////////////////////////////////////////////////////////
// INTERNAL FUNCTIONS //
///////////////////////////////////////////////////////////////////////////////////////////////
/**
* @dev Initializes the vault with provided parameters.
* @notice This function performs the following steps:
* 1. If the vault is not upgradeable, sets the upgrade timelock to the maximum possible value.
* 2. Sets various vault parameters including timelock, factory, cooldown time, denominator, and others.
* 3. Sets the message sender as a manager and risk manager. The Factory will transfer the ownership later.
* 4. Sets price deviation allowance and caps.
* 5. Initializes assets, deposit assets, withdraw assets, debts, adapters, and fees.
*/
function _initializeVault(VaultParams memory vaultParams, FeeParams memory feeParams) internal {
StudioProV1Storage.StudioProV1DS storage $ = StudioProV1Storage.s();
// non upgradeable the timelock should be max/unlimited
if (vaultParams.upgradeable == false) vaultParams.upgradeTimelock = type(uint256).max;
$.upgradeTimelock = vaultParams.upgradeTimelock;
$.factory = msg.sender;
$.cooldownTime = vaultParams.cooldownTime;
$.denominator = IERC20(vaultParams.denominator);
$.denominatorAccounting = vaultParams.denominatorAccounting;
$.isManager[msg.sender] = true;
$.riskManager = msg.sender;
$.upgradeable = vaultParams.upgradeable;
// price deviation
$.cumulativePriceDeviationAllowanceBps = vaultParams.cumulativePriceDeviationAllowanceBps;
// caps
$.maxCap = vaultParams.maxCap;
if (vaultParams.maxDebtRatio > 1e18) revert INITIALIZE__DebtRatioExceedMax(vaultParams.maxDebtRatio);
$.maxDebtRatio = vaultParams.maxDebtRatio;
_initializeAssets(vaultParams.initialAssets, vaultParams.initialAssetAccountings);
_initializeDepositAssets(vaultParams.initialDepositAssets);
_initializeWithdrawAssets(vaultParams.initialWithdrawAssets);
_initializeDebts(vaultParams.initialDebts, vaultParams.initialDebtAccountings);
_initializeAdapters(
vaultParams.initialManagerAdapters,
vaultParams.initialOwnerAdapters,
vaultParams.initialWithdrawAdapters
);
_initializeFees(
feeParams.feeReceiver,
feeParams.depositFee,
feeParams.withdrawFee,
feeParams.performanceFee,
feeParams.managementFee
);
}
/**
* @dev Initializes the assets for the vault.
* @notice This function performs the following steps:
* 1. Checks if the length of initialAssets matches initialAssetAccountings.
* 2. Iterates through the initialAssets array:
* a. Adds each asset to the underlyingAssets array.
* b. Sets the underlyingAssetsMapping for each asset to true.
* c. Sets the assetAccountings for each asset.
* 3. Validates if the denominator exists in the assets.
*/
function _initializeAssets(address[] memory initialAssets, address[] memory initialAssetAccountings) internal {
if (initialAssets.length != initialAssetAccountings.length)
revert INITIALIZE__InvalidAssetAndAcountingLength(initialAssets.length, initialAssetAccountings.length);
StudioProV1Storage.StudioProV1DS storage $ = StudioProV1Storage.s();
for (uint256 i = 0; i < initialAssets.length; i++) {
$.underlyingAssets.push(initialAssets[i]);
$.underlyingAssetsMapping[initialAssets[i]] = true;
$.assetAccountings[initialAssets[i]] = initialAssetAccountings[i];
}
// validate if denominator exist in asset
if (!$.underlyingAssetsMapping[address($.denominator)])
revert INITIALIZE__DenominatorNotExistInAsset(address($.denominator));
// update denominator accounting
$.denominatorAccounting = $.assetAccountings[address($.denominator)];
}
/**
* @dev Initializes the debts for the vault.
* @notice This function performs the following steps:
* 1. Checks if the length of initialDebts matches initialDebtAccountings.
* 2. Iterates through the initialDebts array:
* a. Adds each debt to the underlyingDebts array.
* b. Sets the underlyingDebtsMapping for each debt to true.
* c. Sets the debtAccountings for each debt.
*/
function _initializeDebts(address[] memory initialDebts, address[] memory initialDebtAccountings) internal {
if (initialDebts.length != initialDebtAccountings.length)
revert INITIALIZE__InvalidDebtAndAcountingLength(initialDebts.length, initialDebtAccountings.length);
StudioProV1Storage.StudioProV1DS storage $ = StudioProV1Storage.s();
for (uint256 i = 0; i < initialDebts.length; i++) {
$.underlyingDebts.push(initialDebts[i]);
$.underlyingDebtsMapping[initialDebts[i]] = true;
$.debtAccountings[initialDebts[i]] = initialDebtAccountings[i];
}
}
/**
* @dev Initializes the deposit assets for the vault.
* @notice This function performs the following steps:
* 1. Iterates through the initialDepositAssets array:
* a. Sets the depositAssetsMapping for each asset to true.
* b. Checks if the deposit asset exists in the assets.
* 2. Validates if the denominator exists in the deposit assets.
*/
function _initializeDepositAssets(address[] memory initialDepositAssets) internal {
StudioProV1Storage.StudioProV1DS storage $ = StudioProV1Storage.s();
for (uint256 i = 0; i < initialDepositAssets.length; i++) {
address depositAsset = initialDepositAssets[i];
if (!$.underlyingAssetsMapping[depositAsset]) revert INITIALIZE__DepositAssetNotExistInAsset(depositAsset);
$.depositAssetsMapping[depositAsset] = true;
}
// validate if denominator exist in depositAssets
if (!$.depositAssetsMapping[address($.denominator)])
revert INITIALIZE__DenominatorNotExistInDepositAsset(address($.denominator));
}
/**
* @dev Initializes the withdraw assets for the vault.
* @notice This function performs the following step:
* 1. Iterates through the initialWithdrawAssets array:
* a. Sets the withdrawAssetsMapping for each asset to true.
*/
function _initializeWithdrawAssets(address[] memory initialWithdrawAssets) internal {
StudioProV1Storage.StudioProV1DS storage $ = StudioProV1Storage.s();
for (uint256 i = 0; i < initialWithdrawAssets.length; i++) {
address withdrawAsset = initialWithdrawAssets[i];
if (!$.underlyingAssetsMapping[withdrawAsset])
revert INITIALIZE__WithdrawAssetNotExistInAsset(withdrawAsset);
$.withdrawAssetsMapping[withdrawAsset] = true;
}
}
/**
* @dev Initializes the adapters for the vault.
* @notice This function performs the following steps:
* 1. Iterates through the initialManagerAdapters array:
* a. Sets the managerAdapters mapping for each adapter to true.
* 2. Iterates through the initialOwnerAdapters array:
* a. Sets the ownerAdapters mapping for each adapter to true.
* 3. Iterates through the initialWithdrawAdapters array:
* a. Sets the withdrawAdapters mapping for each adapter to true.
*/
function _initializeAdapters(
address[] memory initialManagerAdapters,
address[] memory initialOwnerAdapters,
address[] memory initialWithdrawAdapters
) internal {
StudioProV1Storage.StudioProV1DS storage $ = StudioProV1Storage.s();
for (uint256 i = 0; i < initialManagerAdapters.length; i++) {
$.managerAdapters[initialManagerAdapters[i]] = true;
}
for (uint256 i = 0; i < initialOwnerAdapters.length; i++) {
$.ownerAdapters[initialOwnerAdapters[i]] = true;
}
for (uint256 i = 0; i < initialWithdrawAdapters.length; i++) {
$.withdrawAdapters[initialWithdrawAdapters[i]] = true;
}
}
/**
* @dev Initializes the fees for the vault.
* @notice This function performs the following steps:
* 1. Validates that each fee does not exceed the maximum allowed (FEE_SCALE).
* 2. Sets the fee receiver and various fee rates in the storage.
*/
function _initializeFees(
address _feeReceiver,
uint256 _depositFee,
uint256 _withdrawFee,
uint256 _performanceFee,
uint256 _managementFee
) internal {
// validate not more than max fee
if (_depositFee > FEE_SCALE) revert INITIALIZE__DepositFeeExceedMax(_depositFee);
if (_withdrawFee > FEE_SCALE) revert INITIALIZE__WithdrawFeeExceedMax(_withdrawFee);
if (_performanceFee > FEE_SCALE) revert INITIALIZE__PerformanceFeeExceedMax(_performanceFee);
if (_managementFee > FEE_SCALE) revert INITIALIZE__ManagementFeeExceedMax(_managementFee);
StudioProV1Storage.StudioProV1DS storage $ = StudioProV1Storage.s();
$.feeReceiver = _feeReceiver;
$.depositFee = _depositFee;
$.withdrawFee = _withdrawFee;
$.performanceFee = _performanceFee;
$.managementFee = _managementFee;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import { StudioProV1Storage } from '../StudioProV1Storage.sol';
import { RolesModule } from './RolesModule.sol';
import { OwnableUpgradeable } from '@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol';
import { IVaultValueV1 } from '../interfaces/IVaultValueV1.sol';
contract RiskManagementModule is OwnableUpgradeable, RolesModule {
error RISK__ExceedsCumulativePriceDeviationAllowance(uint256 priceDeviationLoss);
error RISK__AllowanceExceeds100(uint256 allowance);
error RISK__MaxDebtRatioExceeds100(uint256 maxDebtRatio);
event PriceDeviationRecorded(uint256 priceDeviationLoss);
event CumulativePriceDeviationAllowanceUpdated(uint256 newAllowance);
event MaxCapChanged(uint256 maxCap);
event MaxDebtRatioChanged(uint256 maxDebtRatio);
uint256 public constant MAX_CUMULATIVE_PRICE_DEVIATION_ALLOWANCE = 10000;
///////////////////////////////////////////////////////////////////////////////////////////////
// Price Deviation //
///////////////////////////////////////////////////////////////////////////////////////////////
/**
* @notice Records the price deviation between initial and execution net values.
* @dev This function:
* 1. Calculates the current daily price deviation.
* 2. Computes additional price deviation based on the difference between initial and execution net values.
* 3. Updates the daily price deviation by adding the additional deviation.
* 4. Checks if the new daily price deviation exceeds the allowed cumulative deviation.
* 5. Updates the storage with the new daily price deviation and timestamp.
* 6. Emits an event with the recorded price deviation.
* @param initialNetValue The initial net value.
* @param executionNetValue The execution net value.
*/
function _recordPriceDeviation(uint256 initialNetValue, uint256 executionNetValue) internal {
StudioProV1Storage.StudioProV1DS storage $ = StudioProV1Storage.s();
uint256 currentDailyPriceDeviationBps = _calcDailyPriceDeviationBps();
// Calculate price deviation as a percentage (in basis points)
uint256 additionalPriceDeviationBps = executionNetValue >= initialNetValue
? 0
: ((initialNetValue - executionNetValue) * 10000) / initialNetValue;
// Update daily price deviation
uint256 newDailyPriceDeviationBps = currentDailyPriceDeviationBps + additionalPriceDeviationBps;
if (newDailyPriceDeviationBps > $.cumulativePriceDeviationAllowanceBps) {
revert RISK__ExceedsCumulativePriceDeviationAllowance(newDailyPriceDeviationBps);
}
// stored on storage
$.dailyPriceDeviationBps = newDailyPriceDeviationBps;
$.lastPriceDeviationResetTime = block.timestamp;
emit PriceDeviationRecorded(newDailyPriceDeviationBps);
}
/**
* @notice Sets a new cumulative price deviation allowance.
* @dev This function:
* 1. Checks if the new allowance exceeds the maximum allowed value.
* 2. Updates the storage with the new allowance.
* 3. Emits an event with the updated allowance.
*/
function setCumulativePriceDeviationAllowance(uint256 newAllowanceBps) external onlyOwner {
if (newAllowanceBps > MAX_CUMULATIVE_PRICE_DEVIATION_ALLOWANCE)
revert RISK__AllowanceExceeds100(newAllowanceBps);
StudioProV1Storage.s().cumulativePriceDeviationAllowanceBps = newAllowanceBps;
emit CumulativePriceDeviationAllowanceUpdated(newAllowanceBps);
}
/**
* @notice Retrieves the current cumulative price deviation allowance.
* @return The current cumulative price deviation allowance in basis points.
*/
function getCumulativePriceDeviationAllowance() external view returns (uint256) {
return StudioProV1Storage.s().cumulativePriceDeviationAllowanceBps;
}
/**
* @notice Retrieves the current daily price deviation.
* @return The current daily price deviation in basis points.
*/
function getDailyPriceDeviation() external view returns (uint256) {
return _calcDailyPriceDeviationBps();
}
/**
* @notice Calculates the current daily price deviation.
* @dev This function calculates the remaining daily price deviation as follows:
* 1. Retrieves the time elapsed since the last price deviation reset.
* 2. If more than a day has passed since the last reset, returns 0.
* 3. Otherwise, calculates the remaining deviation using linear interpolation:
* a. Computes the fraction of the day that has passed.
* b. Multiplies the stored daily price deviation by the remaining fraction of the day.
* 4. This approach ensures a gradual, linear decrease in price deviation over the course of a day.
* @dev Important: the price is linearly decayed over the course of a day, starting from the stored daily price deviation.
* @return The current daily price deviation in basis points.
*/
function _calcDailyPriceDeviationBps() internal view returns (uint256) {
StudioProV1Storage.StudioProV1DS storage $ = StudioProV1Storage.s();
uint256 timeSinceLastReset = block.timestamp - $.lastPriceDeviationResetTime;
// if more than a day has passed since the last reset, return 0
if (timeSinceLastReset >= 1 days) {
return 0;
}
// calculate the remaining deviation using linear decay
return ($.dailyPriceDeviationBps * (1 days - timeSinceLastReset)) / 1 days;
}
///////////////////////////////////////////////////////////////////////////////////////////////
// Max Cap //
///////////////////////////////////////////////////////////////////////////////////////////////
/**
* @notice Retrieves the current maximum cap.
* @return The current maximum cap value.
*/
function getMaxCap() external view returns (uint256) {
return StudioProV1Storage.s().maxCap;
}
/**
* @notice Sets a new maximum cap value.
*/
function setMaxCap(uint256 maxCap) external onlyRiskManager {
StudioProV1Storage.s().maxCap = maxCap;
emit MaxCapChanged(maxCap);
}
///////////////////////////////////////////////////////////////////////////////////////////////
// Debt Ratio //
///////////////////////////////////////////////////////////////////////////////////////////////
/**
* @notice Retrieves the current maximum debt ratio.
* @return The current maximum debt ratio value.
*/
function getMaxDebtRatio() external view returns (uint256) {
return StudioProV1Storage.s().maxDebtRatio;
}
/**
* @notice Sets a new maximum debt ratio.
*/
function setMaxDebtRatio(uint256 maxDebtRatio) external onlyRiskManager {
if (maxDebtRatio > 1e18) revert RISK__MaxDebtRatioExceeds100(maxDebtRatio);
StudioProV1Storage.s().maxDebtRatio = maxDebtRatio;
emit MaxDebtRatioChanged(maxDebtRatio);
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.17;
import { StudioProV1Storage } from '../StudioProV1Storage.sol';
import { OwnableUpgradeable } from '@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol';
import { ReentrancyGuardUpgradeable } from '@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol';
import { RolesModule } from './RolesModule.sol';
import { RiskManagementModule } from './RiskManagementModule.sol';
import { IERC20 } from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import { IAccountingV1 } from '../interfaces/IAccountingV1.sol';
import { IVaultValueV1 } from '../interfaces/IVaultValueV1.sol';
import { Math } from '@openzeppelin/contracts/utils/math/Math.sol';
contract ExecutesModule is OwnableUpgradeable, ReentrancyGuardUpgradeable, RolesModule, RiskManagementModule {
using Math for uint256;
error EXECUTE__InvalidAdapter(address adapter);
error EXECUTE__InvalidLength(uint256 adaptersLength, uint256 paramsLength);
error EXECUTE__NVVExceedCap(uint256 executionNetValue);
error EXECUTE__DebtRatioExceedCap(uint256 debtRatio);
error EXECUTE__NotSimulation();
error EXECUTE__NotZeroAddress();
error EXECUTE__MustReduceDebt(uint256 debtRatio);
error EXECUTE__MustReduceNVV(uint256 executionNetValue);
error EXECUTE__NotSelf();
error EXECUTE__InvalidRole();
struct Result {
bool success;
bytes returnData;
}
// Events
event Executed(address indexed adapter, bytes data, bytes returnData);
enum ExecutionRole {
Manager,
Owner
}
/**
* @dev Executes a series of adapter calls as a manager.
* @dev This function can only be called by a manager. It delegates the execution to
* _executeAdapters with the Manager role.
*/
function executeByManager(address[] calldata adapters, bytes[] calldata paramsList) external payable onlyManager {
_executeAdaptersAndValidate(adapters, paramsList, ExecutionRole.Manager);
}
function executeBySelf(address[] calldata adapters, bytes[] calldata paramsList) external payable {
if (msg.sender != address(this)) revert EXECUTE__NotSelf();
_executeAdaptersAndValidate(adapters, paramsList, ExecutionRole.Manager);
}
function executeByManagerAndRead(
address[] calldata adapters,
bytes[] calldata paramsList,
address[] calldata readAdapters,
bytes[] calldata readDatas
) external payable returns (Result[] memory results) {
if (readAdapters.length != readDatas.length)
revert EXECUTE__InvalidLength(readAdapters.length, readDatas.length);
StudioProV1Storage.StudioProV1DS storage $ = StudioProV1Storage.s();
// the simulation must use zero address and manipulate the storage. So only the Simulation can execute this function
if (msg.sender != 0x0000000000000000000000000000000000000000) revert EXECUTE__NotZeroAddress();
if (!$.isSimulation) revert EXECUTE__NotSimulation();
// Execute batch of adapter calls
_executeAdaptersAndValidate(adapters, paramsList, ExecutionRole.Manager);
// Initialize results array with the size of readAdapter
results = new Result[](readAdapters.length);
// Process read adapter calls
for (uint256 i = 0; i < readAdapters.length; ) {
if (!$.managerAdapters[readAdapters[i]]) revert EXECUTE__InvalidAdapter(readAdapters[i]);
// Make the call to the read adapter
(bool success, bytes memory returnData) = readAdapters[i].staticcall(readDatas[i]);
results[i] = Result({ success: success, returnData: returnData });
unchecked {
++i;
}
}
}
/**
* @dev Executes a series of adapter calls as the owner.
* @dev This function can only be called by the owner. It delegates the execution to
* _executeAdapters with the Owner role.
*/
function executeByOwner(
address[] calldata adapters,
bytes[] calldata paramsList
) external payable nonReentrant onlyOwner {
_executeAdaptersAndValidate(adapters, paramsList, ExecutionRole.Owner);
}
/**
* @dev Internal function to execute a series of adapter calls.
* @dev This function performs several checks and operations:
* 1. Checks the daily price deviation before execution.
* 2. Executes each adapter call in the provided sequence.
* 3. Verifies the debt ratio after execution.
* 4. Ensures the net vault value doesn't exceed the maximum cap.
* 5. Records the price deviation of the execution.
*/
function _executeAdaptersAndValidate(
address[] calldata adapters,
bytes[] calldata paramsList,
ExecutionRole role
) internal {
StudioProV1Storage.StudioProV1DS storage $ = StudioProV1Storage.s();
uint256 dailyPriceDeviationBps = _calcDailyPriceDeviationBps();
if (dailyPriceDeviationBps > $.cumulativePriceDeviationAllowanceBps) {
revert RISK__ExceedsCumulativePriceDeviationAllowance(dailyPriceDeviationBps);
}
(uint256 initialTotalAsset, uint256 initialTotalDebt) = IVaultValueV1(address(this)).getAssetDebtValue();
uint256 initialNetValue = initialTotalAsset - initialTotalDebt;
// execute
_executeAdapters(adapters, paramsList, role);
(uint256 totalAsset, uint256 totalDebt) = IVaultValueV1(address(this)).getAssetDebtValue();
// check debt ratio
uint256 debtRatio = totalDebt.mulDiv(1e18, totalAsset);
uint256 initialDebtRatio = initialTotalDebt.mulDiv(1e18, initialTotalAsset);
// if initialDebtRatio less than maxDebRatio but after execution debtRatio exceed maxDebtRatio, manager can't execute it
if (initialDebtRatio <= $.maxDebtRatio && debtRatio > $.maxDebtRatio)
revert EXECUTE__DebtRatioExceedCap(debtRatio);
// if initialDebtRatio more than maxDebRatio, manager can only execute it when debtRatio is less than initialDebtRatio. It force manager to reduce debt
if (initialDebtRatio >= $.maxDebtRatio && debtRatio > initialDebtRatio)
revert EXECUTE__MustReduceDebt(debtRatio);
// check max cap
uint256 executionNetValue = totalAsset - totalDebt;
uint256 initialExecutionNetValue = initialTotalAsset - initialTotalDebt;
// if initialExecutionNetValue less than maxCap but after execution executionNetValue exceed maxCap, manager can't execute it
if (initialExecutionNetValue <= $.maxCap && executionNetValue > $.maxCap)
revert EXECUTE__NVVExceedCap(executionNetValue);
// if initialExecutionNetValue more than maxCap, manager can only execute it when executionNetValue is less than initialExecutionNetValue. It force manager to reduce debt
if (initialExecutionNetValue >= $.maxCap && executionNetValue > initialExecutionNetValue)
revert EXECUTE__MustReduceNVV(executionNetValue);
_recordPriceDeviation(initialNetValue, executionNetValue);
}
function _executeAdapters(address[] calldata adapters, bytes[] calldata paramsList, ExecutionRole role) internal {
if (adapters.length != paramsList.length) revert EXECUTE__InvalidLength(adapters.length, paramsList.length);
StudioProV1Storage.StudioProV1DS storage $ = StudioProV1Storage.s();
for (uint i = 0; i < adapters.length; i++) {
if (role == ExecutionRole.Manager) {
if (!$.managerAdapters[adapters[i]]) revert EXECUTE__InvalidAdapter(adapters[i]);
} else if (role == ExecutionRole.Owner) {
if (!$.ownerAdapters[adapters[i]]) revert EXECUTE__InvalidAdapter(adapters[i]);
} else {
revert EXECUTE__InvalidRole();
}
// Execute the adapter
(bool success, bytes memory returnData) = adapters[i].delegatecall(paramsList[i]);
if (!success) {
// Next 5 lines from https://ethereum.stackexchange.com/a/83577
if (returnData.length < 68) revert();
assembly {
returnData := add(returnData, 0x04)
}
revert(abi.decode(returnData, (string)));
}
emit Executed(adapters[i], paramsList[i], returnData);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
pragma solidity ^0.8.20;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```solidity
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position is the index of the value in the `values` array plus 1.
// Position 0 is used to mean a value is not in the set.
mapping(bytes32 value => uint256) _positions;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._positions[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We cache the value's position to prevent multiple reads from the same storage slot
uint256 position = set._positions[value];
if (position != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 valueIndex = position - 1;
uint256 lastIndex = set._values.length - 1;
if (valueIndex != lastIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the lastValue to the index where the value to delete is
set._values[valueIndex] = lastValue;
// Update the tracked position of the lastValue (that was just moved)
set._positions[lastValue] = position;
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the tracked position for the deleted slot
delete set._positions[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._positions[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.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 ERC20
* applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*/
abstract contract 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}.
*
* All two of these 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;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual returns (uint256) {
ERC20Storage storage $ = _getERC20Storage();
return $._totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
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;
}
/**
* @dev See {IERC20-allowance}.
*/
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}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `value`.
* - the caller must have allowance for ``from``'s tokens of at least
* `value`.
*/
function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, value);
_transfer(from, to, value);
return true;
}
/**
* @dev Moves a `value` amount of tokens from `from` to `to`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _transfer(address from, address to, uint256 value) internal {
if (from == address(0)) {
revert ERC20InvalidSender(address(0));
}
if (to == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(from, to, value);
}
/**
* @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
* (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
* this function.
*
* Emits a {Transfer} event.
*/
function _update(address from, address to, uint256 value) internal virtual {
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:
* ```
* 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
pragma solidity ^0.8.17;
import { Initializable } from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol';
import { Math } from '@openzeppelin/contracts/utils/math/Math.sol';
import { IERC20 } from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import { SafeERC20 } from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
import { RewardManager } from './RewardManager.sol';
import { IVotingEscrow } from '../interfaces/IVotingEscrow.sol';
import { IFactorGaugeController } from '../interfaces/IFactorGaugeController.sol';
import { ArrayLib } from '../libraries/ArrayLib.sol';
/**
* @dev FactorGauge.sol is a modified version of Pendle's PendleGauge.sol:
* https://github.com/pendle-finance/pendle-core-v2-public/blob/main/contracts/core/Market/PendleGauge.sol
*
* @notice
* This is used with FactorVault.
*/
abstract contract FactorGauge is RewardManager, Initializable {
// =============================================================
// Library
// =============================================================
using SafeERC20 for IERC20;
using Math for uint256;
using ArrayLib for address[];
// =============================================================
// Events
// =============================================================
event RedeemRewards(address indexed user, uint256[] rewardsOut);
uint256 internal constant TOKENLESS_PRODUCTION = 40;
struct FactorGaugeStorage {
address esFctr;
address veFctr;
address gaugeController;
uint256 totalActiveSupply;
mapping(address => uint256) activeBalance;
}
bytes32 private constant FACTOR_GAUGE_STORAGE = keccak256('factor.base.gauge.storage');
function _getFactorGaugeStorage() internal pure returns (FactorGaugeStorage storage $) {
bytes32 slot = FACTOR_GAUGE_STORAGE;
assembly {
$.slot := slot
}
}
function __FactorGauge_init(address _veFctr, address _gaugeController) internal onlyInitializing {
FactorGaugeStorage storage $ = _getFactorGaugeStorage();
$.veFctr = _veFctr;
$.gaugeController = _gaugeController;
$.esFctr = IFactorGaugeController(_gaugeController).esFctr();
}
/**
* @dev Since rewardShares is based on activeBalance, user's activeBalance must be updated AFTER
* rewards is updated.
* It's intended to have user's activeBalance updated when rewards is redeemed
*/
function _redeemRewards(address user) internal virtual returns (uint256[] memory rewardsOut) {
_updateAndDistributeRewards(user);
_updateUserActiveBalance(user);
rewardsOut = _doTransferOutRewards(user, user);
emit RedeemRewards(user, rewardsOut);
}
function _updateUserActiveBalance(address user) internal virtual {
_updateUserActiveBalanceForTwo(user, address(0));
}
function _updateUserActiveBalanceForTwo(address user1, address user2) internal virtual {
if (user1 != address(0) && user1 != address(this)) _updateUserActiveBalancePrivate(user1);
if (user2 != address(0) && user2 != address(this)) _updateUserActiveBalancePrivate(user2);
}
/**
* @dev should only be callable from `_updateUserActiveBalanceForTwo` to
* guarantee user != address(0) && user != address(this)
*/
function _updateUserActiveBalancePrivate(address user) private {
assert(user != address(0) && user != address(this));
uint256 lpBalance = _stakedBalance(user);
uint256 veBoostedLpBalance = _calcVeBoostedLpBalance(user, lpBalance);
uint256 newActiveBalance = Math.min(veBoostedLpBalance, lpBalance);
FactorGaugeStorage storage $ = _getFactorGaugeStorage();
$.totalActiveSupply = $.totalActiveSupply - $.activeBalance[user] + newActiveBalance;
$.activeBalance[user] = newActiveBalance;
}
function _calcVeBoostedLpBalance(address user, uint256 lpBalance) internal virtual returns (uint256) {
FactorGaugeStorage storage $ = _getFactorGaugeStorage();
(uint256 veFctrSupplyCurrent, uint256 veFctrBalanceCurrent) = IVotingEscrow($.veFctr)
.totalSupplyAndBalanceCurrent(user);
// Inspired by Curve's Gauge
uint256 veBoostedLpBalance = (lpBalance * TOKENLESS_PRODUCTION) / 100;
if (veFctrSupplyCurrent > 0) {
veBoostedLpBalance +=
(((_totalStaked() * veFctrBalanceCurrent) / veFctrSupplyCurrent) * (100 - TOKENLESS_PRODUCTION)) /
100;
}
return veBoostedLpBalance;
}
function _redeemExternalReward() internal virtual override {
IFactorGaugeController(_getFactorGaugeStorage().gaugeController).redeemVaultReward();
}
function _stakedBalance(address user) internal view virtual returns (uint256);
function _totalStaked() internal view virtual returns (uint256);
function _getRewardTokens() internal view virtual override returns (address[] memory) {
address[] memory rewardTokens = new address[](0);
return rewardTokens.append(_getFactorGaugeStorage().esFctr);
}
function _rewardSharesTotal() internal view virtual override returns (uint256) {
return _getFactorGaugeStorage().totalActiveSupply;
}
function _rewardSharesUser(address user) internal view virtual override returns (uint256) {
return _getFactorGaugeStorage().activeBalance[user];
}
function _beforeTokenTransfer(address from, address to, uint256) internal virtual {
_updateAndDistributeRewardsForTwo(from, to);
}
function _afterTokenTransfer(address from, address to, uint256) internal virtual {
_updateUserActiveBalanceForTwo(from, to);
}
function totalActiveSupply() public view virtual returns (uint256) {
return _getFactorGaugeStorage().totalActiveSupply;
}
function activeBalance(address user) public view virtual returns (uint256) {
return _getFactorGaugeStorage().activeBalance[user];
}
function _pendingRewards(address user) internal view returns (uint256) {
FactorGaugeStorage storage $ = _getFactorGaugeStorage();
address rewardToken = $.esFctr;
(
uint128 fctrPerSec,
uint128 accumulatedFctr,
uint128 lastUpdated,
uint128 incentiveEndsAt
) = IFactorGaugeController($.gaugeController).rewardData(address(this));
accumulatedFctr += fctrPerSec * uint128(Math.min(block.timestamp, incentiveEndsAt) - lastUpdated);
return _calculateReward(user, rewardToken, accumulatedFctr);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import { BoostStorage } from './storages/BoostStorage.sol';
import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
import { Initializable } from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol';
import '@openzeppelin/contracts/utils/structs/EnumerableSet.sol';
/**
* @notice FactorBoostReward.sol is a modified version of Synthetix's StakingRewards.sol:
* https://github.com/Synthetixio/synthetix/blob/develop/contracts/StakingRewards.sol
*
*/
abstract contract FactorBoost is Initializable {
using SafeERC20 for IERC20;
using EnumerableSet for EnumerableSet.AddressSet;
/* ========== EVENTS ========== */
event RewardAdded(uint256 reward);
event RewardPaid(address indexed user, address indexed rewardsToken, uint256 reward);
event AddToWhitelist(address[] tokens, uint256[] minAmounts);
event RemoveFromWhitelist(address[] tokens);
error BOOST__NotSetupRewardTokens();
error BOOST__NotWhitelisted(address token);
error BOOST__LessThanMinAmount();
error BOOST__InvalidLength();
modifier updateReward(address account) {
_updateReward(account);
_;
}
function __FactorBoost_init(uint256 _rewardDuration) internal onlyInitializing {
BoostStorage.BoostDS storage $ = BoostStorage.s();
$.rewardDuration = _rewardDuration;
}
/* ========== VIEWS ========== */
/**
* @notice Returns the reward duration
* @return The reward duration
*/
function _rewardDuration() internal view returns (uint256) {
return BoostStorage.s().rewardDuration;
}
/**
* @notice Returns the user's reward per token paid for a specific rewards token
* @return The user's reward per token paid
*/
function _userRewardPerTokenPaid(address _user, address _rewardsToken) internal view returns (uint256) {
return BoostStorage.s().userRewardPerTokenPaid[_user][_rewardsToken];
}
/**
* @notice Returns the reward data for a specific rewards token
* @return The reward data struct
*/
function _rewardData(address _rewardsToken) internal view returns (BoostStorage.Reward memory) {
return BoostStorage.s().rewardData[_rewardsToken];
}
/**
* @notice Returns the last time reward was applicable for a specific rewards token
* @return The last applicable reward time
*/
function _lastTimeRewardApplicable(address _rewardsToken) internal view returns (uint256) {
BoostStorage.BoostDS storage $ = BoostStorage.s();
uint256 periodFinish = $.rewardData[_rewardsToken].periodFinish;
return block.timestamp < periodFinish ? block.timestamp : periodFinish;
}
/**
* @notice Calculates the reward per token for a specific rewards token
* @return The reward per token
*/
function _rewardPerToken(address _rewardsToken) internal view returns (uint256) {
BoostStorage.BoostDS storage $ = BoostStorage.s();
uint256 totalSupply = _totalStaked();
if (totalSupply == 0) {
return $.rewardData[_rewardsToken].rewardPerTokenStored;
}
return
$.rewardData[_rewardsToken].rewardPerTokenStored +
(((_lastTimeRewardApplicable(_rewardsToken) - $.rewardData[_rewardsToken].lastUpdateTime) *
$.rewardData[_rewardsToken].rewardRate *
1e18) / totalSupply);
}
/**
* @notice Calculates the earned rewards for an account and a specific rewards token
* @return The earned rewards
*/
function _earned(address account, address _rewardsToken) internal view returns (uint256) {
BoostStorage.BoostDS storage $ = BoostStorage.s();
return
(_stakedBalance(account) *
(_rewardPerToken(_rewardsToken) - $.userRewardPerTokenPaid[account][_rewardsToken])) /
1e18 +
$.rewards[account][_rewardsToken];
}
/**
* @notice Calculates the reward for the duration for a specific rewards token
* @return The reward for the duration
*/
function _getRewardForDuration(address _rewardsToken) internal view returns (uint256) {
BoostStorage.BoostDS storage $ = BoostStorage.s();
return $.rewardData[_rewardsToken].rewardRate * $.rewardDuration;
}
/* ========== MUTATIVE FUNCTIONS ========== */
/**
* @notice Redeems all boost rewards for a user
* @dev This function updates the reward before redeeming
*/
function _redeemBoostRewardAll(address user) internal updateReward(user) {
BoostStorage.BoostDS storage $ = BoostStorage.s();
address[] memory rewardTokens = $.rewardTokens.values();
if (rewardTokens.length == 0) revert BOOST__NotSetupRewardTokens();
for (uint i; i < rewardTokens.length; i++) {
address _rewardsToken = rewardTokens[i];
uint256 reward = $.rewards[user][_rewardsToken];
if (reward > 0) {
$.rewards[user][_rewardsToken] = 0;
IERC20(_rewardsToken).safeTransfer(user, reward);
emit RewardPaid(user, _rewardsToken, reward);
}
}
}
/**
* @notice Redeems boost rewards for a user for specific reward tokens
* @dev This function updates the reward before redeeming
*/
function _redeemBoostReward(address user, address[] calldata rewardTokens) internal {
_updateReward(user);
BoostStorage.BoostDS storage $ = BoostStorage.s();
for (uint i; i < rewardTokens.length; i++) {
address _rewardsToken = rewardTokens[i];
uint256 reward = $.rewards[user][_rewardsToken];
if (reward > 0) {
$.rewards[user][_rewardsToken] = 0;
IERC20(_rewardsToken).safeTransfer(user, reward);
emit RewardPaid(user, _rewardsToken, reward);
}
}
}
/* ========== RESTRICTED FUNCTIONS ========== */
/**
* @notice Notifies the contract about new reward amount
* @dev This function updates the reward before notifying
*/
function _notifyRewardAmount(address _rewardsToken, uint256 reward) internal updateReward(address(0)) {
BoostStorage.BoostDS storage $ = BoostStorage.s();
if (!$.whitelisted[_rewardsToken]) revert BOOST__NotWhitelisted(_rewardsToken);
if ($.minAmount[_rewardsToken] > reward) revert BOOST__LessThanMinAmount();
IERC20(_rewardsToken).safeTransferFrom(msg.sender, address(this), reward);
/**
* @dev This condition works as follows:
* 1. It checks if the current block timestamp is greater than or equal to the period finish time for the reward token
* 2. If true, it means the previous reward period has ended, so it sets a new reward rate
* 3. If false, it calculates the remaining reward from the previous period and adds it to the new reward before setting the new rate
*/
if (block.timestamp >= $.rewardData[_rewardsToken].periodFinish) {
$.rewardData[_rewardsToken].rewardRate = reward / $.rewardDuration;
} else {
uint256 remaining = $.rewardData[_rewardsToken].periodFinish - block.timestamp;
uint256 leftover = remaining * $.rewardData[_rewardsToken].rewardRate;
$.rewardData[_rewardsToken].rewardRate = (reward + leftover) / $.rewardDuration;
}
$.rewardData[_rewardsToken].lastUpdateTime = block.timestamp;
$.rewardData[_rewardsToken].periodFinish = block.timestamp + $.rewardDuration;
emit RewardAdded(reward);
}
/**
* @notice Updates the reward for an account
*/
function _updateReward(address _account) internal {
BoostStorage.BoostDS storage $ = BoostStorage.s();
address[] memory rewardTokens = $.rewardTokens.values();
for (uint i; i < rewardTokens.length; i++) {
address token = rewardTokens[i];
$.rewardData[token].rewardPerTokenStored = _rewardPerToken(token);
$.rewardData[token].lastUpdateTime = _lastTimeRewardApplicable(token);
if (_account != address(0)) {
$.rewards[_account][token] = _earned(_account, token);
$.userRewardPerTokenPaid[_account][token] = $.rewardData[token].rewardPerTokenStored;
}
}
}
/**
* @notice Hook that is called before any token transfer
* @dev This function updates the reward for both the sender and receiver
*/
function _beforeTokenTransfer(address from, address to, uint256) internal virtual {
if (from != address(0)) {
_updateReward(from);
}
if (to != address(0) && to != from) {
_updateReward(to);
}
}
/**
* @notice Returns the staked balance of a user
* @dev This function should be implemented by the inheriting contract
* @return The staked balance
*/
function _stakedBalance(address user) internal view virtual returns (uint256);
/**
* @notice Returns the total staked amount
* @dev This function should be implemented by the inheriting contract
* @return The total staked amount
*/
function _totalStaked() internal view virtual returns (uint256);
/**
* @notice Returns all reward tokens
* @return An array of reward token addresses
*/
function _getAllRewardTokens() internal view returns (address[] memory) {
return BoostStorage.s().rewardTokens.values();
}
/**
* @notice Returns the count of reward tokens
* @return The number of reward tokens
*/
function _getRewardTokensCount() internal view returns (uint256) {
return BoostStorage.s().rewardTokens.length();
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC1822.sol)
pragma solidity ^0.8.20;
/**
* @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
* proxy whose upgrades are fully controlled by the current implementation.
*/
interface 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.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.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) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error AddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedInnerCall();
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {FailedInnerCall} error.
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
* unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {FailedInnerCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
*/
function _revert(bytes memory returndata) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity ^0.8.20;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```solidity
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(newImplementation.code.length > 0);
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` representation of the string storage pointer `store`.
*/
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
/**
* @dev Returns an `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
*/
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/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 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: BUSL-1.1
pragma solidity ^0.8.17;
import { StudioProV1Storage } from '../StudioProV1Storage.sol';
import { OwnableUpgradeable } from '@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol';
contract RolesModule is OwnableUpgradeable {
error MANAGER__NotManager();
error MANAGER__NotRiskManager();
error MANAGER__ZeroAddress();
event ManagerAdded(address indexed manager);
event RiskManagerChanged(address indexed manager);
event ManagerRemoved(address indexed manager);
modifier onlyManager() {
if (!StudioProV1Storage.s().isManager[msg.sender]) revert MANAGER__NotManager();
_;
}
modifier onlyRiskManager() {
if (msg.sender != StudioProV1Storage.s().riskManager) revert MANAGER__NotRiskManager();
_;
}
// manager
function addManager(address manager) external virtual onlyOwner {
_addManager(manager);
}
function removeManager(address manager) external virtual onlyOwner {
_removeManager(manager);
}
function _addManager(address manager) internal {
if (manager == address(0)) revert MANAGER__ZeroAddress();
StudioProV1Storage.s().isManager[manager] = true;
emit ManagerAdded(manager);
}
function _removeManager(address manager) internal {
if (manager == address(0)) revert MANAGER__ZeroAddress();
StudioProV1Storage.s().isManager[manager] = false;
emit ManagerRemoved(manager);
}
// risk manager
function setRiskManager(address manager) external onlyOwner {
if (manager == address(0)) revert MANAGER__ZeroAddress();
StudioProV1Storage.s().riskManager = manager;
emit RiskManagerChanged(manager);
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.17;
interface IVaultValueV1 {
function getAssetDebtValue() external view returns (uint256 totalAsset, uint256 totalDebt);
function getNetVaultValue() external view returns (uint256);
function getNetVaultValueInAsset(address) external view returns (uint256);
function getTotalAssetValue() external view returns (uint256);
function getTotalDebtValue() external view returns (uint256);
function getAssetValueByAmount(address _asset, uint256 amount) external view returns (uint256);
function getAssetDebtValueInAsset(address _asset) external view returns (uint256, uint256);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.17;
interface IAccountingV1 {
function getBalance(address vault, address asset) external view returns (uint256);
function getPriceUSD(address asset) external view returns (uint256);
function getUSDDecimals(address asset) external view returns (uint256);
function getDecimals(address asset) external view returns (uint256);
function getPriceDetails(
address asset
) external view returns (uint256 price, uint256 decimalsUSD, uint256 decimals);
function getBalanceAndPriceDetails(
address vault,
address asset
) external view returns (uint256 balance, uint256 decimals, uint256 priceUSD, uint256 decimalsUSD);
function isTransferable(address asset) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
/**
* @dev Muldiv operation overflow.
*/
error MathOverflowedMulDiv();
enum Rounding {
Floor, // Toward negative infinity
Ceil, // Toward positive infinity
Trunc, // Toward zero
Expand // Away from zero
}
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an overflow flag.
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds towards infinity instead
* of rounding towards zero.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
if (b == 0) {
// Guarantee the same behavior as in a regular Solidity division.
return a / b;
}
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
* denominator == 0.
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
* Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0 = x * y; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
if (denominator <= prod1) {
revert MathOverflowedMulDiv();
}
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator.
// Always >= 1. See https://cs.stackexchange.com/q/138556/92363.
uint256 twos = denominator & (0 - denominator);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
// works in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
* towards zero.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256 of a positive value rounded towards zero.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
}
}
/**
* @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
*/
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
return uint8(rounding) % 2 == 1;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard ERC20 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens.
*/
interface IERC20Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC20InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC20InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
* @param spender Address that may be allowed to operate on tokens without being their owner.
* @param allowance Amount of tokens a `spender` is allowed to operate with.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC20InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `spender` to be approved. Used in approvals.
* @param spender Address that may be allowed to operate on tokens without being their owner.
*/
error ERC20InvalidSpender(address spender);
}
/**
* @dev Standard ERC721 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens.
*/
interface IERC721Errors {
/**
* @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20.
* Used in balance queries.
* @param owner Address of the current owner of a token.
*/
error ERC721InvalidOwner(address owner);
/**
* @dev Indicates a `tokenId` whose `owner` is the zero address.
* @param tokenId Identifier number of a token.
*/
error ERC721NonexistentToken(uint256 tokenId);
/**
* @dev Indicates an error related to the ownership over a particular token. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param tokenId Identifier number of a token.
* @param owner Address of the current owner of a token.
*/
error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC721InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC721InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param tokenId Identifier number of a token.
*/
error ERC721InsufficientApproval(address operator, uint256 tokenId);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC721InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC721InvalidOperator(address operator);
}
/**
* @dev Standard ERC1155 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens.
*/
interface IERC1155Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
* @param tokenId Identifier number of a token.
*/
error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC1155InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC1155InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param owner Address of the current owner of a token.
*/
error ERC1155MissingApprovalForAll(address operator, address owner);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC1155InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC1155InvalidOperator(address operator);
/**
* @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
* Used in batch transfers.
* @param idsLength Length of the array of token identifiers
* @param valuesLength Length of the array of token amounts
*/
error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @dev An operation with an ERC20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data);
if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import { SafeCast } from '@openzeppelin/contracts/utils/math/SafeCast.sol';
import { FixedPointMathLib } from '../libraries/uniswap/FixedPointMathLib.sol';
import { IERC20 } from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import { SafeERC20 } from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
/**
* @dev RewardManager.sol is a modified version of Pendle's RewardManager.sol & RewardManagerAbstract:
* https://github.com/pendle-finance/pendle-core-v2-public/blob/main/contracts/core/RewardManager/RewardManager.sol
*
* @notice
* This is used with FactorGauge. RewardManager must not have duplicated rewardTokens
*/
abstract contract RewardManager {
using FixedPointMathLib for uint256;
using SafeCast for uint256;
using SafeERC20 for IERC20;
struct RewardState {
uint128 index;
uint128 lastBalance;
}
struct UserReward {
uint128 index;
uint128 accrued;
}
struct RewardManagerStorage {
uint256 lastRewardBlock;
/// @dev [token] => [user] => (index, accrued)
mapping(address => mapping(address => UserReward)) userReward;
/// @dev [token] => (index, lastBalance)
mapping(address => RewardState) rewardState;
}
bytes32 private constant REWARD_MANAGER_STORAGE = keccak256('factor.base.RewardManager.storage');
function _getRewardManagerStorage() internal pure returns (RewardManagerStorage storage $) {
bytes32 slot = REWARD_MANAGER_STORAGE;
assembly {
$.slot := slot
}
}
uint256 internal constant INITIAL_REWARD_INDEX = 1;
function _updateAndDistributeRewards(address user) internal virtual {
_updateAndDistributeRewardsForTwo(user, address(0));
}
function _updateAndDistributeRewardsForTwo(address user1, address user2) internal virtual {
(address[] memory tokens, uint256[] memory indexes) = _updateRewardIndex();
if (tokens.length == 0) return;
if (user1 != address(0) && user1 != address(this)) _distributeRewardsPrivate(user1, tokens, indexes);
if (user2 != address(0) && user2 != address(this)) _distributeRewardsPrivate(user2, tokens, indexes);
}
/**
* @dev should only be callable from `_updateAndDistributeRewardsForTwo` to guarantee
* user != address(0) && user != address(this)
*/
function _distributeRewardsPrivate(address user, address[] memory tokens, uint256[] memory indexes) private {
assert(user != address(0) && user != address(this));
RewardManagerStorage storage $ = _getRewardManagerStorage();
uint256 userShares = _rewardSharesUser(user);
for (uint256 i = 0; i < tokens.length; ++i) {
address token = tokens[i];
uint256 index = indexes[i];
uint256 userIndex = $.userReward[token][user].index;
if (userIndex == 0) {
$.userReward[token][user].index = index.toUint128();
continue;
}
if (userIndex == index) continue;
uint256 deltaIndex = index - userIndex;
uint256 rewardDelta = userShares.mulWadDown(deltaIndex);
uint256 rewardAccrued = $.userReward[token][user].accrued + rewardDelta;
$.userReward[token][user] = UserReward({ index: index.toUint128(), accrued: rewardAccrued.toUint128() });
}
}
function _updateRewardIndex() internal virtual returns (address[] memory tokens, uint256[] memory indexes) {
tokens = _getRewardTokens();
indexes = new uint256[](tokens.length);
if (tokens.length == 0) return (tokens, indexes);
RewardManagerStorage storage $ = _getRewardManagerStorage();
if ($.lastRewardBlock != block.number) {
// if we have not yet update the index for this block
$.lastRewardBlock = block.number;
uint256 totalShares = _rewardSharesTotal();
_redeemExternalReward();
for (uint256 i = 0; i < tokens.length; ++i) {
address token = tokens[i];
// the entire token balance of the contract must be the rewards of the contract
uint256 accrued = IERC20(tokens[i]).balanceOf(address(this)) - $.rewardState[token].lastBalance;
uint256 index = $.rewardState[token].index;
if (index == 0) index = INITIAL_REWARD_INDEX;
if (totalShares != 0) index += accrued.divWadDown(totalShares);
$.rewardState[token].index = index.toUint128();
$.rewardState[token].lastBalance += accrued.toUint128();
}
}
for (uint256 i = 0; i < tokens.length; i++) indexes[i] = $.rewardState[tokens[i]].index;
}
/// @dev this function doesn't need redeemExternal since redeemExternal is bundled in updateRewardIndex
/// @dev this function also has to update rewardState.lastBalance
function _doTransferOutRewards(
address user,
address receiver
) internal virtual returns (uint256[] memory rewardAmounts) {
address[] memory tokens = _getRewardTokens();
rewardAmounts = new uint256[](tokens.length);
RewardManagerStorage storage $ = _getRewardManagerStorage();
for (uint256 i = 0; i < tokens.length; i++) {
rewardAmounts[i] = $.userReward[tokens[i]][user].accrued;
if (rewardAmounts[i] != 0) {
$.userReward[tokens[i]][user].accrued = 0;
$.rewardState[tokens[i]].lastBalance -= rewardAmounts[i].toUint128();
IERC20(tokens[i]).safeTransfer(receiver, rewardAmounts[i]);
}
}
}
function _redeemExternalReward() internal virtual;
function _rewardSharesUser(address user) internal view virtual returns (uint256);
function _getRewardTokens() internal view virtual returns (address[] memory);
function _rewardSharesTotal() internal view virtual returns (uint256);
function getLastRewardBlock() external view returns (uint256) {
return _getRewardManagerStorage().lastRewardBlock;
}
function _calculateReward(address user, address token, uint256 accumulatedFctr) internal view returns (uint256) {
RewardManagerStorage storage $ = _getRewardManagerStorage();
uint256 index = $.rewardState[token].index;
if (index == 0) index = INITIAL_REWARD_INDEX;
uint256 totalShares = _rewardSharesTotal();
if (totalShares != 0) index += accumulatedFctr.divWadDown(totalShares);
uint256 userIndex = $.userReward[token][user].index;
uint256 rewardDelta = _rewardSharesUser(user).mulWadDown(index - userIndex);
uint256 rewardAccrued = $.userReward[token][user].accrued + rewardDelta;
return rewardAccrued;
}
}// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.20;
interface IVotingEscrow {
// ============= USER INFO =============
function balanceOf(address user) external view returns (uint128);
function balanceOfAt(address user, uint128 timestamp) external view returns (uint128);
function positionData(address user) external view returns (uint128 amount, uint128 expiry);
// ============= META DATA =============
function totalSupplyStored() external view returns (uint128);
function totalSupplyCurrent() external returns (uint128);
function totalSupplyAndBalanceCurrent(address user) external returns (uint128, uint128);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
interface IFactorGaugeController {
event VaultClaimReward(
address indexed vault,
uint256 amount
);
event ReceiveVotingResults(
uint128 indexed wTime,
address[] vaults,
uint256[] fctrAmounts
);
event UpdateVaultReward(
address indexed vault,
uint256 fctrPerSec,
uint256 incentiveEndsAt
);
event AddVault(address indexed vault);
event RemoveVault(address indexed vault);
event SetEsFctr(address indexed oldEsFctr, address indexed newEsFctr);
function fundEsFctr(uint256 amount) external;
function withdrawEsFctr(uint256 amount) external;
function esFctr() external returns (address);
function redeemVaultReward() external;
function rewardData(
address pool
) external view returns (uint128 fctrPerSec, uint128, uint128, uint128);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
library ArrayLib {
function sum(uint256[] memory input) internal pure returns (uint256) {
uint256 value = 0;
for (uint256 i = 0; i < input.length; ) {
value += input[i];
unchecked {
i++;
}
}
return value;
}
/// @notice return index of the element if found, else return uint256.max
function find(address[] memory array, address element) internal pure returns (uint256 index) {
uint256 length = array.length;
for (uint256 i = 0; i < length; ) {
if (array[i] == element) return i;
unchecked {
i++;
}
}
return type(uint256).max;
}
function append(
address[] memory inp,
address element
) internal pure returns (address[] memory out) {
uint256 length = inp.length;
out = new address[](length + 1);
for (uint256 i = 0; i < length; ) {
out[i] = inp[i];
unchecked {
i++;
}
}
out[length] = element;
}
/**
* @dev This function assumes a and b each contains unidentical elements
* @param a array of addresses a
* @param b array of addresses b
* @return out Concatenation of a and b containing unidentical elements
*/
function merge(
address[] memory a,
address[] memory b
) internal pure returns (address[] memory out) {
unchecked {
uint256 countUnidenticalB = 0;
bool[] memory isUnidentical = new bool[](b.length);
for(uint256 i = 0; i < b.length; ++i) {
if (!contains(a, b[i])) {
countUnidenticalB++;
isUnidentical[i] = true;
}
}
out = new address[](a.length + countUnidenticalB);
for(uint256 i = 0; i < a.length; ++i) {
out[i] = a[i];
}
uint256 id = a.length;
for(uint256 i = 0; i < b.length; ++i) {
if (isUnidentical[i]) {
out[id++] = b[i];
}
}
}
}
// various version of contains
function contains(address[] memory array, address element) internal pure returns (bool) {
uint256 length = array.length;
for (uint256 i = 0; i < length; ) {
if (array[i] == element) return true;
unchecked {
i++;
}
}
return false;
}
function contains(bytes4[] memory array, bytes4 element) internal pure returns (bool) {
uint256 length = array.length;
for (uint256 i = 0; i < length; ) {
if (array[i] == element) return true;
unchecked {
i++;
}
}
return false;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/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 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);
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
/// @notice Arithmetic library with operations for fixed-point numbers.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol)
/// @author Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol)
library FixedPointMathLib {
/*//////////////////////////////////////////////////////////////
SIMPLIFIED FIXED POINT OPERATIONS
//////////////////////////////////////////////////////////////*/
uint256 internal constant MAX_UINT256 = 2**256 - 1;
uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s.
function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down.
}
function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up.
}
function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down.
}
function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up.
}
/*//////////////////////////////////////////////////////////////
LOW LEVEL FIXED POINT OPERATIONS
//////////////////////////////////////////////////////////////*/
function mulDivDown(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))
if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {
revert(0, 0)
}
// Divide x * y by the denominator.
z := div(mul(x, y), denominator)
}
}
function mulDivUp(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))
if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {
revert(0, 0)
}
// If x * y modulo the denominator is strictly greater than 0,
// 1 is added to round up the division of x * y by the denominator.
z := add(gt(mod(mul(x, y), denominator), 0), div(mul(x, y), denominator))
}
}
function rpow(
uint256 x,
uint256 n,
uint256 scalar
) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
switch x
case 0 {
switch n
case 0 {
// 0 ** 0 = 1
z := scalar
}
default {
// 0 ** n = 0
z := 0
}
}
default {
switch mod(n, 2)
case 0 {
// If n is even, store scalar in z for now.
z := scalar
}
default {
// If n is odd, store x in z for now.
z := x
}
// Shifting right by 1 is like dividing by 2.
let half := shr(1, scalar)
for {
// Shift n right by 1 before looping to halve it.
n := shr(1, n)
} n {
// Shift n right by 1 each iteration to halve it.
n := shr(1, n)
} {
// Revert immediately if x ** 2 would overflow.
// Equivalent to iszero(eq(div(xx, x), x)) here.
if shr(128, x) {
revert(0, 0)
}
// Store x squared.
let xx := mul(x, x)
// Round to the nearest number.
let xxRound := add(xx, half)
// Revert if xx + half overflowed.
if lt(xxRound, xx) {
revert(0, 0)
}
// Set x to scaled xxRound.
x := div(xxRound, scalar)
// If n is even:
if mod(n, 2) {
// Compute z * x.
let zx := mul(z, x)
// If z * x overflowed:
if iszero(eq(div(zx, x), z)) {
// Revert if x is non-zero.
if iszero(iszero(x)) {
revert(0, 0)
}
}
// Round to the nearest number.
let zxRound := add(zx, half)
// Revert if zx + half overflowed.
if lt(zxRound, zx) {
revert(0, 0)
}
// Return properly scaled zxRound.
z := div(zxRound, scalar)
}
}
}
}
}
/*//////////////////////////////////////////////////////////////
GENERAL NUMBER UTILITIES
//////////////////////////////////////////////////////////////*/
function sqrt(uint256 x) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
let y := x // We start y at x, which will help us make our initial estimate.
z := 181 // The "correct" value is 1, but this saves a multiplication later.
// This segment is to get a reasonable initial estimate for the Babylonian method. With a bad
// start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.
// We check y >= 2^(k + 8) but shift right by k bits
// each branch to ensure that if x >= 256, then y >= 256.
if iszero(lt(y, 0x10000000000000000000000000000000000)) {
y := shr(128, y)
z := shl(64, z)
}
if iszero(lt(y, 0x1000000000000000000)) {
y := shr(64, y)
z := shl(32, z)
}
if iszero(lt(y, 0x10000000000)) {
y := shr(32, y)
z := shl(16, z)
}
if iszero(lt(y, 0x1000000)) {
y := shr(16, y)
z := shl(8, z)
}
// Goal was to get z*z*y within a small factor of x. More iterations could
// get y in a tighter range. Currently, we will have y in [256, 256*2^16).
// We ensured y >= 256 so that the relative difference between y and y+1 is small.
// That's not possible if x < 256 but we can just verify those cases exhaustively.
// Now, z*z*y <= x < z*z*(y+1), and y <= 2^(16+8), and either y >= 256, or x < 256.
// Correctness can be checked exhaustively for x < 256, so we assume y >= 256.
// Then z*sqrt(y) is within sqrt(257)/sqrt(256) of sqrt(x), or about 20bps.
// For s in the range [1/256, 256], the estimate f(s) = (181/1024) * (s+1) is in the range
// (1/2.84 * sqrt(s), 2.84 * sqrt(s)), with largest error when s = 1 and when s = 256 or 1/256.
// Since y is in [256, 256*2^16), let a = y/65536, so that a is in [1/256, 256). Then we can estimate
// sqrt(y) using sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2^18.
// There is no overflow risk here since y < 2^136 after the first branch above.
z := shr(18, mul(z, add(y, 65536))) // A mul() is saved from starting z at 181.
// Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
// If x+1 is a perfect square, the Babylonian method cycles between
// floor(sqrt(x)) and ceil(sqrt(x)). This statement ensures we return floor.
// See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division
// Since the ceil is rare, we save gas on the assignment and repeat division in the rare case.
// If you don't care whether the floor or ceil square root is returned, you can remove this statement.
z := sub(z, lt(div(x, z), z))
}
}
function unsafeMod(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Mod x by y. Note this will return
// 0 instead of reverting if y is zero.
z := mod(x, y)
}
}
function unsafeDiv(uint256 x, uint256 y) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
// Divide x by y. Note this will return
// 0 instead of reverting if y is zero.
r := div(x, y)
}
}
function unsafeDivUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Add 1 to x * y if x % y > 0. Note this will
// return 0 instead of reverting if y is zero.
z := add(gt(mod(x, y), 0), div(x, y))
}
}
}{
"remappings": [
"@openzeppelin/=../../node_modules/@openzeppelin/",
"@uniswap/=../../node_modules/@uniswap/",
"base64-sol/=../../node_modules/base64-sol/",
"solidity-stringutils/=lib/surl/lib/solidity-stringutils/src/",
"forge-std/=lib/forge-std/src/",
"ds-test/=lib/forge-std/lib/ds-test/src/",
"surl/=lib/surl/src/",
"contracts/=contracts/",
"@contracts/=contracts/",
"@test/=test/",
"test/=test/",
"@automate/=lib/automate/contracts/",
"@pendle/=lib/pendle-core-v2-public/contracts/",
"@cryptoalgebra/=../../node_modules/@cryptoalgebra/",
"automate/=lib/automate/contracts/",
"eth-gas-reporter/=../../node_modules/eth-gas-reporter/",
"hardhat-deploy/=../../node_modules/hardhat-deploy/",
"hardhat/=../../node_modules/hardhat/",
"pendle-core-v2-public/=lib/pendle-core-v2-public/contracts/",
"pyth-sdk-solidity/=lib/pyth-sdk-solidity/",
"solmate/=lib/solmate/src/"
],
"optimizer": {
"enabled": true,
"runs": 10000
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "shanghai",
"viaIR": false,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"components":[{"internalType":"address","name":"initialize","type":"address"},{"internalType":"address","name":"deposit","type":"address"},{"internalType":"address","name":"withdraw","type":"address"},{"internalType":"address","name":"roles","type":"address"},{"internalType":"address","name":"fees","type":"address"},{"internalType":"address","name":"executions","type":"address"},{"internalType":"address","name":"vaultValue","type":"address"},{"internalType":"address","name":"resolver","type":"address"},{"internalType":"address","name":"erc4626","type":"address"},{"internalType":"address","name":"scaleBoost","type":"address"},{"internalType":"address","name":"riskManagement","type":"address"},{"internalType":"address","name":"strategy","type":"address"}],"internalType":"struct Modularity.Modules","name":"modules","type":"tuple"},{"internalType":"address","name":"nativeWrapper","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"BOOST__InvalidLength","type":"error"},{"inputs":[],"name":"BOOST__LessThanMinAmount","type":"error"},{"inputs":[],"name":"BOOST__NotSetupRewardTokens","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"BOOST__NotWhitelisted","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":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"MODULARITY_NotSelf","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"uint8","name":"bits","type":"uint8"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"SafeCastOverflowedUintDowncast","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"UPGRADE__ImplementationNotExist","type":"error"},{"inputs":[],"name":"UPGRADE__InvalidUpgrade","type":"error"},{"inputs":[],"name":"UPGRADE__NotUpgradeable","type":"error"},{"inputs":[],"name":"UPGRADE__UpgradeNotReady","type":"error"},{"inputs":[],"name":"UUPSUnauthorizedCallContext","type":"error"},{"inputs":[{"internalType":"bytes32","name":"slot","type":"bytes32"}],"name":"UUPSUnsupportedProxiableUUID","type":"error"},{"inputs":[{"internalType":"address","name":"adapter","type":"address"}],"name":"VAULT__AdapterNotFound","type":"error"},{"inputs":[{"internalType":"bytes4","name":"sig","type":"bytes4"}],"name":"VAULT__SigNotFound","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"tokens","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"minAmounts","type":"uint256[]"}],"name":"AddToWhitelist","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newImplementation","type":"address"},{"indexed":false,"internalType":"uint256","name":"proposedTime","type":"uint256"}],"name":"NewProposedVaultUpgrade","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"rewardsOut","type":"uint256[]"}],"name":"RedeemRewards","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"tokens","type":"address[]"}],"name":"RemoveFromWhitelist","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"reward","type":"uint256"}],"name":"RewardAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"rewardsToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"reward","type":"uint256"}],"name":"RewardPaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"stateMutability":"nonpayable","type":"fallback"},{"inputs":[],"name":"MODULE_DEPOSIT","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MODULE_ERC4626","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MODULE_EXECUTIONS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MODULE_FEES","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MODULE_INITIALIZE","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MODULE_RESOLVER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MODULE_RISK_MANAGEMENT","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MODULE_ROLES","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MODULE_SCALEBOOST","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MODULE_STRATEGY","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MODULE_VAULT_VALUE","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MODULE_WITHDRAW","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UPGRADE_INTERFACE_VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"activeBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"manager","type":"address"}],"name":"addManager","outputs":[],"stateMutability":"nonpayable","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":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_rewardsToken","type":"address"}],"name":"boostMinAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chargePerformanceFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"convertToAssets","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"convertToShares","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"delegateView","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"depositAsset","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"depositAsset","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"depositAndExecute","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"depositAsset","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"bytes","name":"params","type":"bytes"}],"name":"depositWithPermit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address","name":"_rewardsToken","type":"address"}],"name":"earned","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"estimateRawWithdrawEndState","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address[]","name":"","type":"address[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"address[]","name":"","type":"address[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"estimateRawWithdrawExpectedAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address[]","name":"","type":"address[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"address[]","name":"","type":"address[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"adapters","type":"address[]"},{"internalType":"bytes[]","name":"paramsList","type":"bytes[]"}],"name":"executeByManager","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address[]","name":"adapters","type":"address[]"},{"internalType":"bytes[]","name":"paramsList","type":"bytes[]"},{"internalType":"address[]","name":"readAdapters","type":"address[]"},{"internalType":"bytes[]","name":"readDatas","type":"bytes[]"}],"name":"executeByManagerAndRead","outputs":[{"components":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"bytes","name":"returnData","type":"bytes"}],"internalType":"struct ExecutesModule.Result[]","name":"results","type":"tuple[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address[]","name":"adapters","type":"address[]"},{"internalType":"bytes[]","name":"paramsList","type":"bytes[]"}],"name":"executeByOwner","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address[]","name":"adapters","type":"address[]"},{"internalType":"bytes[]","name":"paramsList","type":"bytes[]"}],"name":"executeBySelf","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"executePublicStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getAllRewardTokens","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"getAssetAccounting","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAssetDebtValue","outputs":[{"internalType":"uint256","name":"totalAsset","type":"uint256"},{"internalType":"uint256","name":"totalDebt","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"getAssetValueByAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCooldownTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCumulativePriceDeviationAllowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDailyPriceDeviation","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"getDebtAccounting","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDebtRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getDenominator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDenominatorBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDepositFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"getDepositMinimum","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFactory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFeeReceiver","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastRewardBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getManagementFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMaxCap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMaxDebtRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNetVaultValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"getNetVaultValueInAsset","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getNftToWrapper","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPerformanceFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPricePerShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_rewardsToken","type":"address"}],"name":"getRewardForDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRewardTokens","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRewardTokensCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTimelock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalAssetValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalDebtValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"getUnderlyingAssetBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getUnderlyingAssets","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getUnderlyingAssetsBalance","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"debt","type":"address"}],"name":"getUnderlyingDebtBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getUnderlyingDebts","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getUnderlyingDebtsBalance","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWithdrawFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"wrapper","type":"address"}],"name":"getWrapperToNft","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"},{"components":[{"internalType":"address","name":"denominator","type":"address"},{"internalType":"address","name":"denominatorAccounting","type":"address"},{"internalType":"uint256","name":"upgradeTimelock","type":"uint256"},{"internalType":"uint256","name":"cooldownTime","type":"uint256"},{"internalType":"bool","name":"upgradeable","type":"bool"},{"internalType":"uint256","name":"maxCap","type":"uint256"},{"internalType":"uint256","name":"maxDebtRatio","type":"uint256"},{"internalType":"uint256","name":"cumulativePriceDeviationAllowanceBps","type":"uint256"},{"internalType":"address[]","name":"initialAssets","type":"address[]"},{"internalType":"address[]","name":"initialDepositAssets","type":"address[]"},{"internalType":"address[]","name":"initialWithdrawAssets","type":"address[]"},{"internalType":"address[]","name":"initialDebts","type":"address[]"},{"internalType":"address[]","name":"initialAssetAccountings","type":"address[]"},{"internalType":"address[]","name":"initialDebtAccountings","type":"address[]"},{"internalType":"address[]","name":"initialManagerAdapters","type":"address[]"},{"internalType":"address[]","name":"initialOwnerAdapters","type":"address[]"},{"internalType":"address[]","name":"initialWithdrawAdapters","type":"address[]"}],"internalType":"struct InitializeModule.VaultParams","name":"vaultParams","type":"tuple"},{"components":[{"internalType":"address","name":"feeReceiver","type":"address"},{"internalType":"uint256","name":"depositFee","type":"uint256"},{"internalType":"uint256","name":"withdrawFee","type":"uint256"},{"internalType":"uint256","name":"performanceFee","type":"uint256"},{"internalType":"uint256","name":"managementFee","type":"uint256"}],"internalType":"struct InitializeModule.FeeParams","name":"feeParams","type":"tuple"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"isDepositAsset","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isDepositMinimumEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isDepositWhitelistEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"depositor","type":"address"}],"name":"isDepositorWhitelisted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"withdrawAsset","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"isDirectWithdraw","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"manager","type":"address"}],"name":"isManager","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"isManagerAdapter","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"isOwnerAdapter","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"isUnderlyingAsset","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"isUnderlyingDebt","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isUpgradeable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"isWithdrawAsset","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_rewardsToken","type":"address"}],"name":"lastTimeRewardApplicable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"maxDeposit","outputs":[{"internalType":"uint256","name":"maxAssets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"maxMint","outputs":[{"internalType":"uint256","name":"maxShares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"maxRedeem","outputs":[{"internalType":"uint256","name":"maxShares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"maxWithdraw","outputs":[{"internalType":"uint256","name":"maxAssets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nativeWrapper","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_rewardsToken","type":"address"},{"internalType":"uint256","name":"reward","type":"uint256"}],"name":"notifyRewardAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"depositAsset","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"previewDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewDeposit","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewMint","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewRedeem","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewWithdraw","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"withdrawAsset","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"}],"name":"proposeVaultUpgrade","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"address[]","name":"adapters","type":"address[]"},{"internalType":"bytes[]","name":"paramsList","type":"bytes[]"},{"internalType":"bool[]","name":"isWithdraw","type":"bool[]"}],"name":"rawWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"slot","type":"bytes32"}],"name":"readFromStorage","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"address[]","name":"rewardTokens","type":"address[]"}],"name":"redeemBoostReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"redeemBoostRewardAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"redeemRewards","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"redeemRewardsAndGetReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"removeDepositStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"manager","type":"address"}],"name":"removeManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"removePublicStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_rewardsToken","type":"address"}],"name":"rewardData","outputs":[{"components":[{"internalType":"uint256","name":"periodFinish","type":"uint256"},{"internalType":"uint256","name":"rewardRate","type":"uint256"},{"internalType":"uint256","name":"lastUpdateTime","type":"uint256"},{"internalType":"uint256","name":"rewardPerTokenStored","type":"uint256"}],"internalType":"struct BoostStorage.Reward","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_rewardsToken","type":"address"}],"name":"rewardPerToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newAllowance","type":"uint256"}],"name":"setCumulativePriceDeviationAllowance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"depositFee","type":"uint256"}],"name":"setDepositFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"adapters","type":"address[]"},{"internalType":"bytes[]","name":"params","type":"bytes[]"}],"name":"setDepositStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"feeReceiver","type":"address"}],"name":"setFeeReceiver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"managementFee","type":"uint256"}],"name":"setManagementFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxCap","type":"uint256"}],"name":"setMaxCap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxDebtRatio","type":"uint256"}],"name":"setMaxDebtRatio","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"performanceFee","type":"uint256"}],"name":"setPerformanceFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address[]","name":"adapters","type":"address[]"},{"internalType":"bytes[]","name":"params","type":"bytes[]"}],"name":"setPublicStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"manager","type":"address"}],"name":"setRiskManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"withdrawFee","type":"uint256"}],"name":"setWithdrawFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalActiveSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAssets","outputs":[{"internalType":"uint256","name":"totalManagedAssets","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":[{"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":"address","name":"_rewardsToken","type":"address"}],"name":"userRewardPerTokenPaid","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"withdrawAsset","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
6102406040523060805234801562000015575f80fd5b506040516200589c3803806200589c8339810160408190526200003891620001e1565b81516001600160a01b0390811660a09081526020840151821660c09081526040850151831660e090815260608601518416610100908152608087015185166101209081529387015185166101409081529287015185166101609081529187015185166101805286015184166101a0529185015183166101c0528284166101e0528401518216610200528301511661022052620000d3620000db565b50506200030f565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000900460ff16156200012c5760405163f92ee8a960e01b815260040160405180910390fd5b80546001600160401b03908116146200018c5780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b60405161018081016001600160401b0381118282101715620001bf57634e487b7160e01b5f52604160045260245ffd5b60405290565b80516001600160a01b0381168114620001dc575f80fd5b919050565b5f808284036101a0811215620001f5575f80fd5b6101808082121562000205575f80fd5b6200020f6200018f565b91506200021c85620001c5565b82526200022c60208601620001c5565b60208301526200023f60408601620001c5565b60408301526200025260608601620001c5565b60608301526200026560808601620001c5565b60808301526200027860a08601620001c5565b60a08301526200028b60c08601620001c5565b60c08301526200029e60e08601620001c5565b60e0830152610100620002b3818701620001c5565b90830152610120620002c7868201620001c5565b90830152610140620002db868201620001c5565b90830152610160620002ef868201620001c5565b818401525081935062000304818601620001c5565b925050509250929050565b60805160a05160c05160e05161010051610120516101405161016051610180516101a0516101c0516101e05161020051610220516153d6620004c65f395f8181610ce4015281816118bd01528181611d5b01528181611e180152611e4201525f8181610def01528181611b9a0152611db001525f610b8f01525f81816115cb0152818161187a01528181611942015281816119de01528181611a6301528181611b4501528181611c1b01528181611dee01528181611f270152818161203d015261206901525f8181610c2e0152818161171c0152818161184901528181611d86015261201301525f8181611598015281816118eb0152818161191601528181611be701528181611e730152611eca01525f81816114450152818161174b01528181611e9e01528181611ef6015261214801525f8181610e36015281816119760152611fdb01525f818161149201528181611b6f0152611f5101525f8181610eb60152611a3401525f818161128d015281816119a7015261209401525f818161120601528181611cf40152611d2701525f81816113d3015261217201525f81816127730152818161279c0152612ad301526153d65ff3fe60806040526004361061091b575f3560e01c80638631bb3f116104a9578063bcd1101411610268578063daa3a1631161014d578063f1229777116100c5578063f45fa71c11610094578063f5d95bf111610079578063f5d95bf1146116fa578063fac8343f14610bc9578063fe56e23214610f4457610922565b8063f45fa71c14610e58578063f520e7e51461113157610922565b8063f122977714610b1c578063f2fde38b146116db578063f3ae241514610e58578063f45346dc1461103b57610922565b8063e5a26fbe1161011c578063ef8b30f711610101578063ef8b30f714610afd578063efdcd974146116a2578063f044296d146116bc57610922565b8063e5a26fbe14611683578063e8a353921461124757610922565b8063daa3a16314610c50578063dd62ed3e146115ed578063dfcd412e14611650578063e53fbd431461166f57610922565b8063ca13779f116101e0578063d0e97e1f116101af578063d16c940c11610194578063d16c940c14610d76578063d59308ba14610b1c578063d905777e14610ed857610922565b8063d0e97e1f14610f8a578063d126932f14610be857610922565b8063ca13779f14610c50578063cdb007ee1461106d578063ce96cb7714610ed8578063d0a82cd6146115ba57610922565b8063c4f59f9b11610237578063c6e6f5921161021c578063c6e6f59214610afd578063c7352ede14610f63578063c84f3cf31461158757610922565b8063c4f59f9b14611573578063c63d75b614610ed857610922565b8063bcd1101414610b1c578063bdbef07d14610e58578063bf62bee6146114ed578063c3c8051b1461152057610922565b8063ac18de431161038e578063b6340ee211610306578063b8f82b26116102d5578063bab56cfc116102ba578063bab56cfc14610e58578063bba0d19114610ac8578063bbc6f1dc146114d357610922565b8063b8f82b26146114d3578063ba0876521461141557610922565b8063b6340ee214611481578063b66503cf146114b4578063b6ac642a14610f44578063b82b57f614610f6357610922565b8063b1c89ae41161035d578063b460af9411610342578063b460af9414611415578063b508a61c14611434578063b5c736e41461146757610922565b8063b1c89ae4146113f5578063b3d7f6b914610afd57610922565b8063ac18de4314610d90578063ad3cb1cc1461137a578063ad80ad0b146113c2578063b0274f151461125b57610922565b806391396f151161042157806395856945116103f057806396ebe732116103d557806396ebe73214610be85780639c2b1a9514610be8578063a9059cbb1461135b57610922565b8063958569451461133357806395d89b411461134757610922565b806391396f1514610f635780639262187b1461131457806392e2f5cb14610e5857806394bf804d1461108c57610922565b8063892f8db9116104785780638a26a5ed1161045d5780638a26a5ed146112af5780638da5cb5b146112d85780638f2a02b414610be857610922565b8063892f8db91461125b57806389ec00981461127c57610922565b80638631bb3f146111f5578063870de23114611228578063873e248214610fbb57806388cc58e41461124757610922565b80633be76234116106f557806364bb388f116105da578063715018a611610552578063782cd5ac116105215780637fa5110a116105065780637fa5110a1461119857806382ee866e146111b757806384d4c129146111d657610922565b8063782cd5ac14611145578063794b15b714610e5857610922565b8063715018a61461111d57806372069264146111315780637559aec3146110fe578063763265de146110fe57610922565b80636e553f65116105a957806370897b231161058e57806370897b2314610f4457806370a08231146110ab57806370f2daa6146110fe57610922565b80636e553f651461108c5780637035ab9814610d3857610922565b806364bb388f1461103b5780636811d3171461104e57806369349a9814610d765780636de796231461106d57610922565b8063502206e71161066d57806354fd4d501161063c5780636221a54b116106215780636221a54b14610be857806362ca846014610d90578063638634ee14610b1c57610922565b806354fd4d5014610ff65780635649effa14610e5857610922565b8063502206e714610f8a57806350a3ecf314610fbb57806352d1902d14610fda578063535c370c14610fee57610922565b806348e5d9f8116106c45780634bd20598116106a95780634bd2059814610f635780634cdad50614610afd5780634f1ef28614610f7757610922565b806348e5d9f814610ef2578063490ae21014610f4457610922565b80633be7623414610e865780633d68175c14610be85780634024277c14610ea5578063402d267d14610ed857610922565b8063190eaaba1161081b5780632d06177a1161079357806332ebc04b1161076257806335c08f5a1161074757806335c08f5a14610e255780633894b06514610e5857806338d52e0f14610e7257610922565b806332ebc04b14610dde5780633582d78914610e1157610922565b80632d06177a14610d905780632d9e88e114610daf578063313ce56714610dc3578063328a226314610d0657610922565b8063211dc32d116107ea57806323b872dd116107cf57806323b872dd14610d5757806323fad49b14610d06578063256110a914610d7657610922565b8063211dc32d14610d38578063235c360314610be857610922565b8063190eaaba14610c975780631b80d14914610cd35780631d63397114610d06578063202df50314610d1957610922565b80630b48a8b8116108ae57806312edb24c1161087d57806315bc54591161086257806315bc545914610c1d57806316491c3514610c5057806318160ddd14610c6457610922565b806312edb24c14610bfc5780631540aa8914610be857610922565b80630b48a8b814610b7e5780630d3896fe14610bc95780630de705b514610be857806310a4a26914610ac857610922565b80630892cd8b116108ea5780630892cd8b14610b1c578063095ea7b314610b3b57806309c5fc5614610b6a5780630a28a47714610afd57610922565b806301e1d11414610aa1578063053e938a14610ac857806306fdde0314610adc57806307a2d13a14610afd57610922565b3661092257005b34801561092d575f80fd5b505f80357fffffffff000000000000000000000000000000000000000000000000000000001681527feb5bb3420d9366368c64688d6df836957f2c655b917ed6671c4a93199009bc12602052604090205460ff166109e1576040517faa7311970000000000000000000000000000000000000000000000000000000081527fffffffff000000000000000000000000000000000000000000000000000000005f351660048201526024015b60405180910390fd5b5f80357fffffffff000000000000000000000000000000000000000000000000000000001681527feb5bb3420d9366368c64688d6df836957f2c655b917ed6671c4a93199009bc12602052604090205461010090046001600160a01b031680610a81576040517ffe8c159c0000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024016109d8565b365f80375f80365f845af43d5f803e808015610a9b573d5ff35b3d5ffd5b005b348015610aac575f80fd5b50610ab5611719565b6040519081526020015b60405180910390f35b348015610ad3575f80fd5b50610ab5611748565b348015610ae7575f80fd5b50610af0611773565b604051610abf91906144ed565b348015610b08575f80fd5b50610ab5610b173660046144ff565b611846565b348015610b27575f80fd5b50610ab5610b36366004614531565b611877565b348015610b46575f80fd5b50610b5a610b5536600461454a565b6118a2565b6040519015158152602001610abf565b348015610b75575f80fd5b50610a9f6118bb565b348015610b89575f80fd5b50610bb17f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610abf565b348015610bd4575f80fd5b50610bb1610be3366004614531565b6118e8565b348015610bf3575f80fd5b50610ab5611913565b348015610c07575f80fd5b50610c1061193e565b604051610abf91906145b4565b348015610c28575f80fd5b50610bb17f000000000000000000000000000000000000000000000000000000000000000081565b348015610c5b575f80fd5b50610b5a611913565b348015610c6f575f80fd5b507f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0254610ab5565b348015610ca2575f80fd5b507feb5bb3420d9366368c64688d6df836957f2c655b917ed6671c4a93199009bc03546001600160a01b0316610bb1565b348015610cde575f80fd5b50610bb17f000000000000000000000000000000000000000000000000000000000000000081565b610a9f610d1436600461460e565b611974565b348015610d24575f80fd5b50610a9f610d33366004614675565b6119a5565b348015610d43575f80fd5b50610ab5610d52366004614733565b6119db565b348015610d62575f80fd5b50610b5a610d71366004614764565b611a0d565b348015610d81575f80fd5b50610ab5610be3366004614531565b348015610d9b575f80fd5b50610a9f610daa366004614531565b611a32565b348015610dba575f80fd5b50610ab5611a60565b348015610dce575f80fd5b5060405160128152602001610abf565b348015610de9575f80fd5b50610bb17f000000000000000000000000000000000000000000000000000000000000000081565b348015610e1c575f80fd5b50610c10611a8a565b348015610e30575f80fd5b50610bb17f000000000000000000000000000000000000000000000000000000000000000081565b348015610e63575f80fd5b50610b5a610be3366004614531565b348015610e7d575f80fd5b50610bb1611719565b348015610e91575f80fd5b50610a9f610ea036600461479d565b611b0c565b348015610eb0575f80fd5b50610bb17f000000000000000000000000000000000000000000000000000000000000000081565b348015610ee3575f80fd5b50610ab5610b17366004614531565b348015610efd575f80fd5b50610f11610f0c366004614531565b611b1c565b604051610abf91908151815260208083015190820152604080830151908201526060918201519181019190915260800190565b348015610f4f575f80fd5b50610a9f610f5e3660046144ff565b611b6d565b348015610f6e575f80fd5b50610ab5611b97565b610a9f610f8536600461491c565b611bc2565b348015610f95575f80fd5b50610fa9610fa43660046144ff565b611bdd565b604051610abf96959493929190614995565b348015610fc6575f80fd5b50610a9f610fd5366004614531565b611c19565b348015610fe5575f80fd5b50610ab5611c43565b610a9f611c71565b348015611001575f80fd5b5060408051808201909152600381527f312e3000000000000000000000000000000000000000000000000000000000006020820152610af0565b610ab56110493660046149fa565b611cf1565b348015611059575f80fd5b50610ab5611068366004614a33565b611d24565b348015611078575f80fd5b50610a9f6110873660046144ff565b611d59565b348015611097575f80fd5b50610ab56110a6366004614ac6565b611d83565b3480156110b6575f80fd5b50610ab56110c5366004614531565b6001600160a01b03165f9081527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00602052604090205490565b348015611109575f80fd5b50610a9f6111183660046144ff565b611dae565b348015611128575f80fd5b50610a9f611dd8565b34801561113c575f80fd5b50610ab5611deb565b348015611150575f80fd5b50610ab561115f366004614531565b6001600160a01b03165f9081527feb5bb3420d9366368c64688d6df836957f2c655b917ed6671c4a93199009bc24602052604090205490565b3480156111a3575f80fd5b50610a9f6111b2366004614bf5565b611e16565b3480156111c2575f80fd5b50610a9f6111d1366004614c4b565b611e40565b3480156111e1575f80fd5b50610b5a6111f036600461454a565b611e70565b348015611200575f80fd5b50610bb17f000000000000000000000000000000000000000000000000000000000000000081565b348015611233575f80fd5b50610ab561124236600461454a565b611e9b565b348015611252575f80fd5b50610bb1611913565b348015611266575f80fd5b5061126f611ec6565b604051610abf9190614cb3565b348015611287575f80fd5b50610bb17f000000000000000000000000000000000000000000000000000000000000000081565b3480156112ba575f80fd5b506112c3611ef2565b60408051928352602083019190915201610abf565b3480156112e3575f80fd5b507f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b0316610bb1565b34801561131f575f80fd5b5061126f61132e366004614531565b611f23565b34801561133e575f80fd5b50610a9f611f4f565b348015611352575f80fd5b50610af0611f79565b348015611366575f80fd5b50610b5a61137536600461454a565b611fca565b348015611385575f80fd5b50610af06040518060400160405280600581526020017f352e302e3000000000000000000000000000000000000000000000000000000081525081565b3480156113cd575f80fd5b50610bb17f000000000000000000000000000000000000000000000000000000000000000081565b611408611403366004614cc5565b611fd7565b604051610abf9190614d80565b348015611420575f80fd5b50610ab561142f366004614e12565b612010565b34801561143f575f80fd5b50610bb17f000000000000000000000000000000000000000000000000000000000000000081565b348015611472575f80fd5b50610ab5610be33660046144ff565b34801561148c575f80fd5b50610bb17f000000000000000000000000000000000000000000000000000000000000000081565b3480156114bf575f80fd5b50610a9f6114ce36600461454a565b61203b565b3480156114de575f80fd5b50610ab56111f036600461454a565b3480156114f8575f80fd5b507f42eb16b0bf2565d9a663d4e7253d588f054024f7228c103568322f697f63b61354610ab5565b34801561152b575f80fd5b50610bb161153a3660046144ff565b5f9081527feb5bb3420d9366368c64688d6df836957f2c655b917ed6671c4a93199009bc2360205260409020546001600160a01b031690565b34801561157e575f80fd5b50610c10612065565b348015611592575f80fd5b50610bb17f000000000000000000000000000000000000000000000000000000000000000081565b3480156115c5575f80fd5b50610bb17f000000000000000000000000000000000000000000000000000000000000000081565b3480156115f8575f80fd5b50610ab5611607366004614733565b6001600160a01b039182165f9081527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace016020908152604080832093909416825291909152205490565b34801561165b575f80fd5b50610ab561166a366004614e42565b612091565b34801561167a575f80fd5b50610c106120c5565b34801561168e575f80fd5b50610ab561169d366004614531565b612145565b3480156116ad575f80fd5b50610a9f610f5e366004614531565b3480156116c7575f80fd5b50610a9f6116d6366004614f17565b612170565b3480156116e6575f80fd5b50610a9f6116f5366004614531565b61219a565b348015611705575f80fd5b50610a9f611714366004614531565b6121ed565b5f7f00000000000000000000000000000000000000000000000000000000000000006117448161243d565b5090565b5f7f00000000000000000000000000000000000000000000000000000000000000006117448161243d565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0380546060917f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00916117c490615165565b80601f01602080910402602001604051908101604052809291908181526020018280546117f090615165565b801561183b5780601f106118125761010080835404028352916020019161183b565b820191905f5260205f20905b81548152906001019060200180831161181e57829003601f168201915b505050505091505090565b5f7f00000000000000000000000000000000000000000000000000000000000000006118718161243d565b50919050565b5f7f00000000000000000000000000000000000000000000000000000000000000006118718161243d565b5f336118af818585612482565b60019150505b92915050565b7f00000000000000000000000000000000000000000000000000000000000000006118e581610a81565b50565b5f7f00000000000000000000000000000000000000000000000000000000000000006118718161243d565b5f7f00000000000000000000000000000000000000000000000000000000000000006117448161243d565b60607f000000000000000000000000000000000000000000000000000000000000000061196961248f565b91506117448161243d565b7f000000000000000000000000000000000000000000000000000000000000000061199e81610a81565b5050505050565b7f00000000000000000000000000000000000000000000000000000000000000006119cf81610a81565b50505050505050505050565b5f7f0000000000000000000000000000000000000000000000000000000000000000611a068161243d565b5092915050565b5f33611a1a8582856124bf565b611a2585858561258b565b60019150505b9392505050565b7f0000000000000000000000000000000000000000000000000000000000000000611a5c81610a81565b5050565b5f7f000000000000000000000000000000000000000000000000000000000000000061196961261a565b60607feb5bb3420d9366368c64688d6df836957f2c655b917ed6671c4a93199009bc00600501805480602002602001604051908101604052809291908181526020018280548015611b0257602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311611ae4575b5050505050905090565b611b17838383612644565b505050565b611b4360405180608001604052805f81526020015f81526020015f81526020015f81525090565b7f00000000000000000000000000000000000000000000000000000000000000006118718161243d565b7f0000000000000000000000000000000000000000000000000000000000000000611a5c81610a81565b5f7f00000000000000000000000000000000000000000000000000000000000000006117448161243d565b611bca612768565b611bd382612838565b611a5c82826129a9565b5f806060806060807f0000000000000000000000000000000000000000000000000000000000000000611c0f8161243d565b5091939550919395565b7f0000000000000000000000000000000000000000000000000000000000000000611a5c81610a81565b5f611c4c612ac8565b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc90565b333014611caa576040517fde86987d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc36015f8160248237808183836004355af491503d81823e818015611ced573d82f35b3d82fd5b5f7f0000000000000000000000000000000000000000000000000000000000000000611d1c81610a81565b509392505050565b5f7f0000000000000000000000000000000000000000000000000000000000000000611d4f81610a81565b5095945050505050565b7f0000000000000000000000000000000000000000000000000000000000000000611a5c81610a81565b5f7f0000000000000000000000000000000000000000000000000000000000000000611a0681610a81565b7f0000000000000000000000000000000000000000000000000000000000000000611a5c81610a81565b611de0612b2a565b611de95f612b9e565b565b5f7f00000000000000000000000000000000000000000000000000000000000000006117448161243d565b7f0000000000000000000000000000000000000000000000000000000000000000611b1781610a81565b7f0000000000000000000000000000000000000000000000000000000000000000611e6a81610a81565b50505050565b5f7f0000000000000000000000000000000000000000000000000000000000000000611a068161243d565b5f7f0000000000000000000000000000000000000000000000000000000000000000611a068161243d565b60607f00000000000000000000000000000000000000000000000000000000000000006117448161243d565b5f807f0000000000000000000000000000000000000000000000000000000000000000611f1e8161243d565b509091565b60607f000000000000000000000000000000000000000000000000000000000000000061187181610a81565b7f00000000000000000000000000000000000000000000000000000000000000006118e581610a81565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0480546060917f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00916117c490615165565b5f336118af81858561258b565b60607f000000000000000000000000000000000000000000000000000000000000000061200381610a81565b5098975050505050505050565b5f7f0000000000000000000000000000000000000000000000000000000000000000611d1c81610a81565b7f0000000000000000000000000000000000000000000000000000000000000000611b1781610a81565b60607f00000000000000000000000000000000000000000000000000000000000000006117448161243d565b5f7f00000000000000000000000000000000000000000000000000000000000000006120bc81610a81565b50949350505050565b60607feb5bb3420d9366368c64688d6df836957f2c655b917ed6671c4a93199009bc00600601805480602002602001604051908101604052809291908181526020018280548015611b0257602002820191905f5260205f209081546001600160a01b03168152600190910190602001808311611ae4575050505050905090565b5f7f00000000000000000000000000000000000000000000000000000000000000006118718161243d565b7f000000000000000000000000000000000000000000000000000000000000000061199e81610a81565b6121a2612b2a565b6001600160a01b0381166121e4576040517f1e4fbdf70000000000000000000000000000000000000000000000000000000081525f60048201526024016109d8565b6118e581612b9e565b6121f5612b2a565b7feb5bb3420d9366368c64688d6df836957f2c655b917ed6671c4a93199009bc005474010000000000000000000000000000000000000000900460ff16612268576040517fb4578e8700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7feb5bb3420d9366368c64688d6df836957f2c655b917ed6671c4a93199009bc00546001600160a01b0316639bb8dcfd6122c97f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b0391821660048201529084166024820152604401602060405180830381865afa15801561232b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061234f91906151b0565b612385576040517fc5be01ad00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7feb5bb3420d9366368c64688d6df836957f2c655b917ed6671c4a93199009bc1b80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038316908117909155427feb5bb3420d9366368c64688d6df836957f2c655b917ed6671c4a93199009bc1c81905560408051928352602083019190915280517ffed9008e709886827269b7d7d66b3c92de71653a80e2265584ef0cd47a8bdfbf9281900390910190a150565b7f535c370c000000000000000000000000000000000000000000000000000000005f5280600452365f6024375f80602436015f305afa3d5f803e808015610a9b573d5ff35b611b178383836001612c26565b60606124ba7f0437d4a732399ef7f2c8fca6343f4e97d989d30f9900ddd012da8b53d6c89005612d4e565b905090565b6001600160a01b038381165f9081527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0160209081526040808320938616835292905220547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114611e6a578181101561257d576040517ffb8f41b20000000000000000000000000000000000000000000000000000000081526001600160a01b038416600482015260248101829052604481018390526064016109d8565b611e6a84848484035f612c26565b6001600160a01b0383166125cd576040517f96c6fd1e0000000000000000000000000000000000000000000000000000000081525f60048201526024016109d8565b6001600160a01b03821661260f576040517fec442f050000000000000000000000000000000000000000000000000000000081525f60048201526024016109d8565b611b17838383612d5a565b5f6124ba7f0437d4a732399ef7f2c8fca6343f4e97d989d30f9900ddd012da8b53d6c89005612d86565b61264d83612d8f565b7f0437d4a732399ef7f2c8fca6343f4e97d989d30f9900ddd012da8b53d6c890005f5b8281101561199e575f84848381811061268b5761268b6151cb565b90506020020160208101906126a09190614531565b6001600160a01b038088165f9081526003860160209081526040808320938516835292905220549091508015612753576001600160a01b038088165f908152600386016020908152604080832093861680845293909152812055612705908883612ecb565b816001600160a01b0316876001600160a01b03167f540798df468d7b23d11f156fdb954cb19ad414d150722a7b6d55ba369dea792e8360405161274a91815260200190565b60405180910390a35b5050808061276090615225565b915050612670565b306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148061280157507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166127f57f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b6001600160a01b031614155b15611de9576040517fe07c8dba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612840612b2a565b7feb5bb3420d9366368c64688d6df836957f2c655b917ed6671c4a93199009bc005474010000000000000000000000000000000000000000900460ff166128b3576040517fb4578e8700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7feb5bb3420d9366368c64688d6df836957f2c655b917ed6671c4a93199009bc01547feb5bb3420d9366368c64688d6df836957f2c655b917ed6671c4a93199009bc1c5442916129029161525c565b111561293a576040517f2cac76cf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0381167feb5bb3420d9366368c64688d6df836957f2c655b917ed6671c4a93199009bc00601b01546001600160a01b0316146118e5576040517f352839fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015612a21575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201909252612a1e9181019061526f565b60015b612a62576040517f4c9c8ce30000000000000000000000000000000000000000000000000000000081526001600160a01b03831660048201526024016109d8565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8114612abe576040517faa1d49a4000000000000000000000000000000000000000000000000000000008152600481018290526024016109d8565b611b178383612f4b565b306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611de9576040517fe07c8dba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33612b5c7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b6001600160a01b031614611de9576040517f118cdaa70000000000000000000000000000000000000000000000000000000081523360048201526024016109d8565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080547fffffffffffffffffffffffff000000000000000000000000000000000000000081166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a3505050565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace006001600160a01b038516612c89576040517fe602df050000000000000000000000000000000000000000000000000000000081525f60048201526024016109d8565b6001600160a01b038416612ccb576040517f94280d620000000000000000000000000000000000000000000000000000000081525f60048201526024016109d8565b6001600160a01b038086165f9081526001830160209081526040808320938816835292905220839055811561199e57836001600160a01b0316856001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92585604051612d3f91815260200190565b60405180910390a35050505050565b60605f611a2b83612fa0565b612d65838383612ff9565b612d70838383613003565b612d7b838383613053565b611b178383836131b8565b5f6118b5825490565b7f0437d4a732399ef7f2c8fca6343f4e97d989d30f9900ddd012da8b53d6c890005f612dda7f0437d4a732399ef7f2c8fca6343f4e97d989d30f9900ddd012da8b53d6c89005612d4e565b90505f5b8151811015611e6a575f828281518110612dfa57612dfa6151cb565b60200260200101519050612e0d816131c2565b6001600160a01b0382165f908152600186016020526040902060030155612e33816132aa565b6001600160a01b038083165f908152600187016020526040902060020191909155851615612eb857612e658582613319565b6001600160a01b038087165f8181526003808901602090815260408084209588168085529582528084209690965560018a0181528583209091015492825260028901815284822093825292909252919020555b5080612ec381615225565b915050612dde565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052611b179084906133fa565b612f5482613474565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a2805115612f9857611b17828261351b565b611a5c61358d565b6060815f01805480602002602001604051908101604052809291908181526020018280548015612fed57602002820191905f5260205f20905b815481526020019060010190808311612fd9575b50505050509050919050565b611b1783836135c5565b6001600160a01b0383161561301b5761301b83612d8f565b6001600160a01b038216158015906130455750826001600160a01b0316826001600160a01b031614155b15611b1757611b1782612d8f565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace006001600160a01b0384166130a05781816002015f828254613095919061525c565b909155506131299050565b6001600160a01b0384165f908152602082905260409020548281101561310b576040517fe450d38c0000000000000000000000000000000000000000000000000000000081526001600160a01b038616600482015260248101829052604481018490526064016109d8565b6001600160a01b0385165f9081526020839052604090209083900390555b6001600160a01b038316613147576002810180548390039055613165565b6001600160a01b0383165f9081526020829052604090208054830190555b826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516131aa91815260200190565b60405180910390a350505050565b611b178383613643565b5f7f0437d4a732399ef7f2c8fca6343f4e97d989d30f9900ddd012da8b53d6c89000816131ed6136a1565b9050805f0361321a57506001600160a01b039092165f908152600190920160205250604090206003015490565b6001600160a01b0384165f908152600180840160205260409091209081015460029091015482919061324b876132aa565b6132559190615286565b61325f9190615299565b61327190670de0b6b3a7640000615299565b61327b91906152b0565b6001600160a01b0385165f9081526001840160205260409020600301546132a2919061525c565b949350505050565b6001600160a01b0381165f9081527f0437d4a732399ef7f2c8fca6343f4e97d989d30f9900ddd012da8b53d6c8900160205260408120547f0437d4a732399ef7f2c8fca6343f4e97d989d30f9900ddd012da8b53d6c890009042811161331057806132a2565b42949350505050565b6001600160a01b038281165f8181527f0437d4a732399ef7f2c8fca6343f4e97d989d30f9900ddd012da8b53d6c8900360209081526040808320948616808452948252808320549383527f0437d4a732399ef7f2c8fca6343f4e97d989d30f9900ddd012da8b53d6c890028252808320948352939052918220547f0437d4a732399ef7f2c8fca6343f4e97d989d30f9900ddd012da8b53d6c890009190670de0b6b3a7640000906133c9866131c2565b6133d39190615286565b6133dc876136ca565b6133e69190615299565b6133f091906152b0565b6132a2919061525c565b5f61340e6001600160a01b03841683613706565b905080515f1415801561343257508080602001905181019061343091906151b0565b155b15611b17576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b03841660048201526024016109d8565b806001600160a01b03163b5f036134c2576040517f4c9c8ce30000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024016109d8565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b60605f80846001600160a01b03168460405161353791906152e8565b5f60405180830381855af49150503d805f811461356f576040519150601f19603f3d011682016040523d82523d5f602084013e613574565b606091505b5091509150613584858383613713565b95945050505050565b3415611de9576040517fb398979f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f806135cf613788565b9150915081515f036135e15750505050565b6001600160a01b0384161580159061360257506001600160a01b0384163014155b1561361257613612848383613b4e565b6001600160a01b0383161580159061363357506001600160a01b0383163014155b15611e6a57611e6a838383613b4e565b6001600160a01b0382161580159061366457506001600160a01b0382163014155b156136725761367282613eb8565b6001600160a01b0381161580159061369357506001600160a01b0381163014155b15611a5c57611a5c81613eb8565b5f6124ba7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace025490565b6001600160a01b0381165f9081527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0060205260408120546118b5565b6060611a2b83835f613fc5565b6060826137285761372382614077565b611a2b565b815115801561373f57506001600160a01b0384163b155b15613781576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b03851660048201526024016109d8565b5080611a2b565b6060806137936140b9565b9150815167ffffffffffffffff8111156137af576137af6147ec565b6040519080825280602002602001820160405280156137d8578160200160208202803683370190505b50905081515f036137e7579091565b7f42eb16b0bf2565d9a663d4e7253d588f054024f7228c103568322f697f63b61380544314613abd574381555f61383c7f24bc46ff97535a32ac9a9fd00a6caac7641d058373f14d0429bdbb23908d69d55490565b9050613846614107565b5f5b8451811015613aba575f858281518110613864576138646151cb565b6020908102919091018101516001600160a01b0381165f908152600287019092526040822054885191935070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16908890859081106138c8576138c86151cb565b60209081029190910101516040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa15801561392f573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613953919061526f565b61395d9190615286565b6001600160a01b0383165f9081526002870160205260408120549192506fffffffffffffffffffffffffffffffff9091169081900361399a575060015b84156139b7576139aa8286614195565b6139b4908261525c565b90505b6139c0816141a9565b6001600160a01b0384165f908152600288016020526040902080547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff92909216919091179055613a21826141a9565b6001600160a01b0384165f90815260028801602052604090208054601090613a7090849070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16615303565b92506101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff16021790555050505080613ab390615225565b9050613848565b50505b5f5b8351811015613b4857816002015f858381518110613adf57613adf6151cb565b6020908102919091018101516001600160a01b031682528101919091526040015f205483516fffffffffffffffffffffffffffffffff90911690849083908110613b2b57613b2b6151cb565b602090810291909101015280613b4081615225565b915050613abf565b50509091565b6001600160a01b03831615801590613b6f57506001600160a01b0383163014155b613b7b57613b7b61532c565b7f42eb16b0bf2565d9a663d4e7253d588f054024f7228c103568322f697f63b6135f613bda856001600160a01b03165f9081527f24bc46ff97535a32ac9a9fd00a6caac7641d058373f14d0429bdbb23908d69d6602052604090205490565b90505f5b8451811015613eb0575f858281518110613bfa57613bfa6151cb565b602002602001015190505f858381518110613c1757613c176151cb565b6020908102919091018101516001600160a01b038085165f9081526001890184526040808220928d168252919093528220549092506fffffffffffffffffffffffffffffffff1690819003613cdf57613c6f826141a9565b6001600160a01b039384165f9081526001880160209081526040808320968d1683529590529390932080547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff9094169390931790925550613ea09050565b818103613cee57505050613ea0565b5f613cf98284615286565b90505f613d0687836141fe565b90505f81896001015f886001600160a01b03166001600160a01b031681526020019081526020015f205f8e6001600160a01b03166001600160a01b031681526020019081526020015f205f0160109054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff16613d8b919061525c565b90506040518060400160405280613da1876141a9565b6fffffffffffffffffffffffffffffffff168152602001613dc1836141a9565b6fffffffffffffffffffffffffffffffff16815250896001015f886001600160a01b03166001600160a01b031681526020019081526020015f205f8e6001600160a01b03166001600160a01b031681526020019081526020015f205f820151815f015f6101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055506020820151815f0160106101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055509050505050505050505b613ea981615225565b9050613bde565b505050505050565b6001600160a01b03811615801590613ed957506001600160a01b0381163014155b613ee557613ee561532c565b5f613eef826136ca565b90505f613efc8383614212565b90505f613f09828461434e565b6001600160a01b0385165f9081527f24bc46ff97535a32ac9a9fd00a6caac7641d058373f14d0429bdbb23908d69d660205260409020547f24bc46ff97535a32ac9a9fd00a6caac7641d058373f14d0429bdbb23908d69d5549192507f24bc46ff97535a32ac9a9fd00a6caac7641d058373f14d0429bdbb23908d69d2918391613f9291615286565b613f9c919061525c565b60038201556001600160a01b039094165f90815260049094016020526040909320929092555050565b606081471015614003576040517fcd7860590000000000000000000000000000000000000000000000000000000081523060048201526024016109d8565b5f80856001600160a01b0316848660405161401e91906152e8565b5f6040518083038185875af1925050503d805f8114614058576040519150601f19603f3d011682016040523d82523d5f602084013e61405d565b606091505b509150915061406d868383613713565b9695505050505050565b8051156140875780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080515f80825260208201909252606091506141017f24bc46ff97535a32ac9a9fd00a6caac7641d058373f14d0429bdbb23908d69d25482906001600160a01b0316614363565b91505090565b7f24bc46ff97535a32ac9a9fd00a6caac7641d058373f14d0429bdbb23908d69d454604080517f8113382700000000000000000000000000000000000000000000000000000000815290516001600160a01b03909216916381133827916004808201925f9290919082900301818387803b158015614183575f80fd5b505af1158015611e6a573d5f803e3d5ffd5b5f611a2b83670de0b6b3a764000084614448565b5f6fffffffffffffffffffffffffffffffff821115611744576040517f6dfcc65000000000000000000000000000000000000000000000000000000000815260806004820152602481018390526044016109d8565b5f611a2b8383670de0b6b3a7640000614448565b5f807f24bc46ff97535a32ac9a9fd00a6caac7641d058373f14d0429bdbb23908d69d260018101546040517fe268b3a40000000000000000000000000000000000000000000000000000000081526001600160a01b0387811660048301529293505f928392169063e268b3a49060240160408051808303815f875af115801561429d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906142c19190615378565b6fffffffffffffffffffffffffffffffff91821693501690505f60646142e8602888615299565b6142f291906152b0565b9050821561406d576064614307602882615286565b84846143116136a1565b61431b9190615299565b61432591906152b0565b61432f9190615299565b61433991906152b0565b614343908261525c565b979650505050505050565b5f81831061435c5781611a2b565b5090919050565b815160609061437381600161525c565b67ffffffffffffffff81111561438b5761438b6147ec565b6040519080825280602002602001820160405280156143b4578160200160208202803683370190505b5091505f5b8181101561440d578481815181106143d3576143d36151cb565b60200260200101518382815181106143ed576143ed6151cb565b6001600160a01b03909216602092830291909101909101526001016143b9565b5082828281518110614421576144216151cb565b60200260200101906001600160a01b031690816001600160a01b0316815250505092915050565b5f827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048411830215820261447b575f80fd5b5091020490565b5f5b8381101561449c578181015183820152602001614484565b50505f910152565b5f81518084526144bb816020860160208601614482565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081525f611a2b60208301846144a4565b5f6020828403121561450f575f80fd5b5035919050565b80356001600160a01b038116811461452c575f80fd5b919050565b5f60208284031215614541575f80fd5b611a2b82614516565b5f806040838503121561455b575f80fd5b61456483614516565b946020939093013593505050565b5f8151808452602080850194508084015f5b838110156145a95781516001600160a01b031687529582019590820190600101614584565b509495945050505050565b602081525f611a2b6020830184614572565b5f8083601f8401126145d6575f80fd5b50813567ffffffffffffffff8111156145ed575f80fd5b6020830191508360208260051b8501011115614607575f80fd5b9250929050565b5f805f8060408587031215614621575f80fd5b843567ffffffffffffffff80821115614638575f80fd5b614644888389016145c6565b9096509450602087013591508082111561465c575f80fd5b50614669878288016145c6565b95989497509550505050565b5f805f805f805f805f60c08a8c03121561468d575f80fd5b8935985061469d60208b01614516565b97506146ab60408b01614516565b965060608a013567ffffffffffffffff808211156146c7575f80fd5b6146d38d838e016145c6565b909850965060808c01359150808211156146eb575f80fd5b6146f78d838e016145c6565b909650945060a08c013591508082111561470f575f80fd5b5061471c8c828d016145c6565b915080935050809150509295985092959850929598565b5f8060408385031215614744575f80fd5b61474d83614516565b915061475b60208401614516565b90509250929050565b5f805f60608486031215614776575f80fd5b61477f84614516565b925061478d60208501614516565b9150604084013590509250925092565b5f805f604084860312156147af575f80fd5b6147b884614516565b9250602084013567ffffffffffffffff8111156147d3575f80fd5b6147df868287016145c6565b9497909650939450505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b604051610220810167ffffffffffffffff8111828210171561483d5761483d6147ec565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561488a5761488a6147ec565b604052919050565b5f82601f8301126148a1575f80fd5b813567ffffffffffffffff8111156148bb576148bb6147ec565b6148ec60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601614843565b818152846020838601011115614900575f80fd5b816020850160208301375f918101602001919091529392505050565b5f806040838503121561492d575f80fd5b61493683614516565b9150602083013567ffffffffffffffff811115614951575f80fd5b61495d85828601614892565b9150509250929050565b5f8151808452602080850194508084015f5b838110156145a957815187529582019590820190600101614979565b86815285602082015260c060408201525f6149b360c0830187614572565b82810360608401526149c58187614967565b905082810360808401526149d98186614572565b905082810360a08401526149ed8185614967565b9998505050505050505050565b5f805f60608486031215614a0c575f80fd5b614a1584614516565b925060208401359150614a2a60408501614516565b90509250925092565b5f805f805f60808688031215614a47575f80fd5b614a5086614516565b945060208601359350614a6560408701614516565b9250606086013567ffffffffffffffff80821115614a81575f80fd5b818801915088601f830112614a94575f80fd5b813581811115614aa2575f80fd5b896020828501011115614ab3575f80fd5b9699959850939650602001949392505050565b5f8060408385031215614ad7575f80fd5b8235915061475b60208401614516565b5f67ffffffffffffffff821115614b0057614b006147ec565b5060051b60200190565b5f82601f830112614b19575f80fd5b81356020614b2e614b2983614ae7565b614843565b82815260059290921b84018101918181019086841115614b4c575f80fd5b8286015b84811015614b6e57614b6181614516565b8352918301918301614b50565b509695505050505050565b5f82601f830112614b88575f80fd5b81356020614b98614b2983614ae7565b82815260059290921b84018101918181019086841115614bb6575f80fd5b8286015b84811015614b6e57803567ffffffffffffffff811115614bd9575f8081fd5b614be78986838b0101614892565b845250918301918301614bba565b5f8060408385031215614c06575f80fd5b823567ffffffffffffffff80821115614c1d575f80fd5b614c2986838701614b0a565b93506020850135915080821115614c3e575f80fd5b5061495d85828601614b79565b5f805f60608486031215614c5d575f80fd5b83359250602084013567ffffffffffffffff80821115614c7b575f80fd5b614c8787838801614b0a565b93506040860135915080821115614c9c575f80fd5b50614ca986828701614b79565b9150509250925092565b602081525f611a2b6020830184614967565b5f805f805f805f806080898b031215614cdc575f80fd5b883567ffffffffffffffff80821115614cf3575f80fd5b614cff8c838d016145c6565b909a50985060208b0135915080821115614d17575f80fd5b614d238c838d016145c6565b909850965060408b0135915080821115614d3b575f80fd5b614d478c838d016145c6565b909650945060608b0135915080821115614d5f575f80fd5b50614d6c8b828c016145c6565b999c989b5096995094979396929594505050565b5f6020808301818452808551808352604092508286019150828160051b8701018488015f5b83811015614e04578883037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc00185528151805115158452870151878401879052614df1878501826144a4565b9588019593505090860190600101614da5565b509098975050505050505050565b5f805f60608486031215614e24575f80fd5b83359250614e3460208501614516565b9150614a2a60408501614516565b5f805f8060808587031215614e55575f80fd5b614e5e85614516565b935060208501359250614e7360408601614516565b9150614e8160608601614516565b905092959194509250565b80151581146118e5575f80fd5b803561452c81614e8c565b5f60a08284031215614eb4575f80fd5b60405160a0810181811067ffffffffffffffff82111715614ed757614ed76147ec565b604052905080614ee683614516565b8152602083013560208201526040830135604082015260608301356060820152608083013560808201525092915050565b5f805f80610100808688031215614f2c575f80fd5b853567ffffffffffffffff80821115614f43575f80fd5b614f4f89838a01614892565b96506020880135915080821115614f64575f80fd5b614f7089838a01614892565b95506040880135915080821115614f85575f80fd5b90870190610220828a031215614f99575f80fd5b614fa1614819565b614faa83614516565b8152614fb860208401614516565b60208201526040830135604082015260608301356060820152614fdd60808401614e99565b608082015260a083013560a082015260c083013560c082015260e083013560e08201528383013582811115615010575f80fd5b61501c8b828601614b0a565b858301525061012093508383013582811115615036575f80fd5b6150428b828601614b0a565b85830152506101409350838301358281111561505c575f80fd5b6150688b828601614b0a565b858301525061016093508383013582811115615082575f80fd5b61508e8b828601614b0a565b8583015250610180935083830135828111156150a8575f80fd5b6150b48b828601614b0a565b85830152506101a0935083830135828111156150ce575f80fd5b6150da8b828601614b0a565b85830152506101c0935083830135828111156150f4575f80fd5b6151008b828601614b0a565b85830152506101e09350838301358281111561511a575f80fd5b6151268b828601614b0a565b858301525061020093508383013582811115615140575f80fd5b61514c8b828601614b0a565b858301525080955050505050614e818660608701614ea4565b600181811c9082168061517957607f821691505b602082108103611871577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f602082840312156151c0575f80fd5b8151611a2b81614e8c565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203615255576152556151f8565b5060010190565b808201808211156118b5576118b56151f8565b5f6020828403121561527f575f80fd5b5051919050565b818103818111156118b5576118b56151f8565b80820281158282048414176118b5576118b56151f8565b5f826152e3577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b5f82516152f9818460208701614482565b9190910192915050565b6fffffffffffffffffffffffffffffffff818116838216019080821115611a0657611a066151f8565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52600160045260245ffd5b80516fffffffffffffffffffffffffffffffff8116811461452c575f80fd5b5f8060408385031215615389575f80fd5b61539283615359565b915061475b6020840161535956fea2646970667358221220c8a3325a22f45c8049e5495adc3650aa0219e697d5f272a05d5e4a45f92fdbdf64736f6c634300081400330000000000000000000000001331e781c6d2219741b1c9b46ec4afcb1d1a11060000000000000000000000002dc7ad9b3397ee1813a2004a7787cd53d7fd02a0000000000000000000000000ac694981a40621f67a73b02e67fa29054c13b392000000000000000000000000302375ea70ac865bf44fc298d4459b3cbd01889c0000000000000000000000004db1383dd215786d7b02bcee7823619efc51e97a000000000000000000000000cdddf49aa37e18dc3a13ef14694e7ddaf3356fd8000000000000000000000000a0aae225faca0ffb747fed1fa0526645a427c1500000000000000000000000007c5027a145bd43fc6f7cd51040b1fef6b1f970e80000000000000000000000008ea93a5ae50bc7a949590d2da237b21a375edfb200000000000000000000000009c784690a36e9449f78f60d9daf6c3403d2384000000000000000000000000058ca3045f4914bf702c7203b29a1d65856bd8bf700000000000000000000000028cd7540cb8c510b6b356fa446f1efb399004a9200000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab1
Deployed Bytecode
0x60806040526004361061091b575f3560e01c80638631bb3f116104a9578063bcd1101411610268578063daa3a1631161014d578063f1229777116100c5578063f45fa71c11610094578063f5d95bf111610079578063f5d95bf1146116fa578063fac8343f14610bc9578063fe56e23214610f4457610922565b8063f45fa71c14610e58578063f520e7e51461113157610922565b8063f122977714610b1c578063f2fde38b146116db578063f3ae241514610e58578063f45346dc1461103b57610922565b8063e5a26fbe1161011c578063ef8b30f711610101578063ef8b30f714610afd578063efdcd974146116a2578063f044296d146116bc57610922565b8063e5a26fbe14611683578063e8a353921461124757610922565b8063daa3a16314610c50578063dd62ed3e146115ed578063dfcd412e14611650578063e53fbd431461166f57610922565b8063ca13779f116101e0578063d0e97e1f116101af578063d16c940c11610194578063d16c940c14610d76578063d59308ba14610b1c578063d905777e14610ed857610922565b8063d0e97e1f14610f8a578063d126932f14610be857610922565b8063ca13779f14610c50578063cdb007ee1461106d578063ce96cb7714610ed8578063d0a82cd6146115ba57610922565b8063c4f59f9b11610237578063c6e6f5921161021c578063c6e6f59214610afd578063c7352ede14610f63578063c84f3cf31461158757610922565b8063c4f59f9b14611573578063c63d75b614610ed857610922565b8063bcd1101414610b1c578063bdbef07d14610e58578063bf62bee6146114ed578063c3c8051b1461152057610922565b8063ac18de431161038e578063b6340ee211610306578063b8f82b26116102d5578063bab56cfc116102ba578063bab56cfc14610e58578063bba0d19114610ac8578063bbc6f1dc146114d357610922565b8063b8f82b26146114d3578063ba0876521461141557610922565b8063b6340ee214611481578063b66503cf146114b4578063b6ac642a14610f44578063b82b57f614610f6357610922565b8063b1c89ae41161035d578063b460af9411610342578063b460af9414611415578063b508a61c14611434578063b5c736e41461146757610922565b8063b1c89ae4146113f5578063b3d7f6b914610afd57610922565b8063ac18de4314610d90578063ad3cb1cc1461137a578063ad80ad0b146113c2578063b0274f151461125b57610922565b806391396f151161042157806395856945116103f057806396ebe732116103d557806396ebe73214610be85780639c2b1a9514610be8578063a9059cbb1461135b57610922565b8063958569451461133357806395d89b411461134757610922565b806391396f1514610f635780639262187b1461131457806392e2f5cb14610e5857806394bf804d1461108c57610922565b8063892f8db9116104785780638a26a5ed1161045d5780638a26a5ed146112af5780638da5cb5b146112d85780638f2a02b414610be857610922565b8063892f8db91461125b57806389ec00981461127c57610922565b80638631bb3f146111f5578063870de23114611228578063873e248214610fbb57806388cc58e41461124757610922565b80633be76234116106f557806364bb388f116105da578063715018a611610552578063782cd5ac116105215780637fa5110a116105065780637fa5110a1461119857806382ee866e146111b757806384d4c129146111d657610922565b8063782cd5ac14611145578063794b15b714610e5857610922565b8063715018a61461111d57806372069264146111315780637559aec3146110fe578063763265de146110fe57610922565b80636e553f65116105a957806370897b231161058e57806370897b2314610f4457806370a08231146110ab57806370f2daa6146110fe57610922565b80636e553f651461108c5780637035ab9814610d3857610922565b806364bb388f1461103b5780636811d3171461104e57806369349a9814610d765780636de796231461106d57610922565b8063502206e71161066d57806354fd4d501161063c5780636221a54b116106215780636221a54b14610be857806362ca846014610d90578063638634ee14610b1c57610922565b806354fd4d5014610ff65780635649effa14610e5857610922565b8063502206e714610f8a57806350a3ecf314610fbb57806352d1902d14610fda578063535c370c14610fee57610922565b806348e5d9f8116106c45780634bd20598116106a95780634bd2059814610f635780634cdad50614610afd5780634f1ef28614610f7757610922565b806348e5d9f814610ef2578063490ae21014610f4457610922565b80633be7623414610e865780633d68175c14610be85780634024277c14610ea5578063402d267d14610ed857610922565b8063190eaaba1161081b5780632d06177a1161079357806332ebc04b1161076257806335c08f5a1161074757806335c08f5a14610e255780633894b06514610e5857806338d52e0f14610e7257610922565b806332ebc04b14610dde5780633582d78914610e1157610922565b80632d06177a14610d905780632d9e88e114610daf578063313ce56714610dc3578063328a226314610d0657610922565b8063211dc32d116107ea57806323b872dd116107cf57806323b872dd14610d5757806323fad49b14610d06578063256110a914610d7657610922565b8063211dc32d14610d38578063235c360314610be857610922565b8063190eaaba14610c975780631b80d14914610cd35780631d63397114610d06578063202df50314610d1957610922565b80630b48a8b8116108ae57806312edb24c1161087d57806315bc54591161086257806315bc545914610c1d57806316491c3514610c5057806318160ddd14610c6457610922565b806312edb24c14610bfc5780631540aa8914610be857610922565b80630b48a8b814610b7e5780630d3896fe14610bc95780630de705b514610be857806310a4a26914610ac857610922565b80630892cd8b116108ea5780630892cd8b14610b1c578063095ea7b314610b3b57806309c5fc5614610b6a5780630a28a47714610afd57610922565b806301e1d11414610aa1578063053e938a14610ac857806306fdde0314610adc57806307a2d13a14610afd57610922565b3661092257005b34801561092d575f80fd5b505f80357fffffffff000000000000000000000000000000000000000000000000000000001681527feb5bb3420d9366368c64688d6df836957f2c655b917ed6671c4a93199009bc12602052604090205460ff166109e1576040517faa7311970000000000000000000000000000000000000000000000000000000081527fffffffff000000000000000000000000000000000000000000000000000000005f351660048201526024015b60405180910390fd5b5f80357fffffffff000000000000000000000000000000000000000000000000000000001681527feb5bb3420d9366368c64688d6df836957f2c655b917ed6671c4a93199009bc12602052604090205461010090046001600160a01b031680610a81576040517ffe8c159c0000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024016109d8565b365f80375f80365f845af43d5f803e808015610a9b573d5ff35b3d5ffd5b005b348015610aac575f80fd5b50610ab5611719565b6040519081526020015b60405180910390f35b348015610ad3575f80fd5b50610ab5611748565b348015610ae7575f80fd5b50610af0611773565b604051610abf91906144ed565b348015610b08575f80fd5b50610ab5610b173660046144ff565b611846565b348015610b27575f80fd5b50610ab5610b36366004614531565b611877565b348015610b46575f80fd5b50610b5a610b5536600461454a565b6118a2565b6040519015158152602001610abf565b348015610b75575f80fd5b50610a9f6118bb565b348015610b89575f80fd5b50610bb17f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab181565b6040516001600160a01b039091168152602001610abf565b348015610bd4575f80fd5b50610bb1610be3366004614531565b6118e8565b348015610bf3575f80fd5b50610ab5611913565b348015610c07575f80fd5b50610c1061193e565b604051610abf91906145b4565b348015610c28575f80fd5b50610bb17f0000000000000000000000008ea93a5ae50bc7a949590d2da237b21a375edfb281565b348015610c5b575f80fd5b50610b5a611913565b348015610c6f575f80fd5b507f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0254610ab5565b348015610ca2575f80fd5b507feb5bb3420d9366368c64688d6df836957f2c655b917ed6671c4a93199009bc03546001600160a01b0316610bb1565b348015610cde575f80fd5b50610bb17f00000000000000000000000028cd7540cb8c510b6b356fa446f1efb399004a9281565b610a9f610d1436600461460e565b611974565b348015610d24575f80fd5b50610a9f610d33366004614675565b6119a5565b348015610d43575f80fd5b50610ab5610d52366004614733565b6119db565b348015610d62575f80fd5b50610b5a610d71366004614764565b611a0d565b348015610d81575f80fd5b50610ab5610be3366004614531565b348015610d9b575f80fd5b50610a9f610daa366004614531565b611a32565b348015610dba575f80fd5b50610ab5611a60565b348015610dce575f80fd5b5060405160128152602001610abf565b348015610de9575f80fd5b50610bb17f00000000000000000000000058ca3045f4914bf702c7203b29a1d65856bd8bf781565b348015610e1c575f80fd5b50610c10611a8a565b348015610e30575f80fd5b50610bb17f000000000000000000000000cdddf49aa37e18dc3a13ef14694e7ddaf3356fd881565b348015610e63575f80fd5b50610b5a610be3366004614531565b348015610e7d575f80fd5b50610bb1611719565b348015610e91575f80fd5b50610a9f610ea036600461479d565b611b0c565b348015610eb0575f80fd5b50610bb17f000000000000000000000000302375ea70ac865bf44fc298d4459b3cbd01889c81565b348015610ee3575f80fd5b50610ab5610b17366004614531565b348015610efd575f80fd5b50610f11610f0c366004614531565b611b1c565b604051610abf91908151815260208083015190820152604080830151908201526060918201519181019190915260800190565b348015610f4f575f80fd5b50610a9f610f5e3660046144ff565b611b6d565b348015610f6e575f80fd5b50610ab5611b97565b610a9f610f8536600461491c565b611bc2565b348015610f95575f80fd5b50610fa9610fa43660046144ff565b611bdd565b604051610abf96959493929190614995565b348015610fc6575f80fd5b50610a9f610fd5366004614531565b611c19565b348015610fe5575f80fd5b50610ab5611c43565b610a9f611c71565b348015611001575f80fd5b5060408051808201909152600381527f312e3000000000000000000000000000000000000000000000000000000000006020820152610af0565b610ab56110493660046149fa565b611cf1565b348015611059575f80fd5b50610ab5611068366004614a33565b611d24565b348015611078575f80fd5b50610a9f6110873660046144ff565b611d59565b348015611097575f80fd5b50610ab56110a6366004614ac6565b611d83565b3480156110b6575f80fd5b50610ab56110c5366004614531565b6001600160a01b03165f9081527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00602052604090205490565b348015611109575f80fd5b50610a9f6111183660046144ff565b611dae565b348015611128575f80fd5b50610a9f611dd8565b34801561113c575f80fd5b50610ab5611deb565b348015611150575f80fd5b50610ab561115f366004614531565b6001600160a01b03165f9081527feb5bb3420d9366368c64688d6df836957f2c655b917ed6671c4a93199009bc24602052604090205490565b3480156111a3575f80fd5b50610a9f6111b2366004614bf5565b611e16565b3480156111c2575f80fd5b50610a9f6111d1366004614c4b565b611e40565b3480156111e1575f80fd5b50610b5a6111f036600461454a565b611e70565b348015611200575f80fd5b50610bb17f0000000000000000000000002dc7ad9b3397ee1813a2004a7787cd53d7fd02a081565b348015611233575f80fd5b50610ab561124236600461454a565b611e9b565b348015611252575f80fd5b50610bb1611913565b348015611266575f80fd5b5061126f611ec6565b604051610abf9190614cb3565b348015611287575f80fd5b50610bb17f000000000000000000000000ac694981a40621f67a73b02e67fa29054c13b39281565b3480156112ba575f80fd5b506112c3611ef2565b60408051928352602083019190915201610abf565b3480156112e3575f80fd5b507f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b0316610bb1565b34801561131f575f80fd5b5061126f61132e366004614531565b611f23565b34801561133e575f80fd5b50610a9f611f4f565b348015611352575f80fd5b50610af0611f79565b348015611366575f80fd5b50610b5a61137536600461454a565b611fca565b348015611385575f80fd5b50610af06040518060400160405280600581526020017f352e302e3000000000000000000000000000000000000000000000000000000081525081565b3480156113cd575f80fd5b50610bb17f0000000000000000000000001331e781c6d2219741b1c9b46ec4afcb1d1a110681565b611408611403366004614cc5565b611fd7565b604051610abf9190614d80565b348015611420575f80fd5b50610ab561142f366004614e12565b612010565b34801561143f575f80fd5b50610bb17f000000000000000000000000a0aae225faca0ffb747fed1fa0526645a427c15081565b348015611472575f80fd5b50610ab5610be33660046144ff565b34801561148c575f80fd5b50610bb17f0000000000000000000000004db1383dd215786d7b02bcee7823619efc51e97a81565b3480156114bf575f80fd5b50610a9f6114ce36600461454a565b61203b565b3480156114de575f80fd5b50610ab56111f036600461454a565b3480156114f8575f80fd5b507f42eb16b0bf2565d9a663d4e7253d588f054024f7228c103568322f697f63b61354610ab5565b34801561152b575f80fd5b50610bb161153a3660046144ff565b5f9081527feb5bb3420d9366368c64688d6df836957f2c655b917ed6671c4a93199009bc2360205260409020546001600160a01b031690565b34801561157e575f80fd5b50610c10612065565b348015611592575f80fd5b50610bb17f0000000000000000000000007c5027a145bd43fc6f7cd51040b1fef6b1f970e881565b3480156115c5575f80fd5b50610bb17f00000000000000000000000009c784690a36e9449f78f60d9daf6c3403d2384081565b3480156115f8575f80fd5b50610ab5611607366004614733565b6001600160a01b039182165f9081527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace016020908152604080832093909416825291909152205490565b34801561165b575f80fd5b50610ab561166a366004614e42565b612091565b34801561167a575f80fd5b50610c106120c5565b34801561168e575f80fd5b50610ab561169d366004614531565b612145565b3480156116ad575f80fd5b50610a9f610f5e366004614531565b3480156116c7575f80fd5b50610a9f6116d6366004614f17565b612170565b3480156116e6575f80fd5b50610a9f6116f5366004614531565b61219a565b348015611705575f80fd5b50610a9f611714366004614531565b6121ed565b5f7f0000000000000000000000008ea93a5ae50bc7a949590d2da237b21a375edfb26117448161243d565b5090565b5f7f000000000000000000000000a0aae225faca0ffb747fed1fa0526645a427c1506117448161243d565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0380546060917f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00916117c490615165565b80601f01602080910402602001604051908101604052809291908181526020018280546117f090615165565b801561183b5780601f106118125761010080835404028352916020019161183b565b820191905f5260205f20905b81548152906001019060200180831161181e57829003601f168201915b505050505091505090565b5f7f0000000000000000000000008ea93a5ae50bc7a949590d2da237b21a375edfb26118718161243d565b50919050565b5f7f00000000000000000000000009c784690a36e9449f78f60d9daf6c3403d238406118718161243d565b5f336118af818585612482565b60019150505b92915050565b7f00000000000000000000000028cd7540cb8c510b6b356fa446f1efb399004a926118e581610a81565b50565b5f7f0000000000000000000000007c5027a145bd43fc6f7cd51040b1fef6b1f970e86118718161243d565b5f7f0000000000000000000000007c5027a145bd43fc6f7cd51040b1fef6b1f970e86117448161243d565b60607f00000000000000000000000009c784690a36e9449f78f60d9daf6c3403d2384061196961248f565b91506117448161243d565b7f000000000000000000000000cdddf49aa37e18dc3a13ef14694e7ddaf3356fd861199e81610a81565b5050505050565b7f000000000000000000000000ac694981a40621f67a73b02e67fa29054c13b3926119cf81610a81565b50505050505050505050565b5f7f00000000000000000000000009c784690a36e9449f78f60d9daf6c3403d23840611a068161243d565b5092915050565b5f33611a1a8582856124bf565b611a2585858561258b565b60019150505b9392505050565b7f000000000000000000000000302375ea70ac865bf44fc298d4459b3cbd01889c611a5c81610a81565b5050565b5f7f00000000000000000000000009c784690a36e9449f78f60d9daf6c3403d2384061196961261a565b60607feb5bb3420d9366368c64688d6df836957f2c655b917ed6671c4a93199009bc00600501805480602002602001604051908101604052809291908181526020018280548015611b0257602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311611ae4575b5050505050905090565b611b17838383612644565b505050565b611b4360405180608001604052805f81526020015f81526020015f81526020015f81525090565b7f00000000000000000000000009c784690a36e9449f78f60d9daf6c3403d238406118718161243d565b7f0000000000000000000000004db1383dd215786d7b02bcee7823619efc51e97a611a5c81610a81565b5f7f00000000000000000000000058ca3045f4914bf702c7203b29a1d65856bd8bf76117448161243d565b611bca612768565b611bd382612838565b611a5c82826129a9565b5f806060806060807f0000000000000000000000007c5027a145bd43fc6f7cd51040b1fef6b1f970e8611c0f8161243d565b5091939550919395565b7f00000000000000000000000009c784690a36e9449f78f60d9daf6c3403d23840611a5c81610a81565b5f611c4c612ac8565b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc90565b333014611caa576040517fde86987d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc36015f8160248237808183836004355af491503d81823e818015611ced573d82f35b3d82fd5b5f7f0000000000000000000000002dc7ad9b3397ee1813a2004a7787cd53d7fd02a0611d1c81610a81565b509392505050565b5f7f0000000000000000000000002dc7ad9b3397ee1813a2004a7787cd53d7fd02a0611d4f81610a81565b5095945050505050565b7f00000000000000000000000028cd7540cb8c510b6b356fa446f1efb399004a92611a5c81610a81565b5f7f0000000000000000000000008ea93a5ae50bc7a949590d2da237b21a375edfb2611a0681610a81565b7f00000000000000000000000058ca3045f4914bf702c7203b29a1d65856bd8bf7611a5c81610a81565b611de0612b2a565b611de95f612b9e565b565b5f7f00000000000000000000000009c784690a36e9449f78f60d9daf6c3403d238406117448161243d565b7f00000000000000000000000028cd7540cb8c510b6b356fa446f1efb399004a92611b1781610a81565b7f00000000000000000000000028cd7540cb8c510b6b356fa446f1efb399004a92611e6a81610a81565b50505050565b5f7f0000000000000000000000007c5027a145bd43fc6f7cd51040b1fef6b1f970e8611a068161243d565b5f7f000000000000000000000000a0aae225faca0ffb747fed1fa0526645a427c150611a068161243d565b60607f0000000000000000000000007c5027a145bd43fc6f7cd51040b1fef6b1f970e86117448161243d565b5f807f000000000000000000000000a0aae225faca0ffb747fed1fa0526645a427c150611f1e8161243d565b509091565b60607f00000000000000000000000009c784690a36e9449f78f60d9daf6c3403d2384061187181610a81565b7f0000000000000000000000004db1383dd215786d7b02bcee7823619efc51e97a6118e581610a81565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0480546060917f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00916117c490615165565b5f336118af81858561258b565b60607f000000000000000000000000cdddf49aa37e18dc3a13ef14694e7ddaf3356fd861200381610a81565b5098975050505050505050565b5f7f0000000000000000000000008ea93a5ae50bc7a949590d2da237b21a375edfb2611d1c81610a81565b7f00000000000000000000000009c784690a36e9449f78f60d9daf6c3403d23840611b1781610a81565b60607f00000000000000000000000009c784690a36e9449f78f60d9daf6c3403d238406117448161243d565b5f7f000000000000000000000000ac694981a40621f67a73b02e67fa29054c13b3926120bc81610a81565b50949350505050565b60607feb5bb3420d9366368c64688d6df836957f2c655b917ed6671c4a93199009bc00600601805480602002602001604051908101604052809291908181526020018280548015611b0257602002820191905f5260205f209081546001600160a01b03168152600190910190602001808311611ae4575050505050905090565b5f7f000000000000000000000000a0aae225faca0ffb747fed1fa0526645a427c1506118718161243d565b7f0000000000000000000000001331e781c6d2219741b1c9b46ec4afcb1d1a110661199e81610a81565b6121a2612b2a565b6001600160a01b0381166121e4576040517f1e4fbdf70000000000000000000000000000000000000000000000000000000081525f60048201526024016109d8565b6118e581612b9e565b6121f5612b2a565b7feb5bb3420d9366368c64688d6df836957f2c655b917ed6671c4a93199009bc005474010000000000000000000000000000000000000000900460ff16612268576040517fb4578e8700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7feb5bb3420d9366368c64688d6df836957f2c655b917ed6671c4a93199009bc00546001600160a01b0316639bb8dcfd6122c97f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b0391821660048201529084166024820152604401602060405180830381865afa15801561232b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061234f91906151b0565b612385576040517fc5be01ad00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7feb5bb3420d9366368c64688d6df836957f2c655b917ed6671c4a93199009bc1b80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038316908117909155427feb5bb3420d9366368c64688d6df836957f2c655b917ed6671c4a93199009bc1c81905560408051928352602083019190915280517ffed9008e709886827269b7d7d66b3c92de71653a80e2265584ef0cd47a8bdfbf9281900390910190a150565b7f535c370c000000000000000000000000000000000000000000000000000000005f5280600452365f6024375f80602436015f305afa3d5f803e808015610a9b573d5ff35b611b178383836001612c26565b60606124ba7f0437d4a732399ef7f2c8fca6343f4e97d989d30f9900ddd012da8b53d6c89005612d4e565b905090565b6001600160a01b038381165f9081527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0160209081526040808320938616835292905220547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114611e6a578181101561257d576040517ffb8f41b20000000000000000000000000000000000000000000000000000000081526001600160a01b038416600482015260248101829052604481018390526064016109d8565b611e6a84848484035f612c26565b6001600160a01b0383166125cd576040517f96c6fd1e0000000000000000000000000000000000000000000000000000000081525f60048201526024016109d8565b6001600160a01b03821661260f576040517fec442f050000000000000000000000000000000000000000000000000000000081525f60048201526024016109d8565b611b17838383612d5a565b5f6124ba7f0437d4a732399ef7f2c8fca6343f4e97d989d30f9900ddd012da8b53d6c89005612d86565b61264d83612d8f565b7f0437d4a732399ef7f2c8fca6343f4e97d989d30f9900ddd012da8b53d6c890005f5b8281101561199e575f84848381811061268b5761268b6151cb565b90506020020160208101906126a09190614531565b6001600160a01b038088165f9081526003860160209081526040808320938516835292905220549091508015612753576001600160a01b038088165f908152600386016020908152604080832093861680845293909152812055612705908883612ecb565b816001600160a01b0316876001600160a01b03167f540798df468d7b23d11f156fdb954cb19ad414d150722a7b6d55ba369dea792e8360405161274a91815260200190565b60405180910390a35b5050808061276090615225565b915050612670565b306001600160a01b037f000000000000000000000000328f2279abd86df7c1c82f4bb1e959b78b3b4dad16148061280157507f000000000000000000000000328f2279abd86df7c1c82f4bb1e959b78b3b4dad6001600160a01b03166127f57f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b6001600160a01b031614155b15611de9576040517fe07c8dba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612840612b2a565b7feb5bb3420d9366368c64688d6df836957f2c655b917ed6671c4a93199009bc005474010000000000000000000000000000000000000000900460ff166128b3576040517fb4578e8700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7feb5bb3420d9366368c64688d6df836957f2c655b917ed6671c4a93199009bc01547feb5bb3420d9366368c64688d6df836957f2c655b917ed6671c4a93199009bc1c5442916129029161525c565b111561293a576040517f2cac76cf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0381167feb5bb3420d9366368c64688d6df836957f2c655b917ed6671c4a93199009bc00601b01546001600160a01b0316146118e5576040517f352839fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015612a21575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201909252612a1e9181019061526f565b60015b612a62576040517f4c9c8ce30000000000000000000000000000000000000000000000000000000081526001600160a01b03831660048201526024016109d8565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8114612abe576040517faa1d49a4000000000000000000000000000000000000000000000000000000008152600481018290526024016109d8565b611b178383612f4b565b306001600160a01b037f000000000000000000000000328f2279abd86df7c1c82f4bb1e959b78b3b4dad1614611de9576040517fe07c8dba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33612b5c7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b6001600160a01b031614611de9576040517f118cdaa70000000000000000000000000000000000000000000000000000000081523360048201526024016109d8565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080547fffffffffffffffffffffffff000000000000000000000000000000000000000081166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a3505050565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace006001600160a01b038516612c89576040517fe602df050000000000000000000000000000000000000000000000000000000081525f60048201526024016109d8565b6001600160a01b038416612ccb576040517f94280d620000000000000000000000000000000000000000000000000000000081525f60048201526024016109d8565b6001600160a01b038086165f9081526001830160209081526040808320938816835292905220839055811561199e57836001600160a01b0316856001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92585604051612d3f91815260200190565b60405180910390a35050505050565b60605f611a2b83612fa0565b612d65838383612ff9565b612d70838383613003565b612d7b838383613053565b611b178383836131b8565b5f6118b5825490565b7f0437d4a732399ef7f2c8fca6343f4e97d989d30f9900ddd012da8b53d6c890005f612dda7f0437d4a732399ef7f2c8fca6343f4e97d989d30f9900ddd012da8b53d6c89005612d4e565b90505f5b8151811015611e6a575f828281518110612dfa57612dfa6151cb565b60200260200101519050612e0d816131c2565b6001600160a01b0382165f908152600186016020526040902060030155612e33816132aa565b6001600160a01b038083165f908152600187016020526040902060020191909155851615612eb857612e658582613319565b6001600160a01b038087165f8181526003808901602090815260408084209588168085529582528084209690965560018a0181528583209091015492825260028901815284822093825292909252919020555b5080612ec381615225565b915050612dde565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052611b179084906133fa565b612f5482613474565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a2805115612f9857611b17828261351b565b611a5c61358d565b6060815f01805480602002602001604051908101604052809291908181526020018280548015612fed57602002820191905f5260205f20905b815481526020019060010190808311612fd9575b50505050509050919050565b611b1783836135c5565b6001600160a01b0383161561301b5761301b83612d8f565b6001600160a01b038216158015906130455750826001600160a01b0316826001600160a01b031614155b15611b1757611b1782612d8f565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace006001600160a01b0384166130a05781816002015f828254613095919061525c565b909155506131299050565b6001600160a01b0384165f908152602082905260409020548281101561310b576040517fe450d38c0000000000000000000000000000000000000000000000000000000081526001600160a01b038616600482015260248101829052604481018490526064016109d8565b6001600160a01b0385165f9081526020839052604090209083900390555b6001600160a01b038316613147576002810180548390039055613165565b6001600160a01b0383165f9081526020829052604090208054830190555b826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516131aa91815260200190565b60405180910390a350505050565b611b178383613643565b5f7f0437d4a732399ef7f2c8fca6343f4e97d989d30f9900ddd012da8b53d6c89000816131ed6136a1565b9050805f0361321a57506001600160a01b039092165f908152600190920160205250604090206003015490565b6001600160a01b0384165f908152600180840160205260409091209081015460029091015482919061324b876132aa565b6132559190615286565b61325f9190615299565b61327190670de0b6b3a7640000615299565b61327b91906152b0565b6001600160a01b0385165f9081526001840160205260409020600301546132a2919061525c565b949350505050565b6001600160a01b0381165f9081527f0437d4a732399ef7f2c8fca6343f4e97d989d30f9900ddd012da8b53d6c8900160205260408120547f0437d4a732399ef7f2c8fca6343f4e97d989d30f9900ddd012da8b53d6c890009042811161331057806132a2565b42949350505050565b6001600160a01b038281165f8181527f0437d4a732399ef7f2c8fca6343f4e97d989d30f9900ddd012da8b53d6c8900360209081526040808320948616808452948252808320549383527f0437d4a732399ef7f2c8fca6343f4e97d989d30f9900ddd012da8b53d6c890028252808320948352939052918220547f0437d4a732399ef7f2c8fca6343f4e97d989d30f9900ddd012da8b53d6c890009190670de0b6b3a7640000906133c9866131c2565b6133d39190615286565b6133dc876136ca565b6133e69190615299565b6133f091906152b0565b6132a2919061525c565b5f61340e6001600160a01b03841683613706565b905080515f1415801561343257508080602001905181019061343091906151b0565b155b15611b17576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b03841660048201526024016109d8565b806001600160a01b03163b5f036134c2576040517f4c9c8ce30000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024016109d8565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b60605f80846001600160a01b03168460405161353791906152e8565b5f60405180830381855af49150503d805f811461356f576040519150601f19603f3d011682016040523d82523d5f602084013e613574565b606091505b5091509150613584858383613713565b95945050505050565b3415611de9576040517fb398979f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f806135cf613788565b9150915081515f036135e15750505050565b6001600160a01b0384161580159061360257506001600160a01b0384163014155b1561361257613612848383613b4e565b6001600160a01b0383161580159061363357506001600160a01b0383163014155b15611e6a57611e6a838383613b4e565b6001600160a01b0382161580159061366457506001600160a01b0382163014155b156136725761367282613eb8565b6001600160a01b0381161580159061369357506001600160a01b0381163014155b15611a5c57611a5c81613eb8565b5f6124ba7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace025490565b6001600160a01b0381165f9081527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0060205260408120546118b5565b6060611a2b83835f613fc5565b6060826137285761372382614077565b611a2b565b815115801561373f57506001600160a01b0384163b155b15613781576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b03851660048201526024016109d8565b5080611a2b565b6060806137936140b9565b9150815167ffffffffffffffff8111156137af576137af6147ec565b6040519080825280602002602001820160405280156137d8578160200160208202803683370190505b50905081515f036137e7579091565b7f42eb16b0bf2565d9a663d4e7253d588f054024f7228c103568322f697f63b61380544314613abd574381555f61383c7f24bc46ff97535a32ac9a9fd00a6caac7641d058373f14d0429bdbb23908d69d55490565b9050613846614107565b5f5b8451811015613aba575f858281518110613864576138646151cb565b6020908102919091018101516001600160a01b0381165f908152600287019092526040822054885191935070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16908890859081106138c8576138c86151cb565b60209081029190910101516040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa15801561392f573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613953919061526f565b61395d9190615286565b6001600160a01b0383165f9081526002870160205260408120549192506fffffffffffffffffffffffffffffffff9091169081900361399a575060015b84156139b7576139aa8286614195565b6139b4908261525c565b90505b6139c0816141a9565b6001600160a01b0384165f908152600288016020526040902080547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff92909216919091179055613a21826141a9565b6001600160a01b0384165f90815260028801602052604090208054601090613a7090849070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16615303565b92506101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff16021790555050505080613ab390615225565b9050613848565b50505b5f5b8351811015613b4857816002015f858381518110613adf57613adf6151cb565b6020908102919091018101516001600160a01b031682528101919091526040015f205483516fffffffffffffffffffffffffffffffff90911690849083908110613b2b57613b2b6151cb565b602090810291909101015280613b4081615225565b915050613abf565b50509091565b6001600160a01b03831615801590613b6f57506001600160a01b0383163014155b613b7b57613b7b61532c565b7f42eb16b0bf2565d9a663d4e7253d588f054024f7228c103568322f697f63b6135f613bda856001600160a01b03165f9081527f24bc46ff97535a32ac9a9fd00a6caac7641d058373f14d0429bdbb23908d69d6602052604090205490565b90505f5b8451811015613eb0575f858281518110613bfa57613bfa6151cb565b602002602001015190505f858381518110613c1757613c176151cb565b6020908102919091018101516001600160a01b038085165f9081526001890184526040808220928d168252919093528220549092506fffffffffffffffffffffffffffffffff1690819003613cdf57613c6f826141a9565b6001600160a01b039384165f9081526001880160209081526040808320968d1683529590529390932080547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff9094169390931790925550613ea09050565b818103613cee57505050613ea0565b5f613cf98284615286565b90505f613d0687836141fe565b90505f81896001015f886001600160a01b03166001600160a01b031681526020019081526020015f205f8e6001600160a01b03166001600160a01b031681526020019081526020015f205f0160109054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff16613d8b919061525c565b90506040518060400160405280613da1876141a9565b6fffffffffffffffffffffffffffffffff168152602001613dc1836141a9565b6fffffffffffffffffffffffffffffffff16815250896001015f886001600160a01b03166001600160a01b031681526020019081526020015f205f8e6001600160a01b03166001600160a01b031681526020019081526020015f205f820151815f015f6101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055506020820151815f0160106101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055509050505050505050505b613ea981615225565b9050613bde565b505050505050565b6001600160a01b03811615801590613ed957506001600160a01b0381163014155b613ee557613ee561532c565b5f613eef826136ca565b90505f613efc8383614212565b90505f613f09828461434e565b6001600160a01b0385165f9081527f24bc46ff97535a32ac9a9fd00a6caac7641d058373f14d0429bdbb23908d69d660205260409020547f24bc46ff97535a32ac9a9fd00a6caac7641d058373f14d0429bdbb23908d69d5549192507f24bc46ff97535a32ac9a9fd00a6caac7641d058373f14d0429bdbb23908d69d2918391613f9291615286565b613f9c919061525c565b60038201556001600160a01b039094165f90815260049094016020526040909320929092555050565b606081471015614003576040517fcd7860590000000000000000000000000000000000000000000000000000000081523060048201526024016109d8565b5f80856001600160a01b0316848660405161401e91906152e8565b5f6040518083038185875af1925050503d805f8114614058576040519150601f19603f3d011682016040523d82523d5f602084013e61405d565b606091505b509150915061406d868383613713565b9695505050505050565b8051156140875780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080515f80825260208201909252606091506141017f24bc46ff97535a32ac9a9fd00a6caac7641d058373f14d0429bdbb23908d69d25482906001600160a01b0316614363565b91505090565b7f24bc46ff97535a32ac9a9fd00a6caac7641d058373f14d0429bdbb23908d69d454604080517f8113382700000000000000000000000000000000000000000000000000000000815290516001600160a01b03909216916381133827916004808201925f9290919082900301818387803b158015614183575f80fd5b505af1158015611e6a573d5f803e3d5ffd5b5f611a2b83670de0b6b3a764000084614448565b5f6fffffffffffffffffffffffffffffffff821115611744576040517f6dfcc65000000000000000000000000000000000000000000000000000000000815260806004820152602481018390526044016109d8565b5f611a2b8383670de0b6b3a7640000614448565b5f807f24bc46ff97535a32ac9a9fd00a6caac7641d058373f14d0429bdbb23908d69d260018101546040517fe268b3a40000000000000000000000000000000000000000000000000000000081526001600160a01b0387811660048301529293505f928392169063e268b3a49060240160408051808303815f875af115801561429d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906142c19190615378565b6fffffffffffffffffffffffffffffffff91821693501690505f60646142e8602888615299565b6142f291906152b0565b9050821561406d576064614307602882615286565b84846143116136a1565b61431b9190615299565b61432591906152b0565b61432f9190615299565b61433991906152b0565b614343908261525c565b979650505050505050565b5f81831061435c5781611a2b565b5090919050565b815160609061437381600161525c565b67ffffffffffffffff81111561438b5761438b6147ec565b6040519080825280602002602001820160405280156143b4578160200160208202803683370190505b5091505f5b8181101561440d578481815181106143d3576143d36151cb565b60200260200101518382815181106143ed576143ed6151cb565b6001600160a01b03909216602092830291909101909101526001016143b9565b5082828281518110614421576144216151cb565b60200260200101906001600160a01b031690816001600160a01b0316815250505092915050565b5f827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048411830215820261447b575f80fd5b5091020490565b5f5b8381101561449c578181015183820152602001614484565b50505f910152565b5f81518084526144bb816020860160208601614482565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081525f611a2b60208301846144a4565b5f6020828403121561450f575f80fd5b5035919050565b80356001600160a01b038116811461452c575f80fd5b919050565b5f60208284031215614541575f80fd5b611a2b82614516565b5f806040838503121561455b575f80fd5b61456483614516565b946020939093013593505050565b5f8151808452602080850194508084015f5b838110156145a95781516001600160a01b031687529582019590820190600101614584565b509495945050505050565b602081525f611a2b6020830184614572565b5f8083601f8401126145d6575f80fd5b50813567ffffffffffffffff8111156145ed575f80fd5b6020830191508360208260051b8501011115614607575f80fd5b9250929050565b5f805f8060408587031215614621575f80fd5b843567ffffffffffffffff80821115614638575f80fd5b614644888389016145c6565b9096509450602087013591508082111561465c575f80fd5b50614669878288016145c6565b95989497509550505050565b5f805f805f805f805f60c08a8c03121561468d575f80fd5b8935985061469d60208b01614516565b97506146ab60408b01614516565b965060608a013567ffffffffffffffff808211156146c7575f80fd5b6146d38d838e016145c6565b909850965060808c01359150808211156146eb575f80fd5b6146f78d838e016145c6565b909650945060a08c013591508082111561470f575f80fd5b5061471c8c828d016145c6565b915080935050809150509295985092959850929598565b5f8060408385031215614744575f80fd5b61474d83614516565b915061475b60208401614516565b90509250929050565b5f805f60608486031215614776575f80fd5b61477f84614516565b925061478d60208501614516565b9150604084013590509250925092565b5f805f604084860312156147af575f80fd5b6147b884614516565b9250602084013567ffffffffffffffff8111156147d3575f80fd5b6147df868287016145c6565b9497909650939450505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b604051610220810167ffffffffffffffff8111828210171561483d5761483d6147ec565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561488a5761488a6147ec565b604052919050565b5f82601f8301126148a1575f80fd5b813567ffffffffffffffff8111156148bb576148bb6147ec565b6148ec60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601614843565b818152846020838601011115614900575f80fd5b816020850160208301375f918101602001919091529392505050565b5f806040838503121561492d575f80fd5b61493683614516565b9150602083013567ffffffffffffffff811115614951575f80fd5b61495d85828601614892565b9150509250929050565b5f8151808452602080850194508084015f5b838110156145a957815187529582019590820190600101614979565b86815285602082015260c060408201525f6149b360c0830187614572565b82810360608401526149c58187614967565b905082810360808401526149d98186614572565b905082810360a08401526149ed8185614967565b9998505050505050505050565b5f805f60608486031215614a0c575f80fd5b614a1584614516565b925060208401359150614a2a60408501614516565b90509250925092565b5f805f805f60808688031215614a47575f80fd5b614a5086614516565b945060208601359350614a6560408701614516565b9250606086013567ffffffffffffffff80821115614a81575f80fd5b818801915088601f830112614a94575f80fd5b813581811115614aa2575f80fd5b896020828501011115614ab3575f80fd5b9699959850939650602001949392505050565b5f8060408385031215614ad7575f80fd5b8235915061475b60208401614516565b5f67ffffffffffffffff821115614b0057614b006147ec565b5060051b60200190565b5f82601f830112614b19575f80fd5b81356020614b2e614b2983614ae7565b614843565b82815260059290921b84018101918181019086841115614b4c575f80fd5b8286015b84811015614b6e57614b6181614516565b8352918301918301614b50565b509695505050505050565b5f82601f830112614b88575f80fd5b81356020614b98614b2983614ae7565b82815260059290921b84018101918181019086841115614bb6575f80fd5b8286015b84811015614b6e57803567ffffffffffffffff811115614bd9575f8081fd5b614be78986838b0101614892565b845250918301918301614bba565b5f8060408385031215614c06575f80fd5b823567ffffffffffffffff80821115614c1d575f80fd5b614c2986838701614b0a565b93506020850135915080821115614c3e575f80fd5b5061495d85828601614b79565b5f805f60608486031215614c5d575f80fd5b83359250602084013567ffffffffffffffff80821115614c7b575f80fd5b614c8787838801614b0a565b93506040860135915080821115614c9c575f80fd5b50614ca986828701614b79565b9150509250925092565b602081525f611a2b6020830184614967565b5f805f805f805f806080898b031215614cdc575f80fd5b883567ffffffffffffffff80821115614cf3575f80fd5b614cff8c838d016145c6565b909a50985060208b0135915080821115614d17575f80fd5b614d238c838d016145c6565b909850965060408b0135915080821115614d3b575f80fd5b614d478c838d016145c6565b909650945060608b0135915080821115614d5f575f80fd5b50614d6c8b828c016145c6565b999c989b5096995094979396929594505050565b5f6020808301818452808551808352604092508286019150828160051b8701018488015f5b83811015614e04578883037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc00185528151805115158452870151878401879052614df1878501826144a4565b9588019593505090860190600101614da5565b509098975050505050505050565b5f805f60608486031215614e24575f80fd5b83359250614e3460208501614516565b9150614a2a60408501614516565b5f805f8060808587031215614e55575f80fd5b614e5e85614516565b935060208501359250614e7360408601614516565b9150614e8160608601614516565b905092959194509250565b80151581146118e5575f80fd5b803561452c81614e8c565b5f60a08284031215614eb4575f80fd5b60405160a0810181811067ffffffffffffffff82111715614ed757614ed76147ec565b604052905080614ee683614516565b8152602083013560208201526040830135604082015260608301356060820152608083013560808201525092915050565b5f805f80610100808688031215614f2c575f80fd5b853567ffffffffffffffff80821115614f43575f80fd5b614f4f89838a01614892565b96506020880135915080821115614f64575f80fd5b614f7089838a01614892565b95506040880135915080821115614f85575f80fd5b90870190610220828a031215614f99575f80fd5b614fa1614819565b614faa83614516565b8152614fb860208401614516565b60208201526040830135604082015260608301356060820152614fdd60808401614e99565b608082015260a083013560a082015260c083013560c082015260e083013560e08201528383013582811115615010575f80fd5b61501c8b828601614b0a565b858301525061012093508383013582811115615036575f80fd5b6150428b828601614b0a565b85830152506101409350838301358281111561505c575f80fd5b6150688b828601614b0a565b858301525061016093508383013582811115615082575f80fd5b61508e8b828601614b0a565b8583015250610180935083830135828111156150a8575f80fd5b6150b48b828601614b0a565b85830152506101a0935083830135828111156150ce575f80fd5b6150da8b828601614b0a565b85830152506101c0935083830135828111156150f4575f80fd5b6151008b828601614b0a565b85830152506101e09350838301358281111561511a575f80fd5b6151268b828601614b0a565b858301525061020093508383013582811115615140575f80fd5b61514c8b828601614b0a565b858301525080955050505050614e818660608701614ea4565b600181811c9082168061517957607f821691505b602082108103611871577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f602082840312156151c0575f80fd5b8151611a2b81614e8c565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203615255576152556151f8565b5060010190565b808201808211156118b5576118b56151f8565b5f6020828403121561527f575f80fd5b5051919050565b818103818111156118b5576118b56151f8565b80820281158282048414176118b5576118b56151f8565b5f826152e3577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b5f82516152f9818460208701614482565b9190910192915050565b6fffffffffffffffffffffffffffffffff818116838216019080821115611a0657611a066151f8565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52600160045260245ffd5b80516fffffffffffffffffffffffffffffffff8116811461452c575f80fd5b5f8060408385031215615389575f80fd5b61539283615359565b915061475b6020840161535956fea2646970667358221220c8a3325a22f45c8049e5495adc3650aa0219e697d5f272a05d5e4a45f92fdbdf64736f6c63430008140033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000001331e781c6d2219741b1c9b46ec4afcb1d1a11060000000000000000000000002dc7ad9b3397ee1813a2004a7787cd53d7fd02a0000000000000000000000000ac694981a40621f67a73b02e67fa29054c13b392000000000000000000000000302375ea70ac865bf44fc298d4459b3cbd01889c0000000000000000000000004db1383dd215786d7b02bcee7823619efc51e97a000000000000000000000000cdddf49aa37e18dc3a13ef14694e7ddaf3356fd8000000000000000000000000a0aae225faca0ffb747fed1fa0526645a427c1500000000000000000000000007c5027a145bd43fc6f7cd51040b1fef6b1f970e80000000000000000000000008ea93a5ae50bc7a949590d2da237b21a375edfb200000000000000000000000009c784690a36e9449f78f60d9daf6c3403d2384000000000000000000000000058ca3045f4914bf702c7203b29a1d65856bd8bf700000000000000000000000028cd7540cb8c510b6b356fa446f1efb399004a9200000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab1
-----Decoded View---------------
Arg [0] : modules (tuple):
Arg [1] : initialize (address): 0x1331e781c6D2219741b1c9B46Ec4afcB1D1a1106
Arg [2] : deposit (address): 0x2DC7ad9b3397ee1813A2004a7787CD53d7fD02A0
Arg [3] : withdraw (address): 0xAc694981a40621f67A73b02E67FA29054c13B392
Arg [4] : roles (address): 0x302375Ea70Ac865bF44fc298d4459b3cbD01889C
Arg [5] : fees (address): 0x4DB1383dD215786d7B02bcEE7823619EFC51e97a
Arg [6] : executions (address): 0xcdddF49Aa37E18dC3A13eF14694e7DdAf3356fD8
Arg [7] : vaultValue (address): 0xa0aaE225fACa0fFB747feD1fa0526645a427c150
Arg [8] : resolver (address): 0x7c5027a145BD43Fc6F7cD51040B1FeF6b1F970E8
Arg [9] : erc4626 (address): 0x8eA93A5aE50Bc7a949590d2dA237b21A375EDFB2
Arg [10] : scaleBoost (address): 0x09C784690A36e9449F78f60D9dAF6C3403D23840
Arg [11] : riskManagement (address): 0x58ca3045f4914Bf702C7203B29a1D65856BD8bf7
Arg [12] : strategy (address): 0x28cD7540Cb8C510B6b356fa446F1eFB399004a92
Arg [1] : nativeWrapper (address): 0x82aF49447D8a07e3bd95BD0d56f35241523fBab1
-----Encoded View---------------
13 Constructor Arguments found :
Arg [0] : 0000000000000000000000001331e781c6d2219741b1c9b46ec4afcb1d1a1106
Arg [1] : 0000000000000000000000002dc7ad9b3397ee1813a2004a7787cd53d7fd02a0
Arg [2] : 000000000000000000000000ac694981a40621f67a73b02e67fa29054c13b392
Arg [3] : 000000000000000000000000302375ea70ac865bf44fc298d4459b3cbd01889c
Arg [4] : 0000000000000000000000004db1383dd215786d7b02bcee7823619efc51e97a
Arg [5] : 000000000000000000000000cdddf49aa37e18dc3a13ef14694e7ddaf3356fd8
Arg [6] : 000000000000000000000000a0aae225faca0ffb747fed1fa0526645a427c150
Arg [7] : 0000000000000000000000007c5027a145bd43fc6f7cd51040b1fef6b1f970e8
Arg [8] : 0000000000000000000000008ea93a5ae50bc7a949590d2da237b21a375edfb2
Arg [9] : 00000000000000000000000009c784690a36e9449f78f60d9daf6c3403d23840
Arg [10] : 00000000000000000000000058ca3045f4914bf702c7203b29a1d65856bd8bf7
Arg [11] : 00000000000000000000000028cd7540cb8c510b6b356fa446f1efb399004a92
Arg [12] : 00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab1
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
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.