Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
TokenTracker
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| 0x60a06040 | 19388998 | 615 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
RoleManager
Compiler Version
v0.8.18+commit.87f61d96
Contract Source Code (Solidity)
/**
*Submitted for verification at Etherscan.io on 2024-03-08
*/
// SPDX-License-Identifier: AGPL-3.0
pragma solidity 0.8.18;
contract Governance {
/// @notice Emitted when the governance address is updated.
event GovernanceTransferred(
address indexed previousGovernance,
address indexed newGovernance
);
modifier onlyGovernance() {
_checkGovernance();
_;
}
/// @notice Checks if the msg sender is the governance.
function _checkGovernance() internal view virtual {
require(governance == msg.sender, "!governance");
}
/// @notice Address that can set the default base fee and provider
address public governance;
constructor(address _governance) {
governance = _governance;
emit GovernanceTransferred(address(0), _governance);
}
/**
* @notice Sets a new address as the governance of the contract.
* @dev Throws if the caller is not current governance.
* @param _newGovernance The new governance address.
*/
function transferGovernance(
address _newGovernance
) external virtual onlyGovernance {
require(_newGovernance != address(0), "ZERO ADDRESS");
address oldGovernance = governance;
governance = _newGovernance;
emit GovernanceTransferred(oldGovernance, _newGovernance);
}
}
interface IFactory {
function apiVersion() external view returns (string memory);
}
/**
* @title YearnV3 Release Registry
* @author yearn.finance
* @notice
* Used by Yearn Governance to track on chain all
* releases of the V3 vaults by API Version.
*/
contract ReleaseRegistry is Governance {
event NewRelease(
uint256 indexed releaseId,
address indexed factory,
string apiVersion
);
string public constant name = "Yearn V3 Release Registry";
// The total number of releases that have been deployed
uint256 public numReleases;
// Mapping of release id starting at 0 to the address
// of the corresponding factory for that release.
mapping(uint256 => address) public factories;
// Mapping of the API version for a specific release to the
// place in the order it was released.
mapping(string => uint256) public releaseTargets;
constructor(address _governance) Governance(_governance) {}
/**
* @notice Returns the latest factory.
* @dev Throws if no releases are registered yet.
* @return The address of the factory for the latest release.
*/
function latestFactory() external view virtual returns (address) {
return factories[numReleases - 1];
}
/**
* @notice Returns the api version of the latest release.
* @dev Throws if no releases are registered yet.
* @return The api version of the latest release.
*/
function latestRelease() external view virtual returns (string memory) {
return IFactory(factories[numReleases - 1]).apiVersion(); // dev: no release
}
/**
* @notice Issue a new release using a deployed factory.
* @dev Stores the factory address in `factories` and the release
* target in `releaseTargets` with its associated API version.
*
* Throws if caller isn't `governance`.
* Throws if the api version is the same as the previous release.
* Emits a `NewRelease` event.
*
* @param _factory The factory that will be used create new vaults.
*/
function newRelease(address _factory) external virtual onlyGovernance {
// Check if the release is different from the current one
uint256 releaseId = numReleases;
string memory apiVersion = IFactory(_factory).apiVersion();
if (releaseId > 0) {
// Make sure this isn't the same as the last one
require(
keccak256(
bytes(IFactory(factories[releaseId - 1]).apiVersion())
) != keccak256(bytes(apiVersion)),
"ReleaseRegistry: same api version"
);
}
// Update latest release.
factories[releaseId] = _factory;
// Set the api to the target.
releaseTargets[apiVersion] = releaseId;
// Increase our number of releases.
numReleases = releaseId + 1;
// Log the release for external listeners
emit NewRelease(releaseId, _factory, apiVersion);
}
}
// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC4626.sol)
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*
* _Available since v4.1._
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}
/**
* @dev Interface of the ERC4626 "Tokenized Vault Standard", as defined in
* https://eips.ethereum.org/EIPS/eip-4626[ERC-4626].
*
* _Available since v4.7._
*/
interface IERC4626 is IERC20, IERC20Metadata {
event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);
event Withdraw(
address indexed sender,
address indexed receiver,
address indexed owner,
uint256 assets,
uint256 shares
);
/**
* @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.
*
* - MUST be an ERC-20 token contract.
* - MUST NOT revert.
*/
function asset() external view returns (address assetTokenAddress);
/**
* @dev Returns the total amount of the underlying asset that is “managed” by Vault.
*
* - SHOULD include any compounding that occurs from yield.
* - MUST be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT revert.
*/
function totalAssets() external view returns (uint256 totalManagedAssets);
/**
* @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal
* scenario where all the conditions are met.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToShares(uint256 assets) external view returns (uint256 shares);
/**
* @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal
* scenario where all the conditions are met.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToAssets(uint256 shares) external view returns (uint256 assets);
/**
* @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,
* through a deposit call.
*
* - MUST return a limited value if receiver is subject to some deposit limit.
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.
* - MUST NOT revert.
*/
function maxDeposit(address receiver) external view returns (uint256 maxAssets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit
* call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called
* in the same transaction.
* - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the
* deposit would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewDeposit(uint256 assets) external view returns (uint256 shares);
/**
* @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.
*
* - MUST emit the Deposit event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* deposit execution, and are accounted for during deposit.
* - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not
* approving enough underlying tokens to the Vault contract, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
*/
function deposit(uint256 assets, address receiver) external returns (uint256 shares);
/**
* @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.
* - MUST return a limited value if receiver is subject to some mint limit.
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.
* - MUST NOT revert.
*/
function maxMint(address receiver) external view returns (uint256 maxShares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call
* in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the
* same transaction.
* - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint
* would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by minting.
*/
function previewMint(uint256 shares) external view returns (uint256 assets);
/**
* @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.
*
* - MUST emit the Deposit event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint
* execution, and are accounted for during mint.
* - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not
* approving enough underlying tokens to the Vault contract, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
*/
function mint(uint256 shares, address receiver) external returns (uint256 assets);
/**
* @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the
* Vault, through a withdraw call.
*
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
* - MUST NOT revert.
*/
function maxWithdraw(address owner) external view returns (uint256 maxAssets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw
* call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if
* called
* in the same transaction.
* - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though
* the withdrawal would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewWithdraw(uint256 assets) external view returns (uint256 shares);
/**
* @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.
*
* - MUST emit the Withdraw event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* withdraw execution, and are accounted for during withdraw.
* - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner
* not having enough shares, etc).
*
* Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
* Those methods should be performed separately.
*/
function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);
/**
* @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,
* through a redeem call.
*
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
* - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.
* - MUST NOT revert.
*/
function maxRedeem(address owner) external view returns (uint256 maxShares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call
* in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the
* same transaction.
* - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the
* redemption would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by redeeming.
*/
function previewRedeem(uint256 shares) external view returns (uint256 assets);
/**
* @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.
*
* - MUST emit the Withdraw event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* redeem execution, and are accounted for during redeem.
* - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner
* not having enough shares, etc).
*
* NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
* Those methods should be performed separately.
*/
function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);
}
interface IVault is IERC4626 {
// STRATEGY EVENTS
event StrategyChanged(address indexed strategy, uint256 change_type);
event StrategyReported(
address indexed strategy,
uint256 gain,
uint256 loss,
uint256 current_debt,
uint256 protocol_fees,
uint256 total_fees,
uint256 total_refunds
);
// DEBT MANAGEMENT EVENTS
event DebtUpdated(
address indexed strategy,
uint256 current_debt,
uint256 new_debt
);
// ROLE UPDATES
event RoleSet(address indexed account, uint256 role);
event UpdateRoleManager(address indexed role_manager);
event UpdateAccountant(address indexed accountant);
event UpdateDefaultQueue(address[] new_default_queue);
event UpdateUseDefaultQueue(bool use_default_queue);
event UpdatedMaxDebtForStrategy(
address indexed sender,
address indexed strategy,
uint256 new_debt
);
event UpdateDepositLimit(uint256 deposit_limit);
event UpdateMinimumTotalIdle(uint256 minimum_total_idle);
event UpdateProfitMaxUnlockTime(uint256 profit_max_unlock_time);
event DebtPurchased(address indexed strategy, uint256 amount);
event Shutdown();
struct StrategyParams {
uint256 activation;
uint256 last_report;
uint256 current_debt;
uint256 max_debt;
}
function FACTORY() external view returns (uint256);
function strategies(address) external view returns (StrategyParams memory);
function default_queue(uint256) external view returns (address);
function use_default_queue() external view returns (bool);
function minimum_total_idle() external view returns (uint256);
function deposit_limit() external view returns (uint256);
function deposit_limit_module() external view returns (address);
function withdraw_limit_module() external view returns (address);
function accountant() external view returns (address);
function roles(address) external view returns (uint256);
function role_manager() external view returns (address);
function future_role_manager() external view returns (address);
function isShutdown() external view returns (bool);
function nonces(address) external view returns (uint256);
function initialize(
address,
string memory,
string memory,
address,
uint256
) external;
function set_accountant(address new_accountant) external;
function set_default_queue(address[] memory new_default_queue) external;
function set_use_default_queue(bool) external;
function set_deposit_limit(uint256 deposit_limit) external;
function set_deposit_limit(
uint256 deposit_limit,
bool should_override
) external;
function set_deposit_limit_module(
address new_deposit_limit_module
) external;
function set_deposit_limit_module(
address new_deposit_limit_module,
bool should_override
) external;
function set_withdraw_limit_module(
address new_withdraw_limit_module
) external;
function set_minimum_total_idle(uint256 minimum_total_idle) external;
function setProfitMaxUnlockTime(
uint256 new_profit_max_unlock_time
) external;
function set_role(address account, uint256 role) external;
function add_role(address account, uint256 role) external;
function remove_role(address account, uint256 role) external;
function transfer_role_manager(address role_manager) external;
function accept_role_manager() external;
function unlockedShares() external view returns (uint256);
function pricePerShare() external view returns (uint256);
function get_default_queue() external view returns (address[] memory);
function process_report(
address strategy
) external returns (uint256, uint256);
function buy_debt(address strategy, uint256 amount) external;
function add_strategy(address new_strategy) external;
function revoke_strategy(address strategy) external;
function force_revoke_strategy(address strategy) external;
function update_max_debt_for_strategy(
address strategy,
uint256 new_max_debt
) external;
function update_debt(
address strategy,
uint256 target_debt
) external returns (uint256);
function update_debt(
address strategy,
uint256 target_debt,
uint256 max_loss
) external returns (uint256);
function shutdown_vault() external;
function totalIdle() external view returns (uint256);
function totalDebt() external view returns (uint256);
function apiVersion() external view returns (string memory);
function assess_share_of_unrealised_losses(
address strategy,
uint256 assets_needed
) external view returns (uint256);
function profitMaxUnlockTime() external view returns (uint256);
function fullProfitUnlockDate() external view returns (uint256);
function profitUnlockingRate() external view returns (uint256);
function lastProfitUpdate() external view returns (uint256);
//// NON-STANDARD ERC-4626 FUNCTIONS \\\\
function withdraw(
uint256 assets,
address receiver,
address owner,
uint256 max_loss
) external returns (uint256);
function withdraw(
uint256 assets,
address receiver,
address owner,
uint256 max_loss,
address[] memory strategies
) external returns (uint256);
function redeem(
uint256 shares,
address receiver,
address owner,
uint256 max_loss
) external returns (uint256);
function redeem(
uint256 shares,
address receiver,
address owner,
uint256 max_loss,
address[] memory strategies
) external returns (uint256);
function maxWithdraw(
address owner,
uint256 max_loss
) external view returns (uint256);
function maxWithdraw(
address owner,
uint256 max_loss,
address[] memory strategies
) external view returns (uint256);
function maxRedeem(
address owner,
uint256 max_loss
) external view returns (uint256);
function maxRedeem(
address owner,
uint256 max_loss,
address[] memory strategies
) external view returns (uint256);
//// NON-STANDARD ERC-20 FUNCTIONS \\\\
function DOMAIN_SEPARATOR() external view returns (bytes32);
function permit(
address owner,
address spender,
uint256 amount,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external returns (bool);
}
interface IVaultFactory {
function deploy_new_vault(
address asset,
string memory name,
string memory symbol,
address role_manager,
uint256 profit_max_unlock_time
) external returns (address);
function apiVersion() external view returns (string memory);
}
/**
* @title YearnV3 Registry
* @author yearn.finance
* @notice
* Serves as an on chain registry to track any Yearn
* vaults and strategies that a certain party wants to
* endorse.
*
* Can also be used to deploy new vaults of any specific
* API version.
*/
contract Registry is Governance {
/// @notice Emitted when a new vault is deployed or added.
event NewEndorsedVault(
address indexed vault,
address indexed asset,
uint256 releaseVersion,
uint256 vaultType
);
/// @notice Emitted when a vault is removed.
event RemovedVault(
address indexed vault,
address indexed asset,
uint256 releaseVersion,
uint256 vaultType
);
/// @notice Emitted when a vault is tagged which a string.
event VaultTagged(address indexed vault);
/// @notice Emitted when gov adds ore removes a `tagger`.
event UpdateTagger(address indexed account, bool status);
/// @notice Emitted when gov adds ore removes a `endorser`.
event UpdateEndorser(address indexed account, bool status);
/// @notice Can only be gov or an `endorser`.
modifier onlyEndorsers() {
_isEndorser();
_;
}
/// @notice Can only be gov or a `tagger`.
modifier onlyTaggers() {
_isTagger();
_;
}
/// @notice Check is gov or an `endorser`.
function _isEndorser() internal view {
require(msg.sender == governance || endorsers[msg.sender], "!endorser");
}
/// @notice Check is gov or a `tagger`.
function _isTagger() internal view {
require(msg.sender == governance || taggers[msg.sender], "!tagger");
}
// Struct stored for every endorsed vault or strategy for
// off chain use to easily retrieve info.
struct Info {
// The token thats being used.
address asset;
// The release number corresponding to the release registries version.
uint96 releaseVersion;
// Type of vault.
uint64 vaultType;
// Time when the vault was deployed for easier indexing.
uint128 deploymentTimestamp;
// Index the vault is at in array for easy removals.
uint64 index;
// String so that management can tag a vault with any info for FE's.
string tag;
}
// Address used to get the specific versions from.
address public immutable releaseRegistry;
// Default type used for Multi strategy "Allocator" vaults.
uint256 public constant MULTI_STRATEGY_TYPE = 1;
// Default type used for Single "Tokenized" Strategy vaults.
uint256 public constant SINGLE_STRATEGY_TYPE = 2;
// Custom name for this Registry.
string public name;
// Mapping for any address that is allowed to tag a vault.
mapping(address => bool) public taggers;
// Mapping for any address that is allowed to deploy or endorse.
mapping(address => bool) public endorsers;
// vault/strategy address => Info struct.
mapping(address => Info) public vaultInfo;
// Mapping to check if a specific `asset` has a vault.
mapping(address => bool) public assetIsUsed;
// asset => array of all endorsed vaults.
mapping(address => address[]) internal _endorsedVaults;
// Array of all tokens used as the underlying.
address[] public assets;
/**
* @param _governance Address to set as owner of the Registry.
* @param _name The custom string for this custom registry to be called.
* @param _releaseRegistry The Permissionless releaseRegistry to deploy vaults through.
*/
constructor(
address _governance,
string memory _name,
address _releaseRegistry
) Governance(_governance) {
// Set name.
name = _name;
// Set releaseRegistry.
releaseRegistry = _releaseRegistry;
}
/**
* @notice Returns the total number of assets being used as the underlying.
* @return The amount of assets.
*/
function numAssets() external view virtual returns (uint256) {
return assets.length;
}
/**
* @notice Get the full array of tokens being used.
* @return The full array of underlying tokens being used/.
*/
function getAssets() external view virtual returns (address[] memory) {
return assets;
}
/**
* @notice The amount of endorsed vaults for a specific token.
* @return The amount of endorsed vaults.
*/
function numEndorsedVaults(
address _asset
) public view virtual returns (uint256) {
return _endorsedVaults[_asset].length;
}
/**
* @notice Get the array of vaults endorsed for an `_asset`.
* @param _asset The underlying token used by the vaults.
* @return The endorsed vaults.
*/
function getEndorsedVaults(
address _asset
) external view virtual returns (address[] memory) {
return _endorsedVaults[_asset];
}
/**
* @notice Get all endorsed vaults deployed using the Registry.
* @dev This will return a nested array of all vaults deployed
* separated by their underlying asset.
*
* This is only meant for off chain viewing and should not be used during any
* on chain tx's.
*
* @return allEndorsedVaults A nested array containing all vaults.
*/
function getAllEndorsedVaults()
external
view
virtual
returns (address[][] memory allEndorsedVaults)
{
address[] memory allAssets = assets;
uint256 length = assets.length;
allEndorsedVaults = new address[][](length);
for (uint256 i; i < length; ++i) {
allEndorsedVaults[i] = _endorsedVaults[allAssets[i]];
}
}
/**
* @notice Check if a vault is endorsed in this registry.
* @dev This will check if the `asset` variable in the struct has been
* set for an easy external view check.
* @param _vault Address of the vault to check.
* @return . The vaults endorsement status.
*/
function isEndorsed(address _vault) external view virtual returns (bool) {
return vaultInfo[_vault].asset != address(0);
}
/**
* @notice
* Create and endorse a new multi strategy "Allocator"
* vault and endorse it in this registry.
* @dev
* Throws if caller isn't `owner`.
* Throws if no releases are registered yet.
* Emits a `NewEndorsedVault` event.
* @param _asset The asset that may be deposited into the new Vault.
* @param _name Specify a custom Vault name. .
* @param _symbol Specify a custom Vault symbol name.
* @param _roleManager The address authorized for guardian interactions in the new Vault.
* @param _profitMaxUnlockTime The time strategy profits will unlock over.
* @return _vault address of the newly-deployed vault
*/
function newEndorsedVault(
address _asset,
string memory _name,
string memory _symbol,
address _roleManager,
uint256 _profitMaxUnlockTime
) public virtual returns (address _vault) {
return
newEndorsedVault(
_asset,
_name,
_symbol,
_roleManager,
_profitMaxUnlockTime,
0 // Default to latest version.
);
}
/**
* @notice
* Create and endorse a new multi strategy "Allocator"
* vault and endorse it in this registry.
* @dev
* Throws if caller isn't `owner`.
* Throws if no releases are registered yet.
* Emits a `NewEndorsedVault` event.
* @param _asset The asset that may be deposited into the new Vault.
* @param _name Specify a custom Vault name. .
* @param _symbol Specify a custom Vault symbol name.
* @param _roleManager The address authorized for guardian interactions in the new Vault.
* @param _profitMaxUnlockTime The time strategy profits will unlock over.
* @param _releaseDelta The number of releases prior to the latest to use as a target. NOTE: Set to 0 for latest.
* @return _vault address of the newly-deployed vault
*/
function newEndorsedVault(
address _asset,
string memory _name,
string memory _symbol,
address _roleManager,
uint256 _profitMaxUnlockTime,
uint256 _releaseDelta
) public virtual onlyEndorsers returns (address _vault) {
// Get the target release based on the delta given.
uint256 _releaseTarget = ReleaseRegistry(releaseRegistry)
.numReleases() -
1 -
_releaseDelta;
// Get the factory address for that specific Api version.
address factory = ReleaseRegistry(releaseRegistry).factories(
_releaseTarget
);
// Make sure we got an actual factory
require(factory != address(0), "Registry: unknown release");
// Deploy New vault.
_vault = IVaultFactory(factory).deploy_new_vault(
_asset,
_name,
_symbol,
_roleManager,
_profitMaxUnlockTime
);
// Register the vault with this Registry
_registerVault(
_vault,
_asset,
_releaseTarget,
MULTI_STRATEGY_TYPE,
block.timestamp
);
}
/**
* @notice Endorse an already deployed multi strategy vault.
* @dev To be used with default values for `_releaseDelta`, `_vaultType`
* and `_deploymentTimestamp`.
* @param _vault Address of the vault to endorse.
*/
function endorseMultiStrategyVault(address _vault) external virtual {
endorseVault(_vault, 0, MULTI_STRATEGY_TYPE, 0);
}
/**
* @notice Endorse an already deployed Single Strategy vault.
* @dev To be used with default values for `_releaseDelta`, `_vaultType`
* and `_deploymentTimestamp`.
*
* @param _vault Address of the vault to endorse.
*/
function endorseSingleStrategyVault(address _vault) external virtual {
endorseVault(_vault, 0, SINGLE_STRATEGY_TYPE, 0);
}
/**
* @notice
* Adds an existing vault to the list of "endorsed" vaults for that asset.
* @dev
* Throws if caller isn't `owner`.
* Throws if no releases are registered yet.
* Throws if `vault`'s api version does not match the release specified.
* Emits a `NewEndorsedVault` event.
* @param _vault The vault that will be endorsed by the Registry.
* @param _releaseDelta Specify the number of releases prior to the latest to use as a target.
* @param _vaultType Type of vault to endorse.
* @param _deploymentTimestamp The timestamp of when the vault was deployed for FE use.
*/
function endorseVault(
address _vault,
uint256 _releaseDelta,
uint256 _vaultType,
uint256 _deploymentTimestamp
) public virtual onlyEndorsers {
// Cannot endorse twice.
require(vaultInfo[_vault].asset == address(0), "endorsed");
require(_vaultType != 0, "no 0 type");
require(_vaultType <= type(uint128).max, "type too high");
require(_deploymentTimestamp <= block.timestamp, "!deployment time");
// Will underflow if no releases created yet, or targeting prior to release history
uint256 _releaseTarget = ReleaseRegistry(releaseRegistry)
.numReleases() -
1 -
_releaseDelta; // dev: no releases
// Get the API version for the target specified
string memory apiVersion = IVaultFactory(
ReleaseRegistry(releaseRegistry).factories(_releaseTarget)
).apiVersion();
require(
keccak256(bytes(IVault(_vault).apiVersion())) ==
keccak256(bytes((apiVersion))),
"Wrong API Version"
);
// Add to the end of the list of vaults for asset
_registerVault(
_vault,
IVault(_vault).asset(),
_releaseTarget,
_vaultType,
_deploymentTimestamp
);
}
/**
* @dev Function used to register a newly deployed or added vault.
*
* This well set all of the values for the vault in the `vaultInfo`
* mapping as well as add the vault and the underlying asset to any
* relevant arrays for tracking.
*
*/
function _registerVault(
address _vault,
address _asset,
uint256 _releaseTarget,
uint256 _vaultType,
uint256 _deploymentTimestamp
) internal virtual {
// Set the Info struct for this vault
vaultInfo[_vault] = Info({
asset: _asset,
releaseVersion: uint96(_releaseTarget),
vaultType: uint64(_vaultType),
deploymentTimestamp: uint128(_deploymentTimestamp),
index: uint64(_endorsedVaults[_asset].length),
tag: ""
});
// Add to the endorsed vaults array.
_endorsedVaults[_asset].push(_vault);
if (!assetIsUsed[_asset]) {
// We have a new asset to add
assets.push(_asset);
assetIsUsed[_asset] = true;
}
emit NewEndorsedVault(_vault, _asset, _releaseTarget, _vaultType);
}
/**
* @notice Tag a vault with a specific string.
* @dev This is available to governance to tag any vault or strategy
* on chain if desired to arbitrarily classify any vaults.
* i.e. Certain ratings ("A") / Vault status ("Shutdown") etc.
*
* @param _vault Address of the vault or strategy to tag.
* @param _tag The string to tag the vault or strategy with.
*/
function tagVault(
address _vault,
string memory _tag
) external virtual onlyTaggers {
require(vaultInfo[_vault].asset != address(0), "!Endorsed");
vaultInfo[_vault].tag = _tag;
emit VaultTagged(_vault);
}
/**
* @notice Remove a `_vault`.
* @dev Can be used as an efficient way to remove a vault
* to not have to iterate over the full array.
*
* NOTE: This will not remove the asset from the `assets` array
* if it is no longer in use and will have to be done manually.
*
* @param _vault Address of the vault to remove.
*/
function removeVault(address _vault) external virtual onlyEndorsers {
// Get the struct with all the vaults data.
Info memory info = vaultInfo[_vault];
require(info.asset != address(0), "!endorsed");
require(
_endorsedVaults[info.asset][info.index] == _vault,
"wrong vault"
);
// Get the vault at the end of the array
address lastVault = _endorsedVaults[info.asset][
_endorsedVaults[info.asset].length - 1
];
// If `_vault` is not the last item in the array.
if (lastVault != _vault) {
// Set the last index to the spot we are removing.
_endorsedVaults[info.asset][info.index] = lastVault;
// Update the index of the vault we moved
vaultInfo[lastVault].index = uint64(info.index);
}
// Pop the last item off the array.
_endorsedVaults[info.asset].pop();
// Emit the event.
emit RemovedVault(
_vault,
info.asset,
info.releaseVersion,
info.vaultType
);
// Delete the struct.
delete vaultInfo[_vault];
}
/**
* @notice Removes a specific `_asset` at `_index` from `assets`.
* @dev Can be used if an asset is no longer in use after a vault or
* strategy has also been removed.
*
* @param _asset The asset to remove from the array.
* @param _index The index it sits at.
*/
function removeAsset(
address _asset,
uint256 _index
) external virtual onlyEndorsers {
require(assetIsUsed[_asset], "!in use");
require(_endorsedVaults[_asset].length == 0, "still in use");
require(assets[_index] == _asset, "wrong asset");
// Replace `_asset` with the last index.
assets[_index] = assets[assets.length - 1];
// Pop last item off the array.
assets.pop();
// No longer used.
assetIsUsed[_asset] = false;
}
/**
* @notice Set a new address to be able to endorse or remove an existing endorser.
* @param _account The address to set.
* @param _canEndorse Bool if the `_account` can or cannot endorse.
*/
function setEndorser(
address _account,
bool _canEndorse
) external virtual onlyGovernance {
endorsers[_account] = _canEndorse;
emit UpdateEndorser(_account, _canEndorse);
}
/**
* @notice Set a new address to be able to tag a vault.
* @param _account The address to set.
* @param _canTag Bool if the `_account` can or cannot tag.
*/
function setTagger(
address _account,
bool _canTag
) external virtual onlyGovernance {
taggers[_account] = _canTag;
emit UpdateTagger(_account, _canTag);
}
}
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @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 up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (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; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
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.
require(denominator > prod1, "Math: mulDiv overflow");
///////////////////////////////////////////////
// 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.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
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 (rounding == Rounding.Up && 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 down.
*
* 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 + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* 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 + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* 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 + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* 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 + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol)
// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.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 Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}
/**
* @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}.
* For a generic mechanism see {ERC20PresetMinterPauser}.
*
* 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.
*
* Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
* functions have been added to mitigate the well-known issues around setting
* allowances. See {IERC20-approve}.
*/
contract ERC20 is Context, IERC20, IERC20Metadata {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* All two of these values are immutable: they can only be set once during
* construction.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual override returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the default value returned by this function, unless
* it's overridden.
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual override returns (uint8) {
return 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `amount`.
*/
function transfer(address to, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_transfer(owner, to, amount);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `amount` 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 amount) public virtual override returns (bool) {
address owner = _msgSender();
_approve(owner, spender, amount);
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 `amount`.
* - the caller must have allowance for ``from``'s tokens of at least
* `amount`.
*/
function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, amount);
_transfer(from, to, amount);
return true;
}
/**
* @dev Atomically increases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, allowance(owner, spender) + addedValue);
return true;
}
/**
* @dev Atomically decreases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `spender` must have allowance for the caller of at least
* `subtractedValue`.
*/
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
address owner = _msgSender();
uint256 currentAllowance = allowance(owner, spender);
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
unchecked {
_approve(owner, spender, currentAllowance - subtractedValue);
}
return true;
}
/**
* @dev Moves `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.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
*/
function _transfer(address from, address to, uint256 amount) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(from, to, amount);
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
// Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
// decrementing then incrementing.
_balances[to] += amount;
}
emit Transfer(from, to, amount);
_afterTokenTransfer(from, to, amount);
}
/** @dev Creates `amount` tokens and assigns them to `account`, increasing
* the total supply.
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
unchecked {
// Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
_balances[account] += amount;
}
emit Transfer(address(0), account, amount);
_afterTokenTransfer(address(0), account, amount);
}
/**
* @dev Destroys `amount` tokens from `account`, reducing the
* total supply.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
* - `account` must have at least `amount` tokens.
*/
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
unchecked {
_balances[account] = accountBalance - amount;
// Overflow not possible: amount <= accountBalance <= totalSupply.
_totalSupply -= amount;
}
emit Transfer(account, address(0), amount);
_afterTokenTransfer(account, address(0), amount);
}
/**
* @dev Sets `amount` 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.
*/
function _approve(address owner, address spender, uint256 amount) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
/**
* @dev Updates `owner` s allowance for `spender` based on spent `amount`.
*
* Does not update the allowance amount in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Might emit an {Approval} event.
*/
function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "ERC20: insufficient allowance");
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
/**
* @dev Hook that is called before any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* will be transferred to `to`.
* - when `from` is zero, `amount` tokens will be minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens will be burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}
/**
* @dev Hook that is called after any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* has been transferred to `to`.
* - when `from` is zero, `amount` tokens have been minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens have been burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}
}
// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)
// OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol)
/**
* @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);
}
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(IERC20 token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
* Revert on invalid signature.
*/
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return
success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
}
}
/// @title Accountant.
/// @dev Will charge fees, issue refunds, and run health check on any reported
/// gains or losses during a strategy's report.
contract Accountant {
using SafeERC20 for ERC20;
/// @notice An event emitted when a vault is added or removed.
event VaultChanged(address indexed vault, ChangeType change);
/// @notice An event emitted when the default fee configuration is updated.
event UpdateDefaultFeeConfig(Fee defaultFeeConfig);
/// @notice An event emitted when the future fee manager is set.
event SetFutureFeeManager(address indexed futureFeeManager);
/// @notice An event emitted when a new fee manager is accepted.
event NewFeeManager(address indexed feeManager);
/// @notice An event emitted when a new vault manager is set.
event UpdateVaultManager(address indexed newVaultManager);
/// @notice An event emitted when the fee recipient is updated.
event UpdateFeeRecipient(
address indexed oldFeeRecipient,
address indexed newFeeRecipient
);
/// @notice An event emitted when a custom fee configuration is updated.
event UpdateCustomFeeConfig(address indexed vault, Fee custom_config);
/// @notice An event emitted when a custom fee configuration is removed.
event RemovedCustomFeeConfig(address indexed vault);
/// @notice An event emitted when the `maxLoss` parameter is updated.
event UpdateMaxLoss(uint256 maxLoss);
/// @notice An event emitted when rewards are distributed.
event DistributeRewards(address indexed token, uint256 rewards);
/// @notice Enum defining change types (added or removed).
enum ChangeType {
NULL,
ADDED,
REMOVED
}
/// @notice Struct representing fee details.
struct Fee {
uint16 managementFee; // Annual management fee to charge.
uint16 performanceFee; // Performance fee to charge.
uint16 refundRatio; // Refund ratio to give back on losses.
uint16 maxFee; // Max fee allowed as a percent of gain.
uint16 maxGain; // Max percent gain a strategy can report.
uint16 maxLoss; // Max percent loss a strategy can report.
bool custom; // Flag to set for custom configs.
}
modifier onlyFeeManager() {
_checkFeeManager();
_;
}
modifier onlyVaultOrFeeManager() {
_checkVaultOrFeeManager();
_;
}
modifier onlyFeeManagerOrRecipient() {
_checkFeeManagerOrRecipient();
_;
}
modifier onlyAddedVaults() {
_checkVaultIsAdded();
_;
}
function _checkFeeManager() internal view virtual {
require(msg.sender == feeManager, "!fee manager");
}
function _checkVaultOrFeeManager() internal view virtual {
require(
msg.sender == feeManager || msg.sender == vaultManager,
"!vault manager"
);
}
function _checkFeeManagerOrRecipient() internal view virtual {
require(
msg.sender == feeRecipient || msg.sender == feeManager,
"!recipient"
);
}
function _checkVaultIsAdded() internal view virtual {
require(vaults[msg.sender], "vault not added");
}
/// @notice Constant defining the maximum basis points.
uint256 internal constant MAX_BPS = 10_000;
/// @notice Constant defining the number of seconds in a year.
uint256 internal constant SECS_PER_YEAR = 31_556_952;
/// @notice Constant defining the management fee threshold.
uint16 public constant MANAGEMENT_FEE_THRESHOLD = 200;
/// @notice Constant defining the performance fee threshold.
uint16 public constant PERFORMANCE_FEE_THRESHOLD = 5_000;
/// @notice The amount of max loss to use when redeeming from vaults.
uint256 public maxLoss;
/// @notice The address of the fee manager.
address public feeManager;
/// @notice The address of the fee recipient.
address public feeRecipient;
/// @notice An address that can add or remove vaults.
address public vaultManager;
/// @notice The address of the future fee manager.
address public futureFeeManager;
/// @notice The default fee configuration.
Fee public defaultConfig;
/// @notice Mapping to track added vaults.
mapping(address => bool) public vaults;
/// @notice Mapping vault => custom Fee config if any.
mapping(address => Fee) public customConfig;
/// @notice Mapping vault => strategy => flag for one time healthcheck skips.
mapping(address => mapping(address => bool)) skipHealthCheck;
constructor(
address _feeManager,
address _feeRecipient,
uint16 defaultManagement,
uint16 defaultPerformance,
uint16 defaultRefund,
uint16 defaultMaxFee,
uint16 defaultMaxGain,
uint16 defaultMaxLoss
) {
require(_feeManager != address(0), "ZERO ADDRESS");
require(_feeRecipient != address(0), "ZERO ADDRESS");
feeManager = _feeManager;
feeRecipient = _feeRecipient;
_updateDefaultConfig(
defaultManagement,
defaultPerformance,
defaultRefund,
defaultMaxFee,
defaultMaxGain,
defaultMaxLoss
);
}
/**
* @notice Called by a vault when a `strategy` is reporting.
* @dev The msg.sender must have been added to the `vaults` mapping.
* @param strategy Address of the strategy reporting.
* @param gain Amount of the gain if any.
* @param loss Amount of the loss if any.
* @return totalFees if any to charge.
* @return totalRefunds if any for the vault to pull.
*/
function report(
address strategy,
uint256 gain,
uint256 loss
)
public
virtual
onlyAddedVaults
returns (uint256 totalFees, uint256 totalRefunds)
{
// Declare the config to use as the custom.
Fee memory fee = customConfig[msg.sender];
// Check if there is a custom config to use.
if (!fee.custom) {
// Otherwise use the default.
fee = defaultConfig;
}
// Retrieve the strategy's params from the vault.
IVault.StrategyParams memory strategyParams = IVault(msg.sender)
.strategies(strategy);
// Charge management fees no matter gain or loss.
if (fee.managementFee > 0) {
// Time since the last harvest.
uint256 duration = block.timestamp - strategyParams.last_report;
// managementFee is an annual amount, so charge based on the time passed.
totalFees = ((strategyParams.current_debt *
duration *
(fee.managementFee)) /
MAX_BPS /
SECS_PER_YEAR);
}
// Only charge performance fees if there is a gain.
if (gain > 0) {
// If we are skipping the healthcheck this report
if (skipHealthCheck[msg.sender][strategy]) {
// Make sure it is reset for the next one.
skipHealthCheck[msg.sender][strategy] = false;
// Setting `maxGain` to 0 will disable the healthcheck on profits.
} else if (fee.maxGain > 0) {
require(
gain <=
(strategyParams.current_debt * (fee.maxGain)) / MAX_BPS,
"too much gain"
);
}
totalFees += (gain * (fee.performanceFee)) / MAX_BPS;
} else {
// If we are skipping the healthcheck this report
if (skipHealthCheck[msg.sender][strategy]) {
// Make sure it is reset for the next one.
skipHealthCheck[msg.sender][strategy] = false;
// Setting `maxLoss` to 10_000 will disable the healthcheck on losses.
} else if (fee.maxLoss < MAX_BPS) {
require(
loss <=
(strategyParams.current_debt * (fee.maxLoss)) / MAX_BPS,
"too much loss"
);
}
// Means we should have a loss.
if (fee.refundRatio > 0) {
// Cache the underlying asset the vault uses.
address asset = IVault(msg.sender).asset();
// Give back either all we have or based on the refund ratio.
totalRefunds = Math.min(
(loss * (fee.refundRatio)) / MAX_BPS,
ERC20(asset).balanceOf(address(this))
);
if (totalRefunds > 0) {
// Approve the vault to pull the underlying asset.
_checkAllowance(msg.sender, asset, totalRefunds);
}
}
}
// 0 Max fee means it is not enforced.
if (fee.maxFee > 0) {
// Ensure fee does not exceed the maxFee %.
totalFees = Math.min((gain * (fee.maxFee)) / MAX_BPS, totalFees);
}
return (totalFees, totalRefunds);
}
/**
* @notice Function to add a new vault for this accountant to charge fees for.
* @dev This is not used to set any of the fees for the specific vault or strategy. Each fee will be set separately.
* @param vault The address of a vault to allow to use this accountant.
*/
function addVault(address vault) external virtual onlyVaultOrFeeManager {
// Ensure the vault has not already been added.
require(!vaults[vault], "already added");
vaults[vault] = true;
emit VaultChanged(vault, ChangeType.ADDED);
}
/**
* @notice Function to remove a vault from this accountant's fee charging list.
* @param vault The address of the vault to be removed from this accountant.
*/
function removeVault(address vault) external virtual onlyVaultOrFeeManager {
// Ensure the vault has been previously added.
require(vaults[vault], "not added");
address asset = IVault(vault).asset();
// Remove any allowances left.
if (ERC20(asset).allowance(address(this), vault) != 0) {
ERC20(asset).safeApprove(vault, 0);
}
vaults[vault] = false;
emit VaultChanged(vault, ChangeType.REMOVED);
}
/**
* @notice Function to update the default fee configuration used for
all strategies that don't have a custom config set.
* @param defaultManagement Default annual management fee to charge.
* @param defaultPerformance Default performance fee to charge.
* @param defaultRefund Default refund ratio to give back on losses.
* @param defaultMaxFee Default max fee to allow as a percent of gain.
* @param defaultMaxGain Default max percent gain a strategy can report.
* @param defaultMaxLoss Default max percent loss a strategy can report.
*/
function updateDefaultConfig(
uint16 defaultManagement,
uint16 defaultPerformance,
uint16 defaultRefund,
uint16 defaultMaxFee,
uint16 defaultMaxGain,
uint16 defaultMaxLoss
) external virtual onlyFeeManager {
_updateDefaultConfig(
defaultManagement,
defaultPerformance,
defaultRefund,
defaultMaxFee,
defaultMaxGain,
defaultMaxLoss
);
}
/**
* @dev Updates the Accountant's default fee config.
* Is used during deployment and during any future updates.
*/
function _updateDefaultConfig(
uint16 defaultManagement,
uint16 defaultPerformance,
uint16 defaultRefund,
uint16 defaultMaxFee,
uint16 defaultMaxGain,
uint16 defaultMaxLoss
) internal virtual {
// Check for threshold and limit conditions.
require(
defaultManagement <= MANAGEMENT_FEE_THRESHOLD,
"management fee threshold"
);
require(
defaultPerformance <= PERFORMANCE_FEE_THRESHOLD,
"performance fee threshold"
);
require(defaultMaxLoss <= MAX_BPS, "too high");
// Update the default fee configuration.
defaultConfig = Fee({
managementFee: defaultManagement,
performanceFee: defaultPerformance,
refundRatio: defaultRefund,
maxFee: defaultMaxFee,
maxGain: defaultMaxGain,
maxLoss: defaultMaxLoss,
custom: false
});
emit UpdateDefaultFeeConfig(defaultConfig);
}
/**
* @notice Function to set a custom fee configuration for a specific vault.
* @param vault The vault the strategy is hooked up to.
* @param customManagement Custom annual management fee to charge.
* @param customPerformance Custom performance fee to charge.
* @param customRefund Custom refund ratio to give back on losses.
* @param customMaxFee Custom max fee to allow as a percent of gain.
* @param customMaxGain Custom max percent gain a strategy can report.
* @param customMaxLoss Custom max percent loss a strategy can report.
*/
function setCustomConfig(
address vault,
uint16 customManagement,
uint16 customPerformance,
uint16 customRefund,
uint16 customMaxFee,
uint16 customMaxGain,
uint16 customMaxLoss
) external virtual onlyFeeManager {
// Ensure the vault has been added.
require(vaults[vault], "vault not added");
// Check for threshold and limit conditions.
require(
customManagement <= MANAGEMENT_FEE_THRESHOLD,
"management fee threshold"
);
require(
customPerformance <= PERFORMANCE_FEE_THRESHOLD,
"performance fee threshold"
);
require(customMaxLoss <= MAX_BPS, "too high");
// Create the vault's custom config.
Fee memory _config = Fee({
managementFee: customManagement,
performanceFee: customPerformance,
refundRatio: customRefund,
maxFee: customMaxFee,
maxGain: customMaxGain,
maxLoss: customMaxLoss,
custom: true
});
// Store the config.
customConfig[vault] = _config;
emit UpdateCustomFeeConfig(vault, _config);
}
/**
* @notice Function to remove a previously set custom fee configuration for a vault.
* @param vault The vault to remove custom setting for.
*/
function removeCustomConfig(address vault) external virtual onlyFeeManager {
// Ensure custom fees are set for the specified vault.
require(customConfig[vault].custom, "No custom fees set");
// Set all the vaults's custom fees to 0.
delete customConfig[vault];
// Emit relevant event.
emit RemovedCustomFeeConfig(vault);
}
/**
* @notice Turn off the health check for a specific `vault` `strategy` combo.
* @dev This will only last for one report and get automatically turned back on.
* @param vault Address of the vault.
* @param strategy Address of the strategy.
*/
function turnOffHealthCheck(
address vault,
address strategy
) external virtual onlyFeeManager {
// Ensure the vault has been added.
require(vaults[vault], "vault not added");
skipHealthCheck[vault][strategy] = true;
}
/**
* @notice Public getter to check for custom setting.
* @dev We use uint256 for the flag since its cheaper so this
* will convert it to a bool for easy view functions.
*
* @param vault Address of the vault.
* @return If a custom fee config is set.
*/
function useCustomConfig(
address vault
) external view virtual returns (bool) {
return customConfig[vault].custom;
}
/**
* @notice Get the full config used for a specific `vault`.
* @param vault Address of the vault.
* @return fee The config that would be used during the report.
*/
function getVaultConfig(
address vault
) external view returns (Fee memory fee) {
fee = customConfig[vault];
// Check if there is a custom config to use.
if (!fee.custom) {
// Otherwise use the default.
fee = defaultConfig;
}
}
/**
* @notice Function to redeem the underlying asset from a vault.
* @dev Will default to using the full balance of the vault.
* @param vault The vault to redeem from.
*/
function redeemUnderlying(address vault) external virtual {
redeemUnderlying(vault, IVault(vault).balanceOf(address(this)));
}
/**
* @notice Function to redeem the underlying asset from a vault.
* @param vault The vault to redeem from.
* @param amount The amount in vault shares to redeem.
*/
function redeemUnderlying(
address vault,
uint256 amount
) public virtual onlyFeeManager {
IVault(vault).redeem(amount, address(this), address(this), maxLoss);
}
/**
* @notice Sets the `maxLoss` parameter to be used on redeems.
* @param _maxLoss The amount in basis points to set as the maximum loss.
*/
function setMaxLoss(uint256 _maxLoss) external virtual onlyFeeManager {
// Ensure that the provided `maxLoss` does not exceed 100% (in basis points).
require(_maxLoss <= MAX_BPS, "higher than 100%");
maxLoss = _maxLoss;
// Emit an event to signal the update of the `maxLoss` parameter.
emit UpdateMaxLoss(_maxLoss);
}
/**
* @notice Function to distribute all accumulated fees to the designated recipient.
* @param token The token to distribute.
*/
function distribute(address token) external virtual {
distribute(token, ERC20(token).balanceOf(address(this)));
}
/**
* @notice Function to distribute accumulated fees to the designated recipient.
* @param token The token to distribute.
* @param amount amount of token to distribute.
*/
function distribute(
address token,
uint256 amount
) public virtual onlyFeeManagerOrRecipient {
ERC20(token).safeTransfer(feeRecipient, amount);
emit DistributeRewards(token, amount);
}
/**
* @notice Function to set a future fee manager address.
* @param _futureFeeManager The address to set as the future fee manager.
*/
function setFutureFeeManager(
address _futureFeeManager
) external virtual onlyFeeManager {
// Ensure the futureFeeManager is not a zero address.
require(_futureFeeManager != address(0), "ZERO ADDRESS");
futureFeeManager = _futureFeeManager;
emit SetFutureFeeManager(_futureFeeManager);
}
/**
* @notice Function to accept the role change and become the new fee manager.
* @dev This function allows the future fee manager to accept the role change and become the new fee manager.
*/
function acceptFeeManager() external virtual {
// Make sure the sender is the future fee manager.
require(msg.sender == futureFeeManager, "not future fee manager");
feeManager = futureFeeManager;
futureFeeManager = address(0);
emit NewFeeManager(msg.sender);
}
/**
* @notice Function to set a new vault manager.
* @param newVaultManager Address to add or remove vaults.
*/
function setVaultManager(
address newVaultManager
) external virtual onlyFeeManager {
vaultManager = newVaultManager;
emit UpdateVaultManager(newVaultManager);
}
/**
* @notice Function to set a new address to receive distributed rewards.
* @param newFeeRecipient Address to receive distributed fees.
*/
function setFeeRecipient(
address newFeeRecipient
) external virtual onlyFeeManager {
// Ensure the newFeeRecipient is not a zero address.
require(newFeeRecipient != address(0), "ZERO ADDRESS");
address oldRecipient = feeRecipient;
feeRecipient = newFeeRecipient;
emit UpdateFeeRecipient(oldRecipient, newFeeRecipient);
}
/**
* @dev Internal safe function to make sure the contract you want to
* interact with has enough allowance to pull the desired tokens.
*
* @param _contract The address of the contract that will move the token.
* @param _token The ERC-20 token that will be getting spent.
* @param _amount The amount of `_token` to be spent.
*/
function _checkAllowance(
address _contract,
address _token,
uint256 _amount
) internal {
if (ERC20(_token).allowance(address(this), _contract) < _amount) {
ERC20(_token).safeApprove(_contract, 0);
ERC20(_token).safeApprove(_contract, _amount);
}
}
}
// prettier-ignore
library Roles {
uint256 internal constant ADD_STRATEGY_MANAGER = 1;
uint256 internal constant REVOKE_STRATEGY_MANAGER = 2;
uint256 internal constant FORCE_REVOKE_MANAGER = 4;
uint256 internal constant ACCOUNTANT_MANAGER = 8;
uint256 internal constant QUEUE_MANAGER = 16;
uint256 internal constant REPORTING_MANAGER = 32;
uint256 internal constant DEBT_MANAGER = 64;
uint256 internal constant MAX_DEBT_MANAGER = 128;
uint256 internal constant DEPOSIT_LIMIT_MANAGER = 256;
uint256 internal constant WITHDRAW_LIMIT_MANAGER = 512;
uint256 internal constant MINIMUM_IDLE_MANAGER = 1024;
uint256 internal constant PROFIT_UNLOCK_MANAGER = 2048;
uint256 internal constant DEBT_PURCHASER = 4096;
uint256 internal constant EMERGENCY_MANAGER = 8192;
uint256 internal constant ALL = 16383;
}
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMath {
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// must be unchecked in order to support `n = type(int256).min`
return uint256(n >= 0 ? n : -n);
}
}
}
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toString(int256 value) internal pure returns (string memory) {
return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value))));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return keccak256(bytes(a)) == keccak256(bytes(b));
}
}
contract Governance2Step is Governance {
/// @notice Emitted when the pending governance address is set.
event UpdatePendingGovernance(address indexed newPendingGovernance);
/// @notice Address that is set to take over governance.
address public pendingGovernance;
constructor(address _governance) Governance(_governance) {}
/**
* @notice Sets a new address as the `pendingGovernance` of the contract.
* @dev Throws if the caller is not current governance.
* @param _newGovernance The new governance address.
*/
function transferGovernance(
address _newGovernance
) external virtual override onlyGovernance {
require(_newGovernance != address(0), "ZERO ADDRESS");
pendingGovernance = _newGovernance;
emit UpdatePendingGovernance(_newGovernance);
}
/**
* @notice Allows the `pendingGovernance` to accept the role.
*/
function acceptGovernance() external virtual {
require(msg.sender == pendingGovernance, "!pending governance");
emit GovernanceTransferred(governance, msg.sender);
governance = msg.sender;
pendingGovernance = address(0);
}
}
/**
* @title YearnV3 Debt Allocator
* @author yearn.finance
* @notice
* This Debt Allocator is meant to be used alongside
* a Yearn V3 vault to provide the needed triggers for a keeper
* to perform automated debt updates for the vaults strategies.
*
* Each allocator contract will serve one Vault and each strategy
* that should be managed by this allocator will need to be added
* manually by setting a `targetRatio` and `maxRatio`.
*
* The allocator aims to allocate debt between the strategies
* based on their set target ratios. Which are denominated in basis
* points and represent the percent of total assets that specific
* strategy should hold.
*
* The trigger will attempt to allocate up to the `maxRatio` when
* the strategy has `minimumChange` amount less than the `targetRatio`.
* And will pull funds from the strategy when it has `minimumChange`
* more than its `maxRatio`.
*/
contract DebtAllocator {
/// @notice An event emitted when a strategies debt ratios are Updated.
event UpdateStrategyDebtRatio(
address indexed strategy,
uint256 newTargetRatio,
uint256 newMaxRatio,
uint256 newTotalDebtRatio
);
/// @notice An event emitted when a strategy is added or removed.
event StrategyChanged(address indexed strategy, Status status);
/// @notice An event emitted when the minimum time to wait is updated.
event UpdateMinimumWait(uint256 newMinimumWait);
/// @notice An event emitted when the minimum change is updated.
event UpdateMinimumChange(uint256 newMinimumChange);
/// @notice An event emitted when a keeper is added or removed.
event UpdateManager(address indexed manager, bool allowed);
/// @notice An event emitted when the max debt update loss is updated.
event UpdateMaxDebtUpdateLoss(uint256 newMaxDebtUpdateLoss);
/// @notice Status when a strategy is added or removed from the allocator.
enum Status {
NULL,
ADDED,
REMOVED
}
/// @notice Struct for each strategies info.
struct Config {
// Flag to set when a strategy is added.
bool added;
// The ideal percent in Basis Points the strategy should have.
uint16 targetRatio;
// The max percent of assets the strategy should hold.
uint16 maxRatio;
// Timestamp of the last time debt was updated.
// The debt updates must be done through this allocator
// for this to be used.
uint96 lastUpdate;
// We have an extra 120 bits in the slot.
// So we declare the variable in the struct so it can be
// used if this contract is inherited.
uint120 open;
}
/// @notice Make sure the caller is governance.
modifier onlyGovernance() {
_isGovernance();
_;
}
/// @notice Make sure the caller is governance or a manager.
modifier onlyManagers() {
_isManager();
_;
}
/// @notice Make sure the caller is a keeper
modifier onlyKeepers() {
_isKeeper();
_;
}
/// @notice Check the Factories governance address.
function _isGovernance() internal view virtual {
require(
msg.sender == DebtAllocatorFactory(factory).governance(),
"!governance"
);
}
/// @notice Check is either factories governance or local manager.
function _isManager() internal view virtual {
require(
managers[msg.sender] ||
msg.sender == DebtAllocatorFactory(factory).governance(),
"!manager"
);
}
/// @notice Check is one of the allowed keepers.
function _isKeeper() internal view virtual {
require(DebtAllocatorFactory(factory).keepers(msg.sender), "!keeper");
}
uint256 internal constant MAX_BPS = 10_000;
/// @notice Address to get permissioned roles from.
address public immutable factory;
/// @notice Address of the vault this serves as allocator for.
address public vault;
/// @notice Time to wait between debt updates in seconds.
uint256 public minimumWait;
/// @notice The minimum amount denominated in asset that will
// need to be moved to trigger a debt update.
uint256 public minimumChange;
/// @notice Total debt ratio currently allocated in basis points.
// Can't be more than 10_000.
uint256 public totalDebtRatio;
/// @notice Max loss to accept on debt updates in basis points.
uint256 public maxDebtUpdateLoss;
/// @notice Mapping of addresses that are allowed to update debt ratios.
mapping(address => bool) public managers;
/// @notice Mapping of strategy => its config.
mapping(address => Config) internal _configs;
constructor() {
// Set the factory to retrieve roles from. Will be the same for all clones so can use immutable.
factory = msg.sender;
// Don't allow for original version to be initialized.
vault = address(1);
}
/**
* @notice Initializes the debt allocator.
* @dev Should be called atomically after cloning.
* @param _vault Address of the vault this allocates debt for.
* @param _minimumChange The minimum in asset that must be moved.
*/
function initialize(address _vault, uint256 _minimumChange) public virtual {
require(address(vault) == address(0), "!initialized");
// Set initial variables.
vault = _vault;
minimumChange = _minimumChange;
// Default max loss on debt updates to 1 BP.
maxDebtUpdateLoss = 1;
}
/**
* @notice Debt update wrapper for the vault.
* @dev This can be used if a minimum time between debt updates
* is desired to be used for the trigger and to enforce a max loss.
*
* This contract must have the DEBT_MANAGER role assigned to them.
*
* The function signature matches the vault so no update to the
* call data is required.
*
* This will also run checks on losses realized during debt
* updates to assure decreases did not realize profits outside
* of the allowed range.
*/
function update_debt(
address _strategy,
uint256 _targetDebt
) public virtual onlyKeepers {
IVault _vault = IVault(vault);
// If going to 0 record full balance first.
if (_targetDebt == 0) {
_vault.process_report(_strategy);
}
// Update debt with the default max loss.
_vault.update_debt(_strategy, _targetDebt, maxDebtUpdateLoss);
// Update the last time the strategies debt was updated.
_configs[_strategy].lastUpdate = uint96(block.timestamp);
}
/**
* @notice Check if a strategy's debt should be updated.
* @dev This should be called by a keeper to decide if a strategies
* debt should be updated and if so by how much.
*
* @param _strategy Address of the strategy to check.
* @return . Bool representing if the debt should be updated.
* @return . Calldata if `true` or reason if `false`.
*/
function shouldUpdateDebt(
address _strategy
) public view virtual returns (bool, bytes memory) {
// Get the strategy specific debt config.
Config memory config = getConfig(_strategy);
// Make sure the strategy has been added to the allocator.
if (!config.added) return (false, bytes("!added"));
// Check the base fee isn't too high.
if (!DebtAllocatorFactory(factory).isCurrentBaseFeeAcceptable()) {
return (false, bytes("Base Fee"));
}
// Cache the vault variable.
IVault _vault = IVault(vault);
// Retrieve the strategy specific parameters.
IVault.StrategyParams memory params = _vault.strategies(_strategy);
// Make sure its an active strategy.
require(params.activation != 0, "!active");
if (block.timestamp - config.lastUpdate <= minimumWait) {
return (false, bytes("min wait"));
}
uint256 vaultAssets = _vault.totalAssets();
// Get the target debt for the strategy based on vault assets.
uint256 targetDebt = Math.min(
(vaultAssets * config.targetRatio) / MAX_BPS,
// Make sure it is not more than the max allowed.
params.max_debt
);
// Get the max debt we would want the strategy to have.
uint256 maxDebt = Math.min(
(vaultAssets * config.maxRatio) / MAX_BPS,
// Make sure it is not more than the max allowed.
params.max_debt
);
// If we need to add more.
if (targetDebt > params.current_debt) {
uint256 currentIdle = _vault.totalIdle();
uint256 minIdle = _vault.minimum_total_idle();
// We can't add more than the available idle.
if (minIdle >= currentIdle) {
return (false, bytes("No Idle"));
}
// Add up to the max if possible
uint256 toAdd = Math.min(
maxDebt - params.current_debt,
// Can't take more than is available.
Math.min(
currentIdle - minIdle,
IVault(_strategy).maxDeposit(vault)
)
);
// If the amount to add is over our threshold.
if (toAdd > minimumChange) {
// Return true and the calldata.
return (
true,
abi.encodeWithSignature(
"update_debt(address,uint256)",
_strategy,
params.current_debt + toAdd
)
);
}
// If current debt is greater than our max.
} else if (maxDebt < params.current_debt) {
uint256 toPull = params.current_debt - targetDebt;
uint256 currentIdle = _vault.totalIdle();
uint256 minIdle = _vault.minimum_total_idle();
if (minIdle > currentIdle) {
// Pull at least the amount needed for minIdle.
toPull = Math.max(toPull, minIdle - currentIdle);
}
// Find out by how much. Aim for the target.
toPull = Math.min(
toPull,
// Account for the current liquidity constraints.
// Use max redeem to match vault logic.
IVault(_strategy).convertToAssets(
IVault(_strategy).maxRedeem(address(_vault))
)
);
// Check if it's over the threshold.
if (toPull > minimumChange) {
// Can't lower debt if there are unrealised losses.
if (
_vault.assess_share_of_unrealised_losses(
_strategy,
params.current_debt
) != 0
) {
return (false, bytes("unrealised loss"));
}
// If so return true and the calldata.
return (
true,
abi.encodeWithSignature(
"update_debt(address,uint256)",
_strategy,
params.current_debt - toPull
)
);
}
}
// Either no change or below our minimumChange.
return (false, bytes("Below Min"));
}
/**
* @notice Increase a strategies target debt ratio.
* @dev `setStrategyDebtRatio` functions will do all needed checks.
* @param _strategy The address of the strategy to increase the debt ratio for.
* @param _increase The amount in Basis Points to increase it.
*/
function increaseStrategyDebtRatio(
address _strategy,
uint256 _increase
) external virtual {
uint256 _currentRatio = getConfig(_strategy).targetRatio;
setStrategyDebtRatio(_strategy, _currentRatio + _increase);
}
/**
* @notice Decrease a strategies target debt ratio.
* @param _strategy The address of the strategy to decrease the debt ratio for.
* @param _decrease The amount in Basis Points to decrease it.
*/
function decreaseStrategyDebtRatio(
address _strategy,
uint256 _decrease
) external virtual {
uint256 _currentRatio = getConfig(_strategy).targetRatio;
setStrategyDebtRatio(_strategy, _currentRatio - _decrease);
}
/**
* @notice Sets a new target debt ratio for a strategy.
* @dev This will default to a 20% increase for max debt.
*
* @param _strategy Address of the strategy to set.
* @param _targetRatio Amount in Basis points to allocate.
*/
function setStrategyDebtRatio(
address _strategy,
uint256 _targetRatio
) public virtual {
uint256 maxRatio = Math.min((_targetRatio * 12_000) / MAX_BPS, MAX_BPS);
setStrategyDebtRatio(_strategy, _targetRatio, maxRatio);
}
/**
* @notice Sets a new target debt ratio for a strategy.
* @dev A `minimumChange` for that strategy must be set first.
* This is to prevent debt from being updated too frequently.
*
* @param _strategy Address of the strategy to set.
* @param _targetRatio Amount in Basis points to allocate.
* @param _maxRatio Max ratio to give on debt increases.
*/
function setStrategyDebtRatio(
address _strategy,
uint256 _targetRatio,
uint256 _maxRatio
) public virtual onlyManagers {
// Make sure a minimumChange has been set.
require(minimumChange != 0, "!minimum");
// Cannot be more than 100%.
require(_maxRatio <= MAX_BPS, "max too high");
// Max cannot be lower than the target.
require(_maxRatio >= _targetRatio, "max ratio");
// Get the current config.
Config memory config = getConfig(_strategy);
// Set added flag if not set yet.
if (!config.added) {
config.added = true;
emit StrategyChanged(_strategy, Status.ADDED);
}
// Get what will be the new total debt ratio.
uint256 newTotalDebtRatio = totalDebtRatio -
config.targetRatio +
_targetRatio;
// Make sure it is under 100% allocated
require(newTotalDebtRatio <= MAX_BPS, "ratio too high");
// Update local config.
config.targetRatio = uint16(_targetRatio);
config.maxRatio = uint16(_maxRatio);
// Write to storage.
_configs[_strategy] = config;
totalDebtRatio = newTotalDebtRatio;
emit UpdateStrategyDebtRatio(
_strategy,
_targetRatio,
_maxRatio,
newTotalDebtRatio
);
}
/**
* @notice Remove a strategy from this debt allocator.
* @dev Will delete the full config for the strategy
* @param _strategy Address of the address ro remove.
*/
function removeStrategy(address _strategy) external virtual onlyManagers {
Config memory config = getConfig(_strategy);
require(config.added, "!added");
uint256 target = config.targetRatio;
// Remove any debt ratio the strategy holds.
if (target != 0) {
totalDebtRatio -= target;
emit UpdateStrategyDebtRatio(_strategy, 0, 0, totalDebtRatio);
}
// Remove the full config including the `added` flag.
delete _configs[_strategy];
// Emit Event.
emit StrategyChanged(_strategy, Status.REMOVED);
}
/**
* @notice Set the minimum change variable for a strategy.
* @dev This is the minimum amount of debt to be
* added or pulled for it to trigger an update.
*
* @param _minimumChange The new minimum to set for the strategy.
*/
function setMinimumChange(
uint256 _minimumChange
) external virtual onlyGovernance {
require(_minimumChange > 0, "zero");
// Set the new minimum.
minimumChange = _minimumChange;
emit UpdateMinimumChange(_minimumChange);
}
/**
* @notice Set the max loss in Basis points to allow on debt updates.
* @dev Withdrawing during debt updates use {redeem} which allows for 100% loss.
* This can be used to assure a loss is not realized on redeem outside the tolerance.
* @param _maxDebtUpdateLoss The max loss to accept on debt updates.
*/
function setMaxDebtUpdateLoss(
uint256 _maxDebtUpdateLoss
) external virtual onlyGovernance {
require(_maxDebtUpdateLoss <= MAX_BPS, "higher than max");
maxDebtUpdateLoss = _maxDebtUpdateLoss;
emit UpdateMaxDebtUpdateLoss(_maxDebtUpdateLoss);
}
/**
* @notice Set the minimum time to wait before re-updating a strategies debt.
* @dev This is only enforced per strategy.
* @param _minimumWait The minimum time in seconds to wait.
*/
function setMinimumWait(
uint256 _minimumWait
) external virtual onlyGovernance {
minimumWait = _minimumWait;
emit UpdateMinimumWait(_minimumWait);
}
/**
* @notice Set if a manager can update ratios.
* @param _address The address to set mapping for.
* @param _allowed If the address can call {update_debt}.
*/
function setManager(
address _address,
bool _allowed
) external virtual onlyGovernance {
managers[_address] = _allowed;
emit UpdateManager(_address, _allowed);
}
/**
* @notice Get a strategies full config.
* @dev Used for customizations by inheriting the contract.
* @param _strategy Address of the strategy.
* @return The strategies current Config.
*/
function getConfig(
address _strategy
) public view virtual returns (Config memory) {
return _configs[_strategy];
}
/**
* @notice Get a strategies target debt ratio.
* @param _strategy Address of the strategy.
* @return The strategies current targetRatio.
*/
function getStrategyTargetRatio(
address _strategy
) external view virtual returns (uint256) {
return getConfig(_strategy).targetRatio;
}
/**
* @notice Get a strategies max debt ratio.
* @param _strategy Address of the strategy.
* @return The strategies current maxRatio.
*/
function getStrategyMaxRatio(
address _strategy
) external view virtual returns (uint256) {
return getConfig(_strategy).maxRatio;
}
}
contract Clonable {
/// @notice Set to the address to auto clone from.
address public original;
/**
* @notice Clone the contracts default `original` contract.
* @return Address of the new Minimal Proxy clone.
*/
function _clone() internal virtual returns (address) {
return _clone(original);
}
/**
* @notice Clone any `_original` contract.
* @return _newContract Address of the new Minimal Proxy clone.
*/
function _clone(
address _original
) internal virtual returns (address _newContract) {
// Copied from https://github.com/optionality/clone-factory/blob/master/contracts/CloneFactory.sol
bytes20 addressBytes = bytes20(_original);
assembly {
// EIP-1167 bytecode
let clone_code := mload(0x40)
mstore(
clone_code,
0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000
)
mstore(add(clone_code, 0x14), addressBytes)
mstore(
add(clone_code, 0x28),
0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000
)
_newContract := create(0, clone_code, 0x37)
}
}
}
interface IBaseFee {
function basefee_global() external view returns (uint256);
}
/**
* @title YearnV3 Debt Allocator Factory
* @author yearn.finance
* @notice
* Factory to deploy a debt allocator for a YearnV3 vault.
*/
contract DebtAllocatorFactory is Governance, Clonable {
/// @notice Revert message for when a debt allocator already exists.
error AlreadyDeployed(address _allocator);
/// @notice An event emitted when the base fee provider is set.
event UpdatedBaseFeeProvider(address baseFeeProvider);
/// @notice An event emitted when a keeper is added or removed.
event UpdateKeeper(address indexed keeper, bool allowed);
/// @notice An event emitted when the max base fee is updated.
event UpdateMaxAcceptableBaseFee(uint256 newMaxAcceptableBaseFee);
/// @notice An event emitted when a new debt allocator is added or deployed.
event NewDebtAllocator(address indexed allocator, address indexed vault);
/// @notice Provider to read current block's base fee.
address public baseFeeProvider;
/// @notice Max the chains base fee can be during debt update.
// Will default to max uint256 and need to be set to be used.
uint256 public maxAcceptableBaseFee;
/// @notice Mapping of addresses that are allowed to update debt.
mapping(address => bool) public keepers;
constructor(address _governance) Governance(_governance) {
// Deploy a dummy allocator as the original.
original = address(new DebtAllocator());
// Default max base fee to uint max.
maxAcceptableBaseFee = type(uint256).max;
// Default to allow governance to be a keeper.
keepers[_governance] = true;
emit UpdateKeeper(_governance, true);
}
/**
* @notice Clones a new debt allocator.
* @dev defaults to msg.sender as the governance role and 0
* for the `minimumChange`.
*
* @param _vault The vault for the allocator to be hooked to.
* @return Address of the new debt allocator
*/
function newDebtAllocator(
address _vault
) external virtual returns (address) {
return newDebtAllocator(_vault, 0);
}
/**
* @notice Clones a new debt allocator.
* @param _vault The vault for the allocator to be hooked to.
* @param _minimumChange The minimum amount needed to trigger debt update.
* @return newAllocator Address of the new debt allocator
*/
function newDebtAllocator(
address _vault,
uint256 _minimumChange
) public virtual returns (address newAllocator) {
// Clone new allocator off the original.
newAllocator = _clone();
// Initialize the new allocator.
DebtAllocator(newAllocator).initialize(_vault, _minimumChange);
// Emit event.
emit NewDebtAllocator(newAllocator, _vault);
}
/**
* @notice
* Used to set our baseFeeProvider, which checks the network's current base
* fee price to determine whether it is an optimal time to harvest or tend.
*
* This may only be called by governance.
* @param _baseFeeProvider Address of our baseFeeProvider
*/
function setBaseFeeOracle(
address _baseFeeProvider
) external virtual onlyGovernance {
baseFeeProvider = _baseFeeProvider;
emit UpdatedBaseFeeProvider(_baseFeeProvider);
}
/**
* @notice Set the max acceptable base fee.
* @dev This defaults to max uint256 and will need to
* be set for it to be used.
*
* Is denominated in gwei. So 50gwei would be set as 50e9.
*
* @param _maxAcceptableBaseFee The new max base fee.
*/
function setMaxAcceptableBaseFee(
uint256 _maxAcceptableBaseFee
) external virtual onlyGovernance {
maxAcceptableBaseFee = _maxAcceptableBaseFee;
emit UpdateMaxAcceptableBaseFee(_maxAcceptableBaseFee);
}
/**
* @notice Set if a keeper can update debt.
* @param _address The address to set mapping for.
* @param _allowed If the address can call {update_debt}.
*/
function setKeeper(
address _address,
bool _allowed
) external virtual onlyGovernance {
keepers[_address] = _allowed;
emit UpdateKeeper(_address, _allowed);
}
/**
* @notice Returns wether or not the current base fee is acceptable
* based on the `maxAcceptableBaseFee`.
* @return . If the current base fee is acceptable.
*/
function isCurrentBaseFeeAcceptable() external view virtual returns (bool) {
address _baseFeeProvider = baseFeeProvider;
if (_baseFeeProvider == address(0)) return true;
return
maxAcceptableBaseFee >= IBaseFee(_baseFeeProvider).basefee_global();
}
}
/// @title Yearn V3 Vault Role Manager.
contract RoleManager is Governance2Step {
/// @notice Revert message for when a vault has already been deployed.
error AlreadyDeployed(address _vault);
/// @notice Emitted when a new vault has been deployed or added.
event AddedNewVault(
address indexed vault,
address indexed debtAllocator,
uint256 category
);
/// @notice Emitted when a vaults debt allocator is updated.
event UpdateDebtAllocator(
address indexed vault,
address indexed debtAllocator
);
/// @notice Emitted when a new address is set for a position.
event UpdatePositionHolder(
bytes32 indexed position,
address indexed newAddress
);
/// @notice Emitted when a vault is removed.
event RemovedVault(address indexed vault);
/// @notice Emitted when a new set of roles is set for a position
event UpdatePositionRoles(bytes32 indexed position, uint256 newRoles);
/// @notice Emitted when the defaultProfitMaxUnlock variable is updated.
event UpdateDefaultProfitMaxUnlock(uint256 newDefaultProfitMaxUnlock);
/// @notice Position struct
struct Position {
address holder;
uint96 roles;
}
/// @notice Config that holds all vault info.
struct VaultConfig {
address asset;
uint256 category;
address debtAllocator;
uint256 index;
}
/// @notice Only allow either governance or the position holder to call.
modifier onlyPositionHolder(bytes32 _positionId) {
_isPositionHolder(_positionId);
_;
}
/// @notice Check if the msg sender is governance or the specified position holder.
function _isPositionHolder(bytes32 _positionId) internal view virtual {
require(
msg.sender == governance ||
msg.sender == getPositionHolder(_positionId),
"!allowed"
);
}
// Encoded name so that it can be held as a constant.
bytes32 internal constant _name_ =
bytes32(abi.encodePacked("Yearn V3 Vault Role Manager"));
/*//////////////////////////////////////////////////////////////
POSITION ID'S
//////////////////////////////////////////////////////////////*/
/// @notice Position ID for "daddy".
bytes32 public constant DADDY = keccak256("Daddy");
/// @notice Position ID for "brain".
bytes32 public constant BRAIN = keccak256("Brain");
/// @notice Position ID for "keeper".
bytes32 public constant KEEPER = keccak256("Keeper");
/// @notice Position ID for "security".
bytes32 public constant SECURITY = keccak256("Security");
/// @notice Position ID for the Registry.
bytes32 public constant REGISTRY = keccak256("Registry");
/// @notice Position ID for the Accountant.
bytes32 public constant ACCOUNTANT = keccak256("Accountant");
/// @notice Position ID for Debt Allocator
bytes32 public constant DEBT_ALLOCATOR = keccak256("Debt Allocator");
/// @notice Position ID for Strategy manager.
bytes32 public constant STRATEGY_MANAGER = keccak256("Strategy Manager");
/// @notice Position ID for the Allocator Factory.
bytes32 public constant ALLOCATOR_FACTORY = keccak256("Allocator Factory");
/// @notice Immutable address that the RoleManager position
// will be transferred to when a vault is removed.
address public immutable chad;
/*//////////////////////////////////////////////////////////////
STORAGE
//////////////////////////////////////////////////////////////*/
/// @notice Array storing addresses of all managed vaults.
address[] public vaults;
/// @notice Default time until profits are fully unlocked for new vaults.
uint256 public defaultProfitMaxUnlock = 10 days;
/// @notice Mapping of position ID to position information.
mapping(bytes32 => Position) internal _positions;
/// @notice Mapping of vault addresses to its config.
mapping(address => VaultConfig) public vaultConfig;
/// @notice Mapping of underlying asset, api version and category to vault.
mapping(address => mapping(string => mapping(uint256 => address)))
internal _assetToVault;
constructor(
address _governance,
address _daddy,
address _brain,
address _security,
address _keeper,
address _strategyManager,
address _registry
) Governance2Step(_governance) {
require(_daddy != address(0), "ZERO ADDRESS");
// Set the immutable address that will take over role manager
// if a vault is removed.
chad = _daddy;
// Set up the initial role configs for each position.
// Daddy is given all of the roles.
_positions[DADDY] = Position({
holder: _daddy,
roles: uint96(Roles.ALL)
});
// Setup default roles for Brain.
_positions[BRAIN] = Position({
holder: _brain,
roles: uint96(
Roles.REPORTING_MANAGER |
Roles.DEBT_MANAGER |
Roles.QUEUE_MANAGER |
Roles.DEPOSIT_LIMIT_MANAGER |
Roles.DEBT_PURCHASER
)
});
// Security can set the max debt for strategies to have.
_positions[SECURITY] = Position({
holder: _security,
roles: uint96(Roles.MAX_DEBT_MANAGER)
});
// The keeper can process reports.
_positions[KEEPER] = Position({
holder: _keeper,
roles: uint96(Roles.REPORTING_MANAGER)
});
// Debt allocators manage debt and also need to process reports.
_positions[DEBT_ALLOCATOR].roles = uint96(
Roles.REPORTING_MANAGER | Roles.DEBT_MANAGER
);
// The strategy manager can add and remove strategies.
_positions[STRATEGY_MANAGER] = Position({
holder: _strategyManager,
roles: uint96(
Roles.ADD_STRATEGY_MANAGER | Roles.REVOKE_STRATEGY_MANAGER
)
});
// Set the registry
_positions[REGISTRY].holder = _registry;
}
/*//////////////////////////////////////////////////////////////
VAULT CREATION
//////////////////////////////////////////////////////////////*/
/**
* @notice Creates a new endorsed vault with default profit max
* unlock time and doesn't set the deposit limit.
* @param _asset Address of the underlying asset.
* @param _category Category of the vault.
* @return _vault Address of the newly created vault.
*/
function newVault(
address _asset,
uint256 _category
) external virtual onlyPositionHolder(DADDY) returns (address) {
return _newVault(_asset, _category, 0, defaultProfitMaxUnlock);
}
/**
* @notice Creates a new endorsed vault with default profit max unlock time.
* @param _asset Address of the underlying asset.
* @param _category Category of the vault.
* @param _depositLimit The deposit limit to start the vault with.
* @return _vault Address of the newly created vault.
*/
function newVault(
address _asset,
uint256 _category,
uint256 _depositLimit
) external virtual onlyPositionHolder(DADDY) returns (address) {
return
_newVault(_asset, _category, _depositLimit, defaultProfitMaxUnlock);
}
/**
* @notice Creates a new endorsed vault.
* @param _asset Address of the underlying asset.
* @param _category Category of the vault.
* @param _depositLimit The deposit limit to start the vault with.
* @param _profitMaxUnlockTime Time until profits are fully unlocked.
* @return _vault Address of the newly created vault.
*/
function newVault(
address _asset,
uint256 _category,
uint256 _depositLimit,
uint256 _profitMaxUnlockTime
) external virtual onlyPositionHolder(DADDY) returns (address) {
return
_newVault(_asset, _category, _depositLimit, _profitMaxUnlockTime);
}
/**
* @notice Creates a new endorsed vault.
* @param _asset Address of the underlying asset.
* @param _category Category of the vault.
* @param _depositLimit The deposit limit to start the vault with.
* @param _profitMaxUnlockTime Time until profits are fully unlocked.
* @return _vault Address of the newly created vault.
*/
function _newVault(
address _asset,
uint256 _category,
uint256 _depositLimit,
uint256 _profitMaxUnlockTime
) internal virtual returns (address _vault) {
string memory _categoryString = Strings.toString(_category);
// Name is "{SYMBOL}-{CATEGORY} yVault"
string memory _name = string(
abi.encodePacked(
ERC20(_asset).symbol(),
"-",
_categoryString,
" yVault"
)
);
// Symbol is "yv{SYMBOL}-{CATEGORY}".
string memory _symbol = string(
abi.encodePacked("yv", ERC20(_asset).symbol(), "-", _categoryString)
);
// Deploy through the registry so it is automatically endorsed.
_vault = Registry(getPositionHolder(REGISTRY)).newEndorsedVault(
_asset,
_name,
_symbol,
address(this),
_profitMaxUnlockTime
);
// Check that a vault does not exist for that asset, api and category.
// This reverts late to not waste gas when used correctly.
string memory _apiVersion = IVault(_vault).apiVersion();
if (_assetToVault[_asset][_apiVersion][_category] != address(0))
revert AlreadyDeployed(
_assetToVault[_asset][_apiVersion][_category]
);
// Deploy a new debt allocator for the vault.
address _debtAllocator = _deployAllocator(_vault);
// Give out roles on the new vault.
_sanctify(_vault, _debtAllocator);
// Set up the accountant.
_setAccountant(_vault);
if (_depositLimit != 0) {
_setDepositLimit(_vault, _depositLimit);
}
// Add the vault config to the mapping.
vaultConfig[_vault] = VaultConfig({
asset: _asset,
category: _category,
debtAllocator: _debtAllocator,
index: vaults.length
});
// Add the vault to the mapping.
_assetToVault[_asset][_apiVersion][_category] = _vault;
// Add the vault to the array.
vaults.push(_vault);
// Emit event for new vault.
emit AddedNewVault(_vault, _debtAllocator, _category);
}
/**
* @dev Deploys a debt allocator for the specified vault.
* @param _vault Address of the vault.
* @return _debtAllocator Address of the deployed debt allocator.
*/
function _deployAllocator(
address _vault
) internal virtual returns (address _debtAllocator) {
address factory = getPositionHolder(ALLOCATOR_FACTORY);
// If we have a factory set.
if (factory != address(0)) {
// Deploy a new debt allocator for the vault with Brain as the gov.
_debtAllocator = DebtAllocatorFactory(factory).newDebtAllocator(
_vault
);
} else {
// If no factory is set we should be using one central allocator.
_debtAllocator = getPositionHolder(DEBT_ALLOCATOR);
}
}
/**
* @dev Assigns roles to the newly added vault.
*
* This will override any previously set roles for the holders. But not effect
* the roles held by other addresses.
*
* @param _vault Address of the vault to sanctify.
* @param _debtAllocator Address of the debt allocator for the vault.
*/
function _sanctify(
address _vault,
address _debtAllocator
) internal virtual {
// Set the roles for daddy.
_setRole(_vault, _positions[DADDY]);
// Set the roles for Brain.
_setRole(_vault, _positions[BRAIN]);
// Set the roles for Security.
_setRole(_vault, _positions[SECURITY]);
// Set the roles for the Keeper.
_setRole(_vault, _positions[KEEPER]);
// Set the roles for the Strategy Manager.
_setRole(_vault, _positions[STRATEGY_MANAGER]);
// Give the specific debt allocator its roles.
_setRole(
_vault,
Position(_debtAllocator, _positions[DEBT_ALLOCATOR].roles)
);
}
/**
* @dev Used internally to set the roles on a vault for a given position.
* Will not set the roles if the position holder is address(0).
* This does not check that the roles are !=0 because it is expected that
* the holder will be set to 0 if the position is not being used.
*
* @param _vault Address of the vault.
* @param _position Holder address and roles to set.
*/
function _setRole(
address _vault,
Position memory _position
) internal virtual {
if (_position.holder != address(0)) {
IVault(_vault).set_role(_position.holder, uint256(_position.roles));
}
}
/**
* @dev Sets the accountant on the vault and adds the vault to the accountant.
* This temporarily gives the `ACCOUNTANT_MANAGER` role to this contract.
* @param _vault Address of the vault to set up the accountant for.
*/
function _setAccountant(address _vault) internal virtual {
// Get the current accountant.
address accountant = getPositionHolder(ACCOUNTANT);
// If there is an accountant set.
if (accountant != address(0)) {
// Temporarily give this contract the ability to set the accountant.
IVault(_vault).add_role(address(this), Roles.ACCOUNTANT_MANAGER);
// Set the account on the vault.
IVault(_vault).set_accountant(accountant);
// Take away the role.
IVault(_vault).remove_role(address(this), Roles.ACCOUNTANT_MANAGER);
// Whitelist the vault in the accountant.
Accountant(accountant).addVault(_vault);
}
}
/**
* @dev Used to set an initial deposit limit when a new vault is deployed.
* Any further updates to the limit will need to be done by an address that
* holds the `DEPOSIT_LIMIT_MANAGER` role.
* @param _vault Address of the newly deployed vault.
* @param _depositLimit The deposit limit to set.
*/
function _setDepositLimit(
address _vault,
uint256 _depositLimit
) internal virtual {
// Temporarily give this contract the ability to set the deposit limit.
IVault(_vault).add_role(address(this), Roles.DEPOSIT_LIMIT_MANAGER);
// Set the initial deposit limit on the vault.
IVault(_vault).set_deposit_limit(_depositLimit);
// Take away the role.
IVault(_vault).remove_role(address(this), Roles.DEPOSIT_LIMIT_MANAGER);
}
/*//////////////////////////////////////////////////////////////
VAULT MANAGEMENT
//////////////////////////////////////////////////////////////*/
/**
* @notice Adds a new vault to the RoleManager with the specified category.
* @dev If not already endorsed this function will endorse the vault.
* A new debt allocator will be deployed and configured.
* @param _vault Address of the vault to be added.
* @param _category Category associated with the vault.
*/
function addNewVault(address _vault, uint256 _category) external virtual {
address _debtAllocator = _deployAllocator(_vault);
addNewVault(_vault, _category, _debtAllocator);
}
/**
* @notice Adds a new vault to the RoleManager with the specified category and debt allocator.
* @dev If not already endorsed this function will endorse the vault.
* @param _vault Address of the vault to be added.
* @param _category Category associated with the vault.
* @param _debtAllocator Address of the debt allocator for the vault.
*/
function addNewVault(
address _vault,
uint256 _category,
address _debtAllocator
) public virtual onlyPositionHolder(DADDY) {
// Check that a vault does not exist for that asset, api and category.
address _asset = IVault(_vault).asset();
string memory _apiVersion = IVault(_vault).apiVersion();
if (_assetToVault[_asset][_apiVersion][_category] != address(0))
revert AlreadyDeployed(
_assetToVault[_asset][_apiVersion][_category]
);
// If not the current role manager.
if (IVault(_vault).role_manager() != address(this)) {
// Accept the position of role manager.
IVault(_vault).accept_role_manager();
}
// Get the current registry.
address registry = getPositionHolder(REGISTRY);
// Check if the vault has been endorsed yet in the registry.
if (!Registry(registry).isEndorsed(_vault)) {
// If not endorse it.
// NOTE: This will revert if adding a vault of an older version.
Registry(registry).endorseMultiStrategyVault(_vault);
}
// Set the roles up.
_sanctify(_vault, _debtAllocator);
// Only set an accountant if there is not one set yet.
if (IVault(_vault).accountant() == address(0)) {
_setAccountant(_vault);
}
// Add the vault config to the mapping.
vaultConfig[_vault] = VaultConfig({
asset: _asset,
category: _category,
debtAllocator: _debtAllocator,
index: vaults.length
});
// Add the vault to the mapping.
_assetToVault[_asset][_apiVersion][_category] = _vault;
// Add the vault to the array.
vaults.push(_vault);
// Emit event.
emit AddedNewVault(_vault, _debtAllocator, _category);
}
/**
* @notice Update a `_vault`s debt allocator.
* @dev This will deploy a new allocator using the current
* allocator factory set.
* @param _vault Address of the vault to update the allocator for.
*/
function updateDebtAllocator(
address _vault
) external virtual returns (address _newDebtAllocator) {
_newDebtAllocator = _deployAllocator(_vault);
updateDebtAllocator(_vault, _newDebtAllocator);
}
/**
* @notice Update a `_vault`s debt allocator to a specified `_debtAllocator`.
* @param _vault Address of the vault to update the allocator for.
* @param _debtAllocator Address of the new debt allocator.
*/
function updateDebtAllocator(
address _vault,
address _debtAllocator
) public virtual onlyPositionHolder(BRAIN) {
// Make sure the vault has been added to the role manager.
require(vaultConfig[_vault].asset != address(0), "vault not added");
// Remove the roles from the old allocator.
_setRole(_vault, Position(vaultConfig[_vault].debtAllocator, 0));
// Give the new debt allocator the relevant roles.
_setRole(
_vault,
Position(_debtAllocator, _positions[DEBT_ALLOCATOR].roles)
);
// Update the vaults config.
vaultConfig[_vault].debtAllocator = _debtAllocator;
// Emit event.
emit UpdateDebtAllocator(_vault, _debtAllocator);
}
/**
* @notice Update a `_vault`s keeper to a specified `_keeper`.
* @param _vault Address of the vault to update the keeper for.
* @param _keeper Address of the new keeper.
*/
function updateKeeper(
address _vault,
address _keeper
) external virtual onlyPositionHolder(BRAIN) {
// Make sure the vault has been added to the role manager.
require(vaultConfig[_vault].asset != address(0), "vault not added");
// Remove the roles from the old keeper if active.
address defaultKeeper = getPositionHolder(KEEPER);
if (
_keeper != defaultKeeper && IVault(_vault).roles(defaultKeeper) != 0
) {
_setRole(_vault, Position(defaultKeeper, 0));
}
// Give the new keeper the relevant roles.
_setRole(_vault, Position(_keeper, _positions[KEEPER].roles));
}
/**
* @notice Removes a vault from the RoleManager.
* @dev This will NOT un-endorse the vault from the registry.
* @param _vault Address of the vault to be removed.
*/
function removeVault(
address _vault
) external virtual onlyPositionHolder(BRAIN) {
// Get the vault specific config.
VaultConfig memory config = vaultConfig[_vault];
// Make sure the vault has been added to the role manager.
require(config.asset != address(0), "vault not added");
// Transfer the role manager position.
IVault(_vault).transfer_role_manager(chad);
// Address of the vault to replace it with.
address vaultToMove = vaults[vaults.length - 1];
// Move the last vault to the index of `_vault`
vaults[config.index] = vaultToMove;
vaultConfig[vaultToMove].index = config.index;
// Remove the last item.
vaults.pop();
// Delete the vault from the mapping.
delete _assetToVault[config.asset][IVault(_vault).apiVersion()][
config.category
];
// Delete the config for `_vault`.
delete vaultConfig[_vault];
emit RemovedVault(_vault);
}
/**
* @notice Removes a specific role(s) for a `_holder` from the `_vaults`.
* @dev Can be used to remove one specific role or multiple.
* @param _vaults Array of vaults to adjust.
* @param _holder Address who's having a role removed.
* @param _role The role or roles to remove from the `_holder`.
*/
function removeRoles(
address[] calldata _vaults,
address _holder,
uint256 _role
) external virtual onlyGovernance {
address _vault;
for (uint256 i = 0; i < _vaults.length; ++i) {
_vault = _vaults[i];
// Make sure the vault is added to this Role Manager.
require(vaultConfig[_vault].asset != address(0), "vault not added");
// Remove the role.
IVault(_vault).remove_role(_holder, _role);
}
}
/*//////////////////////////////////////////////////////////////
SETTERS
//////////////////////////////////////////////////////////////*/
/**
* @notice Setter function for updating a positions roles.
* @param _position Identifier for the position.
* @param _newRoles New roles for the position.
*/
function setPositionRoles(
bytes32 _position,
uint256 _newRoles
) external virtual onlyGovernance {
// Cannot change the debt allocator or keeper roles since holder can be updated.
require(
_position != DEBT_ALLOCATOR && _position != KEEPER,
"cannot update"
);
_positions[_position].roles = uint96(_newRoles);
emit UpdatePositionRoles(_position, _newRoles);
}
/**
* @notice Setter function for updating a positions holder.
* @param _position Identifier for the position.
* @param _newHolder New address for position.
*/
function setPositionHolder(
bytes32 _position,
address _newHolder
) external virtual onlyGovernance {
_positions[_position].holder = _newHolder;
emit UpdatePositionHolder(_position, _newHolder);
}
/**
* @notice Sets the default time until profits are fully unlocked for new vaults.
* @param _newDefaultProfitMaxUnlock New value for defaultProfitMaxUnlock.
*/
function setDefaultProfitMaxUnlock(
uint256 _newDefaultProfitMaxUnlock
) external virtual onlyGovernance {
defaultProfitMaxUnlock = _newDefaultProfitMaxUnlock;
emit UpdateDefaultProfitMaxUnlock(_newDefaultProfitMaxUnlock);
}
/*//////////////////////////////////////////////////////////////
VIEW METHODS
//////////////////////////////////////////////////////////////*/
/**
* @notice Get the name of this contract.
*/
function name() external view virtual returns (string memory) {
return string(abi.encodePacked(_name_));
}
/**
* @notice Get all vaults that this role manager controls..
* @return The full array of vault addresses.
*/
function getAllVaults() external view virtual returns (address[] memory) {
return vaults;
}
/**
* @notice Get the vault for a specific asset, api and category.
* @dev This will return address(0) if one has not been added or deployed.
*
* @param _asset The underlying asset used.
* @param _apiVersion The version of the vault.
* @param _category The category of the vault.
* @return The vault for the specified `_asset`, `_apiVersion` and `_category`.
*/
function getVault(
address _asset,
string memory _apiVersion,
uint256 _category
) external view virtual returns (address) {
return _assetToVault[_asset][_apiVersion][_category];
}
/**
* @notice Check if a vault is managed by this contract.
* @dev This will check if the `asset` variable in the struct has been
* set for an easy external view check.
*
* Does not check the vaults `role_manager` position since that can be set
* by anyone for a random vault.
*
* @param _vault Address of the vault to check.
* @return . The vaults role manager status.
*/
function isVaultsRoleManager(
address _vault
) external view virtual returns (bool) {
return vaultConfig[_vault].asset != address(0);
}
/**
* @notice Get the debt allocator for a specific vault.
* @dev Will return address(0) if the vault is not managed by this contract.
* @param _vault Address of the vault.
* @return . Address of the debt allocator if any.
*/
function getDebtAllocator(
address _vault
) external view virtual returns (address) {
return vaultConfig[_vault].debtAllocator;
}
/**
* @notice Get the category for a specific vault.
* @dev Will return 0 if the vault is not managed by this contract.
* @param _vault Address of the vault.
* @return . The category of the vault if any.
*/
function getCategory(
address _vault
) external view virtual returns (uint256) {
return vaultConfig[_vault].category;
}
/**
* @notice Get the address and roles given to a specific position.
* @param _positionId The position identifier.
* @return The address that holds that position.
* @return The roles given to the specified position.
*/
function getPosition(
bytes32 _positionId
) public view virtual returns (address, uint256) {
Position memory _position = _positions[_positionId];
return (_position.holder, uint256(_position.roles));
}
/**
* @notice Get the current address assigned to a specific position.
* @param _positionId The position identifier.
* @return The current address assigned to the specified position.
*/
function getPositionHolder(
bytes32 _positionId
) public view virtual returns (address) {
return _positions[_positionId].holder;
}
/**
* @notice Get the current roles given to a specific position ID.
* @param _positionId The position identifier.
* @return The current roles given to the specified position ID.
*/
function getPositionRoles(
bytes32 _positionId
) public view virtual returns (uint256) {
return uint256(_positions[_positionId].roles);
}
/**
* @notice Get the address assigned to the Daddy position.
* @return The address assigned to the Daddy position.
*/
function getDaddy() external view virtual returns (address) {
return getPositionHolder(DADDY);
}
/**
* @notice Get the address assigned to the Brain position.
* @return The address assigned to the Brain position.
*/
function getBrain() external view virtual returns (address) {
return getPositionHolder(BRAIN);
}
/**
* @notice Get the address assigned to the Security position.
* @return The address assigned to the Security position.
*/
function getSecurity() external view virtual returns (address) {
return getPositionHolder(SECURITY);
}
/**
* @notice Get the address assigned to the Keeper position.
* @return The address assigned to the Keeper position.
*/
function getKeeper() external view virtual returns (address) {
return getPositionHolder(KEEPER);
}
/**
* @notice Get the address assigned to the strategy manager.
* @return The address assigned to the strategy manager.
*/
function getStrategyManager() external view virtual returns (address) {
return getPositionHolder(STRATEGY_MANAGER);
}
/**
* @notice Get the address assigned to the accountant.
* @return The address assigned to the accountant.
*/
function getAccountant() external view virtual returns (address) {
return getPositionHolder(ACCOUNTANT);
}
/**
* @notice Get the address assigned to the Registry.
* @return The address assigned to the Registry.
*/
function getRegistry() external view virtual returns (address) {
return getPositionHolder(REGISTRY);
}
/**
* @notice Get the address assigned to be the debt allocator if any.
* @return The address assigned to be the debt allocator if any.
*/
function getDebtAllocator() external view virtual returns (address) {
return getPositionHolder(DEBT_ALLOCATOR);
}
/**
* @notice Get the address assigned to the allocator factory.
* @return The address assigned to the allocator factory.
*/
function getAllocatorFactory() external view virtual returns (address) {
return getPositionHolder(ALLOCATOR_FACTORY);
}
/**
* @notice Get the roles given to the Daddy position.
* @return The roles given to the Daddy position.
*/
function getDaddyRoles() external view virtual returns (uint256) {
return getPositionRoles(DADDY);
}
/**
* @notice Get the roles given to the Brain position.
* @return The roles given to the Brain position.
*/
function getBrainRoles() external view virtual returns (uint256) {
return getPositionRoles(BRAIN);
}
/**
* @notice Get the roles given to the Security position.
* @return The roles given to the Security position.
*/
function getSecurityRoles() external view virtual returns (uint256) {
return getPositionRoles(SECURITY);
}
/**
* @notice Get the roles given to the Keeper position.
* @return The roles given to the Keeper position.
*/
function getKeeperRoles() external view virtual returns (uint256) {
return getPositionRoles(KEEPER);
}
/**
* @notice Get the roles given to the debt allocators.
* @return The roles given to the debt allocators.
*/
function getDebtAllocatorRoles() external view virtual returns (uint256) {
return getPositionRoles(DEBT_ALLOCATOR);
}
/**
* @notice Get the roles given to the strategy manager.
* @return The roles given to the strategy manager.
*/
function getStrategyManagerRoles() external view virtual returns (uint256) {
return getPositionRoles(STRATEGY_MANAGER);
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_governance","type":"address"},{"internalType":"address","name":"_daddy","type":"address"},{"internalType":"address","name":"_brain","type":"address"},{"internalType":"address","name":"_security","type":"address"},{"internalType":"address","name":"_keeper","type":"address"},{"internalType":"address","name":"_strategyManager","type":"address"},{"internalType":"address","name":"_registry","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"}],"name":"AlreadyDeployed","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"vault","type":"address"},{"indexed":true,"internalType":"address","name":"debtAllocator","type":"address"},{"indexed":false,"internalType":"uint256","name":"category","type":"uint256"}],"name":"AddedNewVault","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousGovernance","type":"address"},{"indexed":true,"internalType":"address","name":"newGovernance","type":"address"}],"name":"GovernanceTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"vault","type":"address"}],"name":"RemovedVault","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"vault","type":"address"},{"indexed":true,"internalType":"address","name":"debtAllocator","type":"address"}],"name":"UpdateDebtAllocator","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newDefaultProfitMaxUnlock","type":"uint256"}],"name":"UpdateDefaultProfitMaxUnlock","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newPendingGovernance","type":"address"}],"name":"UpdatePendingGovernance","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"position","type":"bytes32"},{"indexed":true,"internalType":"address","name":"newAddress","type":"address"}],"name":"UpdatePositionHolder","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"position","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"newRoles","type":"uint256"}],"name":"UpdatePositionRoles","type":"event"},{"inputs":[],"name":"ACCOUNTANT","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ALLOCATOR_FACTORY","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BRAIN","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DADDY","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEBT_ALLOCATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"KEEPER","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REGISTRY","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SECURITY","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STRATEGY_MANAGER","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptGovernance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"},{"internalType":"uint256","name":"_category","type":"uint256"},{"internalType":"address","name":"_debtAllocator","type":"address"}],"name":"addNewVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"},{"internalType":"uint256","name":"_category","type":"uint256"}],"name":"addNewVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"chad","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"defaultProfitMaxUnlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAccountant","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllVaults","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllocatorFactory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBrain","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBrainRoles","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"}],"name":"getCategory","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDaddy","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDaddyRoles","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"}],"name":"getDebtAllocator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDebtAllocator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDebtAllocatorRoles","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getKeeper","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getKeeperRoles","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_positionId","type":"bytes32"}],"name":"getPosition","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_positionId","type":"bytes32"}],"name":"getPositionHolder","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_positionId","type":"bytes32"}],"name":"getPositionRoles","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRegistry","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getSecurity","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getSecurityRoles","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStrategyManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStrategyManagerRoles","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"string","name":"_apiVersion","type":"string"},{"internalType":"uint256","name":"_category","type":"uint256"}],"name":"getVault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"governance","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"}],"name":"isVaultsRoleManager","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"uint256","name":"_category","type":"uint256"}],"name":"newVault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"uint256","name":"_category","type":"uint256"},{"internalType":"uint256","name":"_depositLimit","type":"uint256"},{"internalType":"uint256","name":"_profitMaxUnlockTime","type":"uint256"}],"name":"newVault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"uint256","name":"_category","type":"uint256"},{"internalType":"uint256","name":"_depositLimit","type":"uint256"}],"name":"newVault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pendingGovernance","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"_vaults","type":"address[]"},{"internalType":"address","name":"_holder","type":"address"},{"internalType":"uint256","name":"_role","type":"uint256"}],"name":"removeRoles","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"}],"name":"removeVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newDefaultProfitMaxUnlock","type":"uint256"}],"name":"setDefaultProfitMaxUnlock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_position","type":"bytes32"},{"internalType":"address","name":"_newHolder","type":"address"}],"name":"setPositionHolder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_position","type":"bytes32"},{"internalType":"uint256","name":"_newRoles","type":"uint256"}],"name":"setPositionRoles","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newGovernance","type":"address"}],"name":"transferGovernance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"},{"internalType":"address","name":"_debtAllocator","type":"address"}],"name":"updateDebtAllocator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"}],"name":"updateDebtAllocator","outputs":[{"internalType":"address","name":"_newDebtAllocator","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"},{"internalType":"address","name":"_keeper","type":"address"}],"name":"updateKeeper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"vaultConfig","outputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"category","type":"uint256"},{"internalType":"address","name":"debtAllocator","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"vaults","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]Contract Creation Code
60a0604052620d2f006003553480156200001857600080fd5b50604051620033d2380380620033d28339810160408190526200003b91620003b8565b600080546001600160a01b0319166001600160a01b038916908117825560405189928392917f5f56bee8cffbe9a78652a74a60705edede02af10b0bbb888ca44b79a0d42ce80908290a350506001600160a01b038616620000d15760405162461bcd60e51b815260206004820152600c60248201526b5a45524f204144445245535360a01b604482015260640160405180910390fd5b6001600160a01b039586166080818152604080518082018252928352613fff60208085019182527feef8b74e4ca2e456a61430d3d94f2b0a4710302ac13b192e2eec36b17440cfc560009081526004808352955192516001600160601b03908116600160a01b908102948e16949094177fd47b3c79bd50e59096d8ce65b63ebf51be417f69055d0030a5934fa136f10d2455845180860186529b8d168c526111708c84019081527f4c1bd391859805757d865ed7b509d4d26733b7a2204f0afcf45fe0d3efa000a583528784529b519b51811684029b8d169b909b177f8d0e7cff81b8eff0d9b894fecb0fea5bbeb095356aa51bcebdf3c71720e5bb285583518085018552998c168a528982019485527fc764ac13dc7e58eb6edf8aad73d30d911cca42d6ee992ed1eec1b0c56476dc028152858252985193518a168202938b16939093177f0f0b81d657455a35b8381ada6898e7d534146b34b30517e64f1480e4d241f39d5581518083018352968a1687528683018381527f4f78afe9dfc9a0cb0441c27b9405070cd2a48b490636a7bdd09f355e33a5d7de89528484529651965189168102968a16969096177fc0f9a12d667a5c774acef575ed1617cc006b6e66e225868264b4c1aa563dae6b557fb33d6e6dff8e4e4e4050e51a87d0b1f91bda65467f96287ee8d6049a2e99a8518054600360a51b908b161790558051808201909152938816845260038482019081527f672945667f64ce7b1755853bd0c8de4d92f2ded2bdeebd30a972846a04a46806875291905291519151909416909102908416177f26a8d9344e226b269b0d236a40fe5b87efe6af1e7a3c9ff71fb1cccdf3b9399e557f8c53ae70b0aa86068023c633abcdda89c433a8a76949ea111f756c171fa2366390527f8dc63755d617d994eebfba101617bf9b5653d4d567bcd5a055c4d3d1b007cc0b8054919092166001600160a01b031991909116179055506200044d565b80516001600160a01b0381168114620003b357600080fd5b919050565b600080600080600080600060e0888a031215620003d457600080fd5b620003df886200039b565b9650620003ef602089016200039b565b9550620003ff604089016200039b565b94506200040f606089016200039b565b93506200041f608089016200039b565b92506200042f60a089016200039b565b91506200043f60c089016200039b565b905092959891949750929550565b608051612f62620004706000396000818161076a01526117220152612f626000f3fe608060405234801561001057600080fd5b50600436106103425760003560e01c80638440d167116101b8578063ceb68c2311610104578063e0a4edf3116100a2578063ef8d03da1161007c578063ef8d03da14610765578063f39c38a01461078c578063f857ef671461079f578063fc036d7c1461081757600080fd5b8063e0a4edf314610737578063e33c71d01461074a578063e7c512771461075257600080fd5b8063d811ae21116100de578063d811ae21146106f2578063de490aca146106fa578063de8c1b791461070f578063deb20d871461072457600080fd5b8063ceb68c23146106c4578063d013355a146106d7578063d38bfff4146106df57600080fd5b80639fc2c47611610171578063b458dd011161014b578063b458dd0114610678578063b4936a591461068b578063bfb7d4a31461069e578063caa61cb0146106b157600080fd5b80639fc2c47614610648578063a1b770461461065d578063a7bebf9f1461066557600080fd5b80638440d167146105a3578063862a179e146105cf5780638808f66d146105e45780638b9d2940146105f95780638c64ea4a1461062057806397331bf91461063357600080fd5b8063391b6f4e1161029257806362dd471611610230578063732742761161020a578063732742761461058357806374e417d71461058b57806375e48e7e146105935780637de9cd221461059b57600080fd5b806362dd471614610539578063647246041461054c5780636b802bc61461057b57600080fd5b80635594851d1161026c5780635594851d146104d85780635aa6e675146104e05780635ab1bd53146104f35780635dcd6745146104fb57600080fd5b8063391b6f4e146104bf57806348dff373146104c75780634c12c773146104d057600080fd5b80631507a04d116102ff5780632541897f116102d95780632541897f1461047e5780632eeabd8f146104865780633080cef11461049957806338906554146104ac57600080fd5b80631507a04d146103f35780631928b3cb14610406578063238efcbc1461047657600080fd5b806306433b1b1461034757806306fdde031461036f57806309e5d1b7146103845780630a1c187c146103ab57806314adb2f3146103d657806314f675d2146103de575b600080fd5b61035c600080516020612e6d83398151915281565b6040519081526020015b60405180910390f35b61037761082c565b6040516103669190612824565b61035c7f250bebb02a4f564f8ff4a1d2af194d82b25fee33eab79ab5d8256144e0ed0dfe81565b6103be6103b936600461283e565b610899565b6040516001600160a01b039091168152602001610366565b61035c6108b4565b6103f16103ec36600461286c565b6108d2565b005b6103f16104013660046128a5565b610a33565b61045761041436600461283e565b6000908152600460209081526040918290208251808401909352546001600160a01b038116808452600160a01b9091046001600160601b03169290910182905291565b604080516001600160a01b039093168352602083019190915201610366565b6103f1610b23565b6103be610bcb565b6103be610494366004612931565b610be4565b6103f16104a736600461295d565b610c15565b6103f16104ba36600461286c565b611144565b6103be6112e4565b61035c60035481565b61035c6112fd565b61035c611316565b6000546103be906001600160a01b031681565b6103be61132f565b61052961050936600461299f565b6001600160a01b0390811660009081526005602052604090205416151590565b6040519015158152602001610366565b6103be6105473660046129bc565b611348565b6103be61055a36600461299f565b6001600160a01b039081166000908152600560205260409020600201541690565b61035c611378565b61035c611391565b6103be6113aa565b6103be6113c3565b6103be6113ee565b61035c6105b136600461299f565b6001600160a01b031660009081526005602052604090206001015490565b61035c600080516020612ecd83398151915281565b61035c600080516020612e8d83398151915281565b61035c7f1629cfbd564ce33f37c84741f82a28dcd353c97db5819722102f8704671969be81565b6103be61062e36600461283e565b611419565b61063b611443565b60405161036691906129f7565b61035c600080516020612e4d83398151915281565b6103be6114a5565b6103f161067336600461283e565b6114be565b6103be610686366004612a44565b611501565b6103f1610699366004612a79565b611532565b6103be6106ac36600461299f565b611593565b6103f16106bf366004612a9e565b6115af565b6103f16106d236600461299f565b611685565b61035c611972565b6103f16106ed36600461299f565b61198b565b6103be611a22565b61035c600080516020612eed83398151915281565b61035c600080516020612f0d83398151915281565b6103f1610732366004612931565b611a3b565b61035c61074536600461283e565b611a58565b6103be611a7a565b6103be610760366004612b2f565b611a93565b6103be7f000000000000000000000000000000000000000000000000000000000000000081565b6001546103be906001600160a01b031681565b6107e26107ad36600461299f565b60056020526000908152604090208054600182015460028301546003909301546001600160a01b039283169391929091169084565b60405161036694939291906001600160a01b039485168152602081019390935292166040820152606081019190915260800190565b61035c600080516020612ead83398151915281565b6040517f596561726e205633205661756c7420526f6c65204d616e6167657200000000006020820152606090603b0160405160208183030381529060405261087390612bcb565b60405160200161088591815260200190565b604051602081830303815290604052905090565b6000908152600460205260409020546001600160a01b031690565b60006108cd600080516020612ecd833981519152611a58565b905090565b600080516020612f0d8339815191526108ea81611ae6565b6001600160a01b038381166000908152600560205260409020541661092a5760405162461bcd60e51b815260040161092190612bef565b60405180910390fd5b6040805180820182526001600160a01b0380861660009081526005602090815293812060020154909116825291810191909152610968908490611b52565b604080518082019091526001600160a01b0383168152600080516020612e8d833981519152600052600460209081527fb33d6e6dff8e4e4e4050e51a87d0b1f91bda65467f96287ee8d6049a2e99a85154600160a01b90046001600160601b0316908201526109d8908490611b52565b6001600160a01b0383811660008181526005602052604080822060020180546001600160a01b0319169487169485179055517f46b03560e5440592db04cf536396abd2d0e1da05cd4bab259a01af406a8686ed9190a3505050565b610a3b611bd6565b6000805b84811015610b1b57858582818110610a5957610a59612c18565b9050602002016020810190610a6e919061299f565b6001600160a01b0380821660009081526005602052604090205491935016610aa85760405162461bcd60e51b815260040161092190612bef565b60405163e2bf56dd60e01b81526001600160a01b0385811660048301526024820185905283169063e2bf56dd90604401600060405180830381600087803b158015610af257600080fd5b505af1158015610b06573d6000803e3d6000fd5b5050505080610b1490612c44565b9050610a3f565b505050505050565b6001546001600160a01b03163314610b735760405162461bcd60e51b81526020600482015260136024820152722170656e64696e6720676f7665726e616e636560681b6044820152606401610921565b6000805460405133926001600160a01b03909216917f5f56bee8cffbe9a78652a74a60705edede02af10b0bbb888ca44b79a0d42ce8091a3600080546001600160a01b03199081163317909155600180549091169055565b60006108cd600080516020612ead833981519152610899565b6000600080516020612eed833981519152610bfe81611ae6565b610c0d84846000600354611c20565b949350505050565b600080516020612eed833981519152610c2d81611ae6565b6000846001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c6d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c919190612c5d565b90506000856001600160a01b031663258294106040518163ffffffff1660e01b8152600401600060405180830381865afa158015610cd3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610cfb9190810190612c7a565b6001600160a01b03831660009081526006602052604080822090519293509091610d26908490612ce8565b9081526040805160209281900383019020600089815292529020546001600160a01b031614610db1576001600160a01b038216600090815260066020526040908190209051610d76908390612ce8565b9081526040805160209281900383018120600089815293529120546329ab51bf60e01b82526001600160a01b03166004820152602401610921565b306001600160a01b0316866001600160a01b03166379b989176040518163ffffffff1660e01b8152600401602060405180830381865afa158015610df9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e1d9190612c5d565b6001600160a01b031614610e7f57856001600160a01b031663f776bf1f6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610e6657600080fd5b505af1158015610e7a573d6000803e3d6000fd5b505050505b6000610e98600080516020612e6d833981519152610899565b60405163a237e94d60e01b81526001600160a01b0389811660048301529192509082169063a237e94d90602401602060405180830381865afa158015610ee2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f069190612d04565b610f6657604051630ab322d960e01b81526001600160a01b038881166004830152821690630ab322d990602401600060405180830381600087803b158015610f4d57600080fd5b505af1158015610f61573d6000803e3d6000fd5b505050505b610f708786612075565b60006001600160a01b0316876001600160a01b0316634fb3ccc56040518163ffffffff1660e01b8152600401602060405180830381865afa158015610fb9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fdd9190612c5d565b6001600160a01b031603610ff457610ff487612324565b604080516080810182526001600160a01b0380861680835260208084018b81528a841685870190815260028054606088019081528f8716600090815260058652898120985189549089166001600160a01b0319918216178a55945160018a0155925191880180549290971691909316179094555160039094019390935581526006909152819020905188919061108b908590612ce8565b90815260408051918290036020908101832060008b8152915290812080546001600160a01b039485166001600160a01b0319918216179091556002805460018101825592527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace90910180548b851692168217905591871691907f65fe7f527479e9a13137b5a7af43efff08bb8e165ff5897ad493bb0362a690c190611133908a815260200190565b60405180910390a350505050505050565b600080516020612f0d83398151915261115c81611ae6565b6001600160a01b03838116600090815260056020526040902054166111935760405162461bcd60e51b815260040161092190612bef565b60006111ac600080516020612ecd833981519152610899565b9050806001600160a01b0316836001600160a01b0316141580156112385750604051634c9ba32160e11b81526001600160a01b038281166004830152851690639937464290602401602060405180830381865afa158015611211573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112359190612d26565b15155b1561126e5761126e846040518060400160405280846001600160a01b0316815260200160006001600160601b0316815250611b52565b604080518082019091526001600160a01b0384168152600080516020612ecd833981519152600052600460209081527fc0f9a12d667a5c774acef575ed1617cc006b6e66e225868264b4c1aa563dae6b54600160a01b90046001600160601b0316908201526112de908590611b52565b50505050565b60006108cd600080516020612ecd833981519152610899565b60006108cd600080516020612ead833981519152611a58565b60006108cd600080516020612e4d833981519152611a58565b60006108cd600080516020612e6d833981519152610899565b6000600080516020612eed83398151915261136281611ae6565b61136e86868686611c20565b9695505050505050565b60006108cd600080516020612f0d833981519152611a58565b60006108cd600080516020612eed833981519152611a58565b60006108cd600080516020612e4d833981519152610899565b60006108cd7f250bebb02a4f564f8ff4a1d2af194d82b25fee33eab79ab5d8256144e0ed0dfe610899565b60006108cd7f1629cfbd564ce33f37c84741f82a28dcd353c97db5819722102f8704671969be610899565b6002818154811061142957600080fd5b6000918252602090912001546001600160a01b0316905081565b6060600280548060200260200160405190810160405280929190818152602001828054801561149b57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161147d575b5050505050905090565b60006108cd600080516020612e8d833981519152610899565b6114c6611bd6565b60038190556040518181527f4c5e7edcabd189a3cdd68d6b4890f6b8159bf382e2d11a87aa39851f0377432f9060200160405180910390a150565b6000600080516020612eed83398151915261151b81611ae6565b611529858585600354611c20565b95945050505050565b61153a611bd6565b60008281526004602052604080822080546001600160a01b0319166001600160a01b0385169081179091559051909184917f8c42303edb98aad4f3e4f1a15363dda2db344e9fd66ecff9acf62f770c474fa39190a35050565b600061159e826124a9565b90506115aa82826108d2565b919050565b6115b7611bd6565b600080516020612e8d83398151915282141580156115e35750600080516020612ecd8339815191528214155b61161f5760405162461bcd60e51b815260206004820152600d60248201526c63616e6e6f742075706461746560981b6044820152606401610921565b60008281526004602090815260409182902080546001600160a01b0316600160a01b6001600160601b03861602179055905182815283917ff8a7e043f1e7310711bc663ed81ae8855aa474348c57a6461b9f52a4fa88a94d910160405180910390a25050565b600080516020612f0d83398151915261169d81611ae6565b6001600160a01b03808316600090815260056020908152604091829020825160808101845281548516808252600183015493820193909352600282015490941692840192909252600390910154606083015261170b5760405162461bcd60e51b815260040161092190612bef565b60405163ef54cefd60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015284169063ef54cefd90602401600060405180830381600087803b15801561176e57600080fd5b505af1158015611782573d6000803e3d6000fd5b5050505060006002600160028054905061179c9190612d3f565b815481106117ac576117ac612c18565b9060005260206000200160009054906101000a90046001600160a01b031690508060028360600151815481106117e4576117e4612c18565b600091825260208083209190910180546001600160a01b0319166001600160a01b0394851617905560608501519284168252600590526040902060030155600280548061183357611833612d52565b60008281526020808220830160001990810180546001600160a01b031916905590920190925583516001600160a01b039081168352600690915260408083208151630258294160e41b81529151909392881692632582941092600480820193918290030181865afa1580156118ac573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526118d49190810190612c7a565b6040516118e19190612ce8565b908152604080516020928190038301812085840151600090815290845282812080546001600160a01b03199081169091556001600160a01b03891680835260059095529281208054841681556001810182905560028101805490941690935560039092018290557fa40a7d97cd4243d8bcd193dc4d709afc3717750c5996d9e7216d1a5e0288c4949190a250505050565b60006108cd600080516020612e8d833981519152611a58565b611993611bd6565b6001600160a01b0381166119d85760405162461bcd60e51b815260206004820152600c60248201526b5a45524f204144445245535360a01b6044820152606401610921565b600180546001600160a01b0319166001600160a01b0383169081179091556040517fa443b483867b0f9db5b03913474dd21935ac5ba70fa6c94e3423ba9be157c44b90600090a250565b60006108cd600080516020612f0d833981519152610899565b6000611a46836124a9565b9050611a53838383610c15565b505050565b600090815260046020526040902054600160a01b90046001600160601b031690565b60006108cd600080516020612eed833981519152610899565b6001600160a01b0383166000908152600660205260408082209051611ab9908590612ce8565b90815260408051602092819003830190206000948552909152909120546001600160a01b03169392505050565b6000546001600160a01b0316331480611b185750611b0381610899565b6001600160a01b0316336001600160a01b0316145b611b4f5760405162461bcd60e51b815260206004820152600860248201526708585b1b1bddd95960c21b6044820152606401610921565b50565b80516001600160a01b031615611bd25780516020820151604051632cf7fd8560e01b81526001600160a01b0392831660048201526001600160601b03909116602482015290831690632cf7fd85906044015b600060405180830381600087803b158015611bbe57600080fd5b505af1158015610b1b573d6000803e3d6000fd5b5050565b6000546001600160a01b03163314611c1e5760405162461bcd60e51b815260206004820152600b60248201526a21676f7665726e616e636560a81b6044820152606401610921565b565b600080611c2c85612579565b90506000866001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015611c6e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611c969190810190612c7a565b82604051602001611ca8929190612d68565b60405160208183030381529060405290506000876001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015611cf9573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611d219190810190612c7a565b83604051602001611d33929190612db8565b6040516020818303038152906040529050611d5b600080516020612e6d833981519152610899565b6001600160a01b03166317bdd312898484308a6040518663ffffffff1660e01b8152600401611d8e959493929190612e02565b6020604051808303816000875af1158015611dad573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dd19190612c5d565b93506000846001600160a01b031663258294106040518163ffffffff1660e01b8152600401600060405180830381865afa158015611e13573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611e3b9190810190612c7a565b6001600160a01b038a1660009081526006602052604080822090519293509091611e66908490612ce8565b908152604080516020928190038301902060008c815292529020546001600160a01b031614611ef1576001600160a01b038916600090815260066020526040908190209051611eb6908390612ce8565b908152604080516020928190038301812060008c815293529120546329ab51bf60e01b82526001600160a01b03166004820152602401610921565b6000611efc866124a9565b9050611f088682612075565b611f1186612324565b8715611f2157611f21868961260c565b604080516080810182526001600160a01b03808d1680835260208084018e815286841685870190815260028054606088019081528e8716600090815260058652898120985189549089166001600160a01b0319918216178a55945160018a01559251918801805492909716919093161790945551600390940193909355815260069091528190209051879190611fb8908590612ce8565b90815260408051918290036020908101832060008e8152915290812080546001600160a01b039485166001600160a01b0319918216179091556002805460018101825592527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace90910180548a851692168217905591831691907f65fe7f527479e9a13137b5a7af43efff08bb8e165ff5897ad493bb0362a690c190612060908d815260200190565b60405180910390a35050505050949350505050565b600080516020612eed83398151915260005260046020908152604080518082019091527fd47b3c79bd50e59096d8ce65b63ebf51be417f69055d0030a5934fa136f10d24546001600160a01b0381168252600160a01b90046001600160601b0316918101919091526120e8908390611b52565b600080516020612f0d83398151915260005260046020908152604080518082019091527f8d0e7cff81b8eff0d9b894fecb0fea5bbeb095356aa51bcebdf3c71720e5bb28546001600160a01b0381168252600160a01b90046001600160601b03169181019190915261215b908390611b52565b600080516020612ead83398151915260005260046020908152604080518082019091527f0f0b81d657455a35b8381ada6898e7d534146b34b30517e64f1480e4d241f39d546001600160a01b0381168252600160a01b90046001600160601b0316918101919091526121ce908390611b52565b600080516020612ecd83398151915260005260046020908152604080518082019091527fc0f9a12d667a5c774acef575ed1617cc006b6e66e225868264b4c1aa563dae6b546001600160a01b0381168252600160a01b90046001600160601b031691810191909152612241908390611b52565b600080516020612e4d83398151915260005260046020908152604080518082019091527f26a8d9344e226b269b0d236a40fe5b87efe6af1e7a3c9ff71fb1cccdf3b9399e546001600160a01b0381168252600160a01b90046001600160601b0316918101919091526122b4908390611b52565b604080518082019091526001600160a01b0382168152600080516020612e8d833981519152600052600460209081527fb33d6e6dff8e4e4e4050e51a87d0b1f91bda65467f96287ee8d6049a2e99a85154600160a01b90046001600160601b031690820152611bd2908390611b52565b600061234f7f1629cfbd564ce33f37c84741f82a28dcd353c97db5819722102f8704671969be610899565b90506001600160a01b03811615611bd2576040516354be77d160e11b8152306004820152600860248201526001600160a01b0383169063a97cefa290604401600060405180830381600087803b1580156123a857600080fd5b505af11580156123bc573d6000803e3d6000fd5b50506040516371da8a8d60e01b81526001600160a01b038481166004830152851692506371da8a8d9150602401600060405180830381600087803b15801561240357600080fd5b505af1158015612417573d6000803e3d6000fd5b505060405163e2bf56dd60e01b8152306004820152600860248201526001600160a01b038516925063e2bf56dd9150604401600060405180830381600087803b15801561246357600080fd5b505af1158015612477573d6000803e3d6000fd5b50506040516312b5ad0160e11b81526001600160a01b0385811660048301528416925063256b5a029150602401611ba4565b6000806124d57f250bebb02a4f564f8ff4a1d2af194d82b25fee33eab79ab5d8256144e0ed0dfe610899565b90506001600160a01b038116156125595760405163028d34c960e41b81526001600160a01b0384811660048301528216906328d34c90906024016020604051808303816000875af115801561252e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125529190612c5d565b9150612573565b612570600080516020612e8d833981519152610899565b91505b50919050565b60606000612586836126fb565b600101905060008167ffffffffffffffff8111156125a6576125a6612ac0565b6040519080825280601f01601f1916602001820160405280156125d0576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a85049450846125da57509392505050565b6040516354be77d160e11b815230600482015261010060248201526001600160a01b0383169063a97cefa290604401600060405180830381600087803b15801561265557600080fd5b505af1158015612669573d6000803e3d6000fd5b50506040516337f00e8f60e11b8152600481018490526001600160a01b0385169250636fe01d1e9150602401600060405180830381600087803b1580156126af57600080fd5b505af11580156126c3573d6000803e3d6000fd5b505060405163e2bf56dd60e01b815230600482015261010060248201526001600160a01b038516925063e2bf56dd9150604401611ba4565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b831061273a5772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef81000000008310612766576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc10000831061278457662386f26fc10000830492506010015b6305f5e100831061279c576305f5e100830492506008015b61271083106127b057612710830492506004015b606483106127c2576064830492506002015b600a83106127ce576001015b92915050565b60005b838110156127ef5781810151838201526020016127d7565b50506000910152565b600081518084526128108160208601602086016127d4565b601f01601f19169290920160200192915050565b60208152600061283760208301846127f8565b9392505050565b60006020828403121561285057600080fd5b5035919050565b6001600160a01b0381168114611b4f57600080fd5b6000806040838503121561287f57600080fd5b823561288a81612857565b9150602083013561289a81612857565b809150509250929050565b600080600080606085870312156128bb57600080fd5b843567ffffffffffffffff808211156128d357600080fd5b818701915087601f8301126128e757600080fd5b8135818111156128f657600080fd5b8860208260051b850101111561290b57600080fd5b6020928301965094505085013561292181612857565b9396929550929360400135925050565b6000806040838503121561294457600080fd5b823561294f81612857565b946020939093013593505050565b60008060006060848603121561297257600080fd5b833561297d81612857565b925060208401359150604084013561299481612857565b809150509250925092565b6000602082840312156129b157600080fd5b813561283781612857565b600080600080608085870312156129d257600080fd5b84356129dd81612857565b966020860135965060408601359560600135945092505050565b6020808252825182820181905260009190848201906040850190845b81811015612a385783516001600160a01b031683529284019291840191600101612a13565b50909695505050505050565b600080600060608486031215612a5957600080fd5b8335612a6481612857565b95602085013595506040909401359392505050565b60008060408385031215612a8c57600080fd5b82359150602083013561289a81612857565b60008060408385031215612ab157600080fd5b50508035926020909101359150565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715612aff57612aff612ac0565b604052919050565b600067ffffffffffffffff821115612b2157612b21612ac0565b50601f01601f191660200190565b600080600060608486031215612b4457600080fd5b8335612b4f81612857565b9250602084013567ffffffffffffffff811115612b6b57600080fd5b8401601f81018613612b7c57600080fd5b8035612b8f612b8a82612b07565b612ad6565b818152876020838501011115612ba457600080fd5b81602084016020830137600060208383010152809450505050604084013590509250925092565b805160208083015191908110156125735760001960209190910360031b1b16919050565b6020808252600f908201526e1d985d5b1d081b9bdd081859191959608a1b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201612c5657612c56612c2e565b5060010190565b600060208284031215612c6f57600080fd5b815161283781612857565b600060208284031215612c8c57600080fd5b815167ffffffffffffffff811115612ca357600080fd5b8201601f81018413612cb457600080fd5b8051612cc2612b8a82612b07565b818152856020838501011115612cd757600080fd5b6115298260208301602086016127d4565b60008251612cfa8184602087016127d4565b9190910192915050565b600060208284031215612d1657600080fd5b8151801515811461283757600080fd5b600060208284031215612d3857600080fd5b5051919050565b818103818111156127ce576127ce612c2e565b634e487b7160e01b600052603160045260246000fd5b60008351612d7a8184602088016127d4565b602d60f81b9083019081528351612d988160018401602088016127d4565b66081e55985d5b1d60ca1b60019290910191820152600801949350505050565b613cbb60f11b815260008351612dd58160028501602088016127d4565b602d60f81b6002918401918201528351612df68160038401602088016127d4565b01600301949350505050565b600060018060a01b03808816835260a06020840152612e2460a08401886127f8565b8381036040850152612e3681886127f8565b959091166060840152505060800152939250505056fe672945667f64ce7b1755853bd0c8de4d92f2ded2bdeebd30a972846a04a468068c53ae70b0aa86068023c633abcdda89c433a8a76949ea111f756c171fa23663e36275342c99ede79a003741503250226904c6a298f8766fdff5fe056b171b70c764ac13dc7e58eb6edf8aad73d30d911cca42d6ee992ed1eec1b0c56476dc024f78afe9dfc9a0cb0441c27b9405070cd2a48b490636a7bdd09f355e33a5d7deeef8b74e4ca2e456a61430d3d94f2b0a4710302ac13b192e2eec36b17440cfc54c1bd391859805757d865ed7b509d4d26733b7a2204f0afcf45fe0d3efa000a5a26469706673582212204f62da56a9b8cd75182336b57a2a001fdacade7867d92e13340daa5b2614253664736f6c63430008120033000000000000000000000000feb4acf3df3cdea7399794d0869ef76a6efaff52000000000000000000000000feb4acf3df3cdea7399794d0869ef76a6efaff5200000000000000000000000016388463d60ffe0661cf7f1f31a7d658ac790ff70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c2d26d13582324f10c7c3753b8f5fc71011ecf570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ff31a1b020c868f6ea3f61eb953344920eeca3af
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106103425760003560e01c80638440d167116101b8578063ceb68c2311610104578063e0a4edf3116100a2578063ef8d03da1161007c578063ef8d03da14610765578063f39c38a01461078c578063f857ef671461079f578063fc036d7c1461081757600080fd5b8063e0a4edf314610737578063e33c71d01461074a578063e7c512771461075257600080fd5b8063d811ae21116100de578063d811ae21146106f2578063de490aca146106fa578063de8c1b791461070f578063deb20d871461072457600080fd5b8063ceb68c23146106c4578063d013355a146106d7578063d38bfff4146106df57600080fd5b80639fc2c47611610171578063b458dd011161014b578063b458dd0114610678578063b4936a591461068b578063bfb7d4a31461069e578063caa61cb0146106b157600080fd5b80639fc2c47614610648578063a1b770461461065d578063a7bebf9f1461066557600080fd5b80638440d167146105a3578063862a179e146105cf5780638808f66d146105e45780638b9d2940146105f95780638c64ea4a1461062057806397331bf91461063357600080fd5b8063391b6f4e1161029257806362dd471611610230578063732742761161020a578063732742761461058357806374e417d71461058b57806375e48e7e146105935780637de9cd221461059b57600080fd5b806362dd471614610539578063647246041461054c5780636b802bc61461057b57600080fd5b80635594851d1161026c5780635594851d146104d85780635aa6e675146104e05780635ab1bd53146104f35780635dcd6745146104fb57600080fd5b8063391b6f4e146104bf57806348dff373146104c75780634c12c773146104d057600080fd5b80631507a04d116102ff5780632541897f116102d95780632541897f1461047e5780632eeabd8f146104865780633080cef11461049957806338906554146104ac57600080fd5b80631507a04d146103f35780631928b3cb14610406578063238efcbc1461047657600080fd5b806306433b1b1461034757806306fdde031461036f57806309e5d1b7146103845780630a1c187c146103ab57806314adb2f3146103d657806314f675d2146103de575b600080fd5b61035c600080516020612e6d83398151915281565b6040519081526020015b60405180910390f35b61037761082c565b6040516103669190612824565b61035c7f250bebb02a4f564f8ff4a1d2af194d82b25fee33eab79ab5d8256144e0ed0dfe81565b6103be6103b936600461283e565b610899565b6040516001600160a01b039091168152602001610366565b61035c6108b4565b6103f16103ec36600461286c565b6108d2565b005b6103f16104013660046128a5565b610a33565b61045761041436600461283e565b6000908152600460209081526040918290208251808401909352546001600160a01b038116808452600160a01b9091046001600160601b03169290910182905291565b604080516001600160a01b039093168352602083019190915201610366565b6103f1610b23565b6103be610bcb565b6103be610494366004612931565b610be4565b6103f16104a736600461295d565b610c15565b6103f16104ba36600461286c565b611144565b6103be6112e4565b61035c60035481565b61035c6112fd565b61035c611316565b6000546103be906001600160a01b031681565b6103be61132f565b61052961050936600461299f565b6001600160a01b0390811660009081526005602052604090205416151590565b6040519015158152602001610366565b6103be6105473660046129bc565b611348565b6103be61055a36600461299f565b6001600160a01b039081166000908152600560205260409020600201541690565b61035c611378565b61035c611391565b6103be6113aa565b6103be6113c3565b6103be6113ee565b61035c6105b136600461299f565b6001600160a01b031660009081526005602052604090206001015490565b61035c600080516020612ecd83398151915281565b61035c600080516020612e8d83398151915281565b61035c7f1629cfbd564ce33f37c84741f82a28dcd353c97db5819722102f8704671969be81565b6103be61062e36600461283e565b611419565b61063b611443565b60405161036691906129f7565b61035c600080516020612e4d83398151915281565b6103be6114a5565b6103f161067336600461283e565b6114be565b6103be610686366004612a44565b611501565b6103f1610699366004612a79565b611532565b6103be6106ac36600461299f565b611593565b6103f16106bf366004612a9e565b6115af565b6103f16106d236600461299f565b611685565b61035c611972565b6103f16106ed36600461299f565b61198b565b6103be611a22565b61035c600080516020612eed83398151915281565b61035c600080516020612f0d83398151915281565b6103f1610732366004612931565b611a3b565b61035c61074536600461283e565b611a58565b6103be611a7a565b6103be610760366004612b2f565b611a93565b6103be7f000000000000000000000000feb4acf3df3cdea7399794d0869ef76a6efaff5281565b6001546103be906001600160a01b031681565b6107e26107ad36600461299f565b60056020526000908152604090208054600182015460028301546003909301546001600160a01b039283169391929091169084565b60405161036694939291906001600160a01b039485168152602081019390935292166040820152606081019190915260800190565b61035c600080516020612ead83398151915281565b6040517f596561726e205633205661756c7420526f6c65204d616e6167657200000000006020820152606090603b0160405160208183030381529060405261087390612bcb565b60405160200161088591815260200190565b604051602081830303815290604052905090565b6000908152600460205260409020546001600160a01b031690565b60006108cd600080516020612ecd833981519152611a58565b905090565b600080516020612f0d8339815191526108ea81611ae6565b6001600160a01b038381166000908152600560205260409020541661092a5760405162461bcd60e51b815260040161092190612bef565b60405180910390fd5b6040805180820182526001600160a01b0380861660009081526005602090815293812060020154909116825291810191909152610968908490611b52565b604080518082019091526001600160a01b0383168152600080516020612e8d833981519152600052600460209081527fb33d6e6dff8e4e4e4050e51a87d0b1f91bda65467f96287ee8d6049a2e99a85154600160a01b90046001600160601b0316908201526109d8908490611b52565b6001600160a01b0383811660008181526005602052604080822060020180546001600160a01b0319169487169485179055517f46b03560e5440592db04cf536396abd2d0e1da05cd4bab259a01af406a8686ed9190a3505050565b610a3b611bd6565b6000805b84811015610b1b57858582818110610a5957610a59612c18565b9050602002016020810190610a6e919061299f565b6001600160a01b0380821660009081526005602052604090205491935016610aa85760405162461bcd60e51b815260040161092190612bef565b60405163e2bf56dd60e01b81526001600160a01b0385811660048301526024820185905283169063e2bf56dd90604401600060405180830381600087803b158015610af257600080fd5b505af1158015610b06573d6000803e3d6000fd5b5050505080610b1490612c44565b9050610a3f565b505050505050565b6001546001600160a01b03163314610b735760405162461bcd60e51b81526020600482015260136024820152722170656e64696e6720676f7665726e616e636560681b6044820152606401610921565b6000805460405133926001600160a01b03909216917f5f56bee8cffbe9a78652a74a60705edede02af10b0bbb888ca44b79a0d42ce8091a3600080546001600160a01b03199081163317909155600180549091169055565b60006108cd600080516020612ead833981519152610899565b6000600080516020612eed833981519152610bfe81611ae6565b610c0d84846000600354611c20565b949350505050565b600080516020612eed833981519152610c2d81611ae6565b6000846001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c6d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c919190612c5d565b90506000856001600160a01b031663258294106040518163ffffffff1660e01b8152600401600060405180830381865afa158015610cd3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610cfb9190810190612c7a565b6001600160a01b03831660009081526006602052604080822090519293509091610d26908490612ce8565b9081526040805160209281900383019020600089815292529020546001600160a01b031614610db1576001600160a01b038216600090815260066020526040908190209051610d76908390612ce8565b9081526040805160209281900383018120600089815293529120546329ab51bf60e01b82526001600160a01b03166004820152602401610921565b306001600160a01b0316866001600160a01b03166379b989176040518163ffffffff1660e01b8152600401602060405180830381865afa158015610df9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e1d9190612c5d565b6001600160a01b031614610e7f57856001600160a01b031663f776bf1f6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610e6657600080fd5b505af1158015610e7a573d6000803e3d6000fd5b505050505b6000610e98600080516020612e6d833981519152610899565b60405163a237e94d60e01b81526001600160a01b0389811660048301529192509082169063a237e94d90602401602060405180830381865afa158015610ee2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f069190612d04565b610f6657604051630ab322d960e01b81526001600160a01b038881166004830152821690630ab322d990602401600060405180830381600087803b158015610f4d57600080fd5b505af1158015610f61573d6000803e3d6000fd5b505050505b610f708786612075565b60006001600160a01b0316876001600160a01b0316634fb3ccc56040518163ffffffff1660e01b8152600401602060405180830381865afa158015610fb9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fdd9190612c5d565b6001600160a01b031603610ff457610ff487612324565b604080516080810182526001600160a01b0380861680835260208084018b81528a841685870190815260028054606088019081528f8716600090815260058652898120985189549089166001600160a01b0319918216178a55945160018a0155925191880180549290971691909316179094555160039094019390935581526006909152819020905188919061108b908590612ce8565b90815260408051918290036020908101832060008b8152915290812080546001600160a01b039485166001600160a01b0319918216179091556002805460018101825592527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace90910180548b851692168217905591871691907f65fe7f527479e9a13137b5a7af43efff08bb8e165ff5897ad493bb0362a690c190611133908a815260200190565b60405180910390a350505050505050565b600080516020612f0d83398151915261115c81611ae6565b6001600160a01b03838116600090815260056020526040902054166111935760405162461bcd60e51b815260040161092190612bef565b60006111ac600080516020612ecd833981519152610899565b9050806001600160a01b0316836001600160a01b0316141580156112385750604051634c9ba32160e11b81526001600160a01b038281166004830152851690639937464290602401602060405180830381865afa158015611211573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112359190612d26565b15155b1561126e5761126e846040518060400160405280846001600160a01b0316815260200160006001600160601b0316815250611b52565b604080518082019091526001600160a01b0384168152600080516020612ecd833981519152600052600460209081527fc0f9a12d667a5c774acef575ed1617cc006b6e66e225868264b4c1aa563dae6b54600160a01b90046001600160601b0316908201526112de908590611b52565b50505050565b60006108cd600080516020612ecd833981519152610899565b60006108cd600080516020612ead833981519152611a58565b60006108cd600080516020612e4d833981519152611a58565b60006108cd600080516020612e6d833981519152610899565b6000600080516020612eed83398151915261136281611ae6565b61136e86868686611c20565b9695505050505050565b60006108cd600080516020612f0d833981519152611a58565b60006108cd600080516020612eed833981519152611a58565b60006108cd600080516020612e4d833981519152610899565b60006108cd7f250bebb02a4f564f8ff4a1d2af194d82b25fee33eab79ab5d8256144e0ed0dfe610899565b60006108cd7f1629cfbd564ce33f37c84741f82a28dcd353c97db5819722102f8704671969be610899565b6002818154811061142957600080fd5b6000918252602090912001546001600160a01b0316905081565b6060600280548060200260200160405190810160405280929190818152602001828054801561149b57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161147d575b5050505050905090565b60006108cd600080516020612e8d833981519152610899565b6114c6611bd6565b60038190556040518181527f4c5e7edcabd189a3cdd68d6b4890f6b8159bf382e2d11a87aa39851f0377432f9060200160405180910390a150565b6000600080516020612eed83398151915261151b81611ae6565b611529858585600354611c20565b95945050505050565b61153a611bd6565b60008281526004602052604080822080546001600160a01b0319166001600160a01b0385169081179091559051909184917f8c42303edb98aad4f3e4f1a15363dda2db344e9fd66ecff9acf62f770c474fa39190a35050565b600061159e826124a9565b90506115aa82826108d2565b919050565b6115b7611bd6565b600080516020612e8d83398151915282141580156115e35750600080516020612ecd8339815191528214155b61161f5760405162461bcd60e51b815260206004820152600d60248201526c63616e6e6f742075706461746560981b6044820152606401610921565b60008281526004602090815260409182902080546001600160a01b0316600160a01b6001600160601b03861602179055905182815283917ff8a7e043f1e7310711bc663ed81ae8855aa474348c57a6461b9f52a4fa88a94d910160405180910390a25050565b600080516020612f0d83398151915261169d81611ae6565b6001600160a01b03808316600090815260056020908152604091829020825160808101845281548516808252600183015493820193909352600282015490941692840192909252600390910154606083015261170b5760405162461bcd60e51b815260040161092190612bef565b60405163ef54cefd60e01b81526001600160a01b037f000000000000000000000000feb4acf3df3cdea7399794d0869ef76a6efaff528116600483015284169063ef54cefd90602401600060405180830381600087803b15801561176e57600080fd5b505af1158015611782573d6000803e3d6000fd5b5050505060006002600160028054905061179c9190612d3f565b815481106117ac576117ac612c18565b9060005260206000200160009054906101000a90046001600160a01b031690508060028360600151815481106117e4576117e4612c18565b600091825260208083209190910180546001600160a01b0319166001600160a01b0394851617905560608501519284168252600590526040902060030155600280548061183357611833612d52565b60008281526020808220830160001990810180546001600160a01b031916905590920190925583516001600160a01b039081168352600690915260408083208151630258294160e41b81529151909392881692632582941092600480820193918290030181865afa1580156118ac573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526118d49190810190612c7a565b6040516118e19190612ce8565b908152604080516020928190038301812085840151600090815290845282812080546001600160a01b03199081169091556001600160a01b03891680835260059095529281208054841681556001810182905560028101805490941690935560039092018290557fa40a7d97cd4243d8bcd193dc4d709afc3717750c5996d9e7216d1a5e0288c4949190a250505050565b60006108cd600080516020612e8d833981519152611a58565b611993611bd6565b6001600160a01b0381166119d85760405162461bcd60e51b815260206004820152600c60248201526b5a45524f204144445245535360a01b6044820152606401610921565b600180546001600160a01b0319166001600160a01b0383169081179091556040517fa443b483867b0f9db5b03913474dd21935ac5ba70fa6c94e3423ba9be157c44b90600090a250565b60006108cd600080516020612f0d833981519152610899565b6000611a46836124a9565b9050611a53838383610c15565b505050565b600090815260046020526040902054600160a01b90046001600160601b031690565b60006108cd600080516020612eed833981519152610899565b6001600160a01b0383166000908152600660205260408082209051611ab9908590612ce8565b90815260408051602092819003830190206000948552909152909120546001600160a01b03169392505050565b6000546001600160a01b0316331480611b185750611b0381610899565b6001600160a01b0316336001600160a01b0316145b611b4f5760405162461bcd60e51b815260206004820152600860248201526708585b1b1bddd95960c21b6044820152606401610921565b50565b80516001600160a01b031615611bd25780516020820151604051632cf7fd8560e01b81526001600160a01b0392831660048201526001600160601b03909116602482015290831690632cf7fd85906044015b600060405180830381600087803b158015611bbe57600080fd5b505af1158015610b1b573d6000803e3d6000fd5b5050565b6000546001600160a01b03163314611c1e5760405162461bcd60e51b815260206004820152600b60248201526a21676f7665726e616e636560a81b6044820152606401610921565b565b600080611c2c85612579565b90506000866001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015611c6e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611c969190810190612c7a565b82604051602001611ca8929190612d68565b60405160208183030381529060405290506000876001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015611cf9573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611d219190810190612c7a565b83604051602001611d33929190612db8565b6040516020818303038152906040529050611d5b600080516020612e6d833981519152610899565b6001600160a01b03166317bdd312898484308a6040518663ffffffff1660e01b8152600401611d8e959493929190612e02565b6020604051808303816000875af1158015611dad573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dd19190612c5d565b93506000846001600160a01b031663258294106040518163ffffffff1660e01b8152600401600060405180830381865afa158015611e13573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611e3b9190810190612c7a565b6001600160a01b038a1660009081526006602052604080822090519293509091611e66908490612ce8565b908152604080516020928190038301902060008c815292529020546001600160a01b031614611ef1576001600160a01b038916600090815260066020526040908190209051611eb6908390612ce8565b908152604080516020928190038301812060008c815293529120546329ab51bf60e01b82526001600160a01b03166004820152602401610921565b6000611efc866124a9565b9050611f088682612075565b611f1186612324565b8715611f2157611f21868961260c565b604080516080810182526001600160a01b03808d1680835260208084018e815286841685870190815260028054606088019081528e8716600090815260058652898120985189549089166001600160a01b0319918216178a55945160018a01559251918801805492909716919093161790945551600390940193909355815260069091528190209051879190611fb8908590612ce8565b90815260408051918290036020908101832060008e8152915290812080546001600160a01b039485166001600160a01b0319918216179091556002805460018101825592527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace90910180548a851692168217905591831691907f65fe7f527479e9a13137b5a7af43efff08bb8e165ff5897ad493bb0362a690c190612060908d815260200190565b60405180910390a35050505050949350505050565b600080516020612eed83398151915260005260046020908152604080518082019091527fd47b3c79bd50e59096d8ce65b63ebf51be417f69055d0030a5934fa136f10d24546001600160a01b0381168252600160a01b90046001600160601b0316918101919091526120e8908390611b52565b600080516020612f0d83398151915260005260046020908152604080518082019091527f8d0e7cff81b8eff0d9b894fecb0fea5bbeb095356aa51bcebdf3c71720e5bb28546001600160a01b0381168252600160a01b90046001600160601b03169181019190915261215b908390611b52565b600080516020612ead83398151915260005260046020908152604080518082019091527f0f0b81d657455a35b8381ada6898e7d534146b34b30517e64f1480e4d241f39d546001600160a01b0381168252600160a01b90046001600160601b0316918101919091526121ce908390611b52565b600080516020612ecd83398151915260005260046020908152604080518082019091527fc0f9a12d667a5c774acef575ed1617cc006b6e66e225868264b4c1aa563dae6b546001600160a01b0381168252600160a01b90046001600160601b031691810191909152612241908390611b52565b600080516020612e4d83398151915260005260046020908152604080518082019091527f26a8d9344e226b269b0d236a40fe5b87efe6af1e7a3c9ff71fb1cccdf3b9399e546001600160a01b0381168252600160a01b90046001600160601b0316918101919091526122b4908390611b52565b604080518082019091526001600160a01b0382168152600080516020612e8d833981519152600052600460209081527fb33d6e6dff8e4e4e4050e51a87d0b1f91bda65467f96287ee8d6049a2e99a85154600160a01b90046001600160601b031690820152611bd2908390611b52565b600061234f7f1629cfbd564ce33f37c84741f82a28dcd353c97db5819722102f8704671969be610899565b90506001600160a01b03811615611bd2576040516354be77d160e11b8152306004820152600860248201526001600160a01b0383169063a97cefa290604401600060405180830381600087803b1580156123a857600080fd5b505af11580156123bc573d6000803e3d6000fd5b50506040516371da8a8d60e01b81526001600160a01b038481166004830152851692506371da8a8d9150602401600060405180830381600087803b15801561240357600080fd5b505af1158015612417573d6000803e3d6000fd5b505060405163e2bf56dd60e01b8152306004820152600860248201526001600160a01b038516925063e2bf56dd9150604401600060405180830381600087803b15801561246357600080fd5b505af1158015612477573d6000803e3d6000fd5b50506040516312b5ad0160e11b81526001600160a01b0385811660048301528416925063256b5a029150602401611ba4565b6000806124d57f250bebb02a4f564f8ff4a1d2af194d82b25fee33eab79ab5d8256144e0ed0dfe610899565b90506001600160a01b038116156125595760405163028d34c960e41b81526001600160a01b0384811660048301528216906328d34c90906024016020604051808303816000875af115801561252e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125529190612c5d565b9150612573565b612570600080516020612e8d833981519152610899565b91505b50919050565b60606000612586836126fb565b600101905060008167ffffffffffffffff8111156125a6576125a6612ac0565b6040519080825280601f01601f1916602001820160405280156125d0576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a85049450846125da57509392505050565b6040516354be77d160e11b815230600482015261010060248201526001600160a01b0383169063a97cefa290604401600060405180830381600087803b15801561265557600080fd5b505af1158015612669573d6000803e3d6000fd5b50506040516337f00e8f60e11b8152600481018490526001600160a01b0385169250636fe01d1e9150602401600060405180830381600087803b1580156126af57600080fd5b505af11580156126c3573d6000803e3d6000fd5b505060405163e2bf56dd60e01b815230600482015261010060248201526001600160a01b038516925063e2bf56dd9150604401611ba4565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b831061273a5772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef81000000008310612766576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc10000831061278457662386f26fc10000830492506010015b6305f5e100831061279c576305f5e100830492506008015b61271083106127b057612710830492506004015b606483106127c2576064830492506002015b600a83106127ce576001015b92915050565b60005b838110156127ef5781810151838201526020016127d7565b50506000910152565b600081518084526128108160208601602086016127d4565b601f01601f19169290920160200192915050565b60208152600061283760208301846127f8565b9392505050565b60006020828403121561285057600080fd5b5035919050565b6001600160a01b0381168114611b4f57600080fd5b6000806040838503121561287f57600080fd5b823561288a81612857565b9150602083013561289a81612857565b809150509250929050565b600080600080606085870312156128bb57600080fd5b843567ffffffffffffffff808211156128d357600080fd5b818701915087601f8301126128e757600080fd5b8135818111156128f657600080fd5b8860208260051b850101111561290b57600080fd5b6020928301965094505085013561292181612857565b9396929550929360400135925050565b6000806040838503121561294457600080fd5b823561294f81612857565b946020939093013593505050565b60008060006060848603121561297257600080fd5b833561297d81612857565b925060208401359150604084013561299481612857565b809150509250925092565b6000602082840312156129b157600080fd5b813561283781612857565b600080600080608085870312156129d257600080fd5b84356129dd81612857565b966020860135965060408601359560600135945092505050565b6020808252825182820181905260009190848201906040850190845b81811015612a385783516001600160a01b031683529284019291840191600101612a13565b50909695505050505050565b600080600060608486031215612a5957600080fd5b8335612a6481612857565b95602085013595506040909401359392505050565b60008060408385031215612a8c57600080fd5b82359150602083013561289a81612857565b60008060408385031215612ab157600080fd5b50508035926020909101359150565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715612aff57612aff612ac0565b604052919050565b600067ffffffffffffffff821115612b2157612b21612ac0565b50601f01601f191660200190565b600080600060608486031215612b4457600080fd5b8335612b4f81612857565b9250602084013567ffffffffffffffff811115612b6b57600080fd5b8401601f81018613612b7c57600080fd5b8035612b8f612b8a82612b07565b612ad6565b818152876020838501011115612ba457600080fd5b81602084016020830137600060208383010152809450505050604084013590509250925092565b805160208083015191908110156125735760001960209190910360031b1b16919050565b6020808252600f908201526e1d985d5b1d081b9bdd081859191959608a1b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201612c5657612c56612c2e565b5060010190565b600060208284031215612c6f57600080fd5b815161283781612857565b600060208284031215612c8c57600080fd5b815167ffffffffffffffff811115612ca357600080fd5b8201601f81018413612cb457600080fd5b8051612cc2612b8a82612b07565b818152856020838501011115612cd757600080fd5b6115298260208301602086016127d4565b60008251612cfa8184602087016127d4565b9190910192915050565b600060208284031215612d1657600080fd5b8151801515811461283757600080fd5b600060208284031215612d3857600080fd5b5051919050565b818103818111156127ce576127ce612c2e565b634e487b7160e01b600052603160045260246000fd5b60008351612d7a8184602088016127d4565b602d60f81b9083019081528351612d988160018401602088016127d4565b66081e55985d5b1d60ca1b60019290910191820152600801949350505050565b613cbb60f11b815260008351612dd58160028501602088016127d4565b602d60f81b6002918401918201528351612df68160038401602088016127d4565b01600301949350505050565b600060018060a01b03808816835260a06020840152612e2460a08401886127f8565b8381036040850152612e3681886127f8565b959091166060840152505060800152939250505056fe672945667f64ce7b1755853bd0c8de4d92f2ded2bdeebd30a972846a04a468068c53ae70b0aa86068023c633abcdda89c433a8a76949ea111f756c171fa23663e36275342c99ede79a003741503250226904c6a298f8766fdff5fe056b171b70c764ac13dc7e58eb6edf8aad73d30d911cca42d6ee992ed1eec1b0c56476dc024f78afe9dfc9a0cb0441c27b9405070cd2a48b490636a7bdd09f355e33a5d7deeef8b74e4ca2e456a61430d3d94f2b0a4710302ac13b192e2eec36b17440cfc54c1bd391859805757d865ed7b509d4d26733b7a2204f0afcf45fe0d3efa000a5a26469706673582212204f62da56a9b8cd75182336b57a2a001fdacade7867d92e13340daa5b2614253664736f6c63430008120033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000feb4acf3df3cdea7399794d0869ef76a6efaff52000000000000000000000000feb4acf3df3cdea7399794d0869ef76a6efaff5200000000000000000000000016388463d60ffe0661cf7f1f31a7d658ac790ff70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c2d26d13582324f10c7c3753b8f5fc71011ecf570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ff31a1b020c868f6ea3f61eb953344920eeca3af
-----Decoded View---------------
Arg [0] : _governance (address): 0xFEB4acf3df3cDEA7399794D0869ef76A6EfAff52
Arg [1] : _daddy (address): 0xFEB4acf3df3cDEA7399794D0869ef76A6EfAff52
Arg [2] : _brain (address): 0x16388463d60FFE0661Cf7F1f31a7D658aC790ff7
Arg [3] : _security (address): 0x0000000000000000000000000000000000000000
Arg [4] : _keeper (address): 0xc2d26d13582324f10c7c3753B8F5Fc71011EcF57
Arg [5] : _strategyManager (address): 0x0000000000000000000000000000000000000000
Arg [6] : _registry (address): 0xff31A1B020c868F6eA3f61Eb953344920EeCA3af
-----Encoded View---------------
7 Constructor Arguments found :
Arg [0] : 000000000000000000000000feb4acf3df3cdea7399794d0869ef76a6efaff52
Arg [1] : 000000000000000000000000feb4acf3df3cdea7399794d0869ef76a6efaff52
Arg [2] : 00000000000000000000000016388463d60ffe0661cf7f1f31a7d658ac790ff7
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [4] : 000000000000000000000000c2d26d13582324f10c7c3753b8f5fc71011ecf57
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [6] : 000000000000000000000000ff31a1b020c868f6ea3f61eb953344920eeca3af
Deployed Bytecode Sourcemap
145974:33025:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;148754:56;;-1:-1:-1;;;;;;;;;;;148754:56:0;;;;;160:25:1;;;148:2;133:18;148754:56:0;;;;;;;;171251:120;;;:::i;:::-;;;;;;;:::i;149242:74::-;;149286:30;149242:74;;174427:158;;;;;;:::i;:::-;;:::i;:::-;;;-1:-1:-1;;;;;1301:32:1;;;1283:51;;1271:2;1256:18;174427:158:0;1137:203:1;178328:116:0;;;:::i;165418:791::-;;;;;;:::i;:::-;;:::i;:::-;;168739:522;;;;;;:::i;:::-;;:::i;173967:237::-;;;;;;:::i;:::-;174054:7;174111:23;;;:10;:23;;;;;;;;;174083:51;;;;;;;;;-1:-1:-1;;;;;174083:51:0;;;;;-1:-1:-1;;;174083:51:0;;;-1:-1:-1;;;;;174083:51:0;;;;;;;;;173967:237;;;;;-1:-1:-1;;;;;3077:32:1;;;3059:51;;3141:2;3126:18;;3119:34;;;;3032:18;173967:237:0;2885:274:1;120160:267:0;;;:::i;175645:116::-;;;:::i;152837:220::-;;;;;;:::i;:::-;;:::i;162735:1957::-;;;;;;:::i;:::-;;:::i;166422:704::-;;;;;;:::i;:::-;;:::i;175913:112::-;;;:::i;149837:47::-;;;;;;178066:120;;;:::i;178861:135::-;;;:::i;626:25::-;;;;;-1:-1:-1;;;;;626:25:0;;;176710:116;;;:::i;172718:163::-;;;;;;:::i;:::-;-1:-1:-1;;;;;172834:19:0;;;172810:4;172834:19;;;:11;:19;;;;;:25;;:39;;;172718:163;;;;4362:14:1;;4355:22;4337:41;;4325:2;4310:18;172718:163:0;4197:187:1;154057:314:0;;;;;;:::i;:::-;;:::i;173150:157::-;;;;;;:::i;:::-;-1:-1:-1;;;;;173266:19:0;;;173239:7;173266:19;;;:11;:19;;;;;:33;;;;;173150:157;177806:114;;;:::i;177552:::-;;;:::i;176179:131::-;;;:::i;177279:133::-;;;:::i;176452:120::-;;;:::i;173557:147::-;;;;;;:::i;:::-;-1:-1:-1;;;;;173668:19:0;173641:7;173668:19;;;:11;:19;;;;;:28;;;;173557:147;148540:52;;-1:-1:-1;;;;;;;;;;;148540:52:0;;148981:68;;-1:-1:-1;;;;;;;;;;;148981:68:0;;148866:60;;148903:23;148866:60;;149726:23;;;;;;:::i;:::-;;:::i;171513:105::-;;;:::i;:::-;;;;;;;:::i;149107:72::-;;-1:-1:-1;;;;;;;;;;;149107:72:0;;176996:127;;;:::i;170731:263::-;;;;;;:::i;:::-;;:::i;153399:277::-;;;;;;:::i;:::-;;:::i;170294:244::-;;;;;;:::i;:::-;;:::i;164938:234::-;;;;;;:::i;:::-;;:::i;169637:460::-;;;;;;:::i;:::-;;:::i;167331:1058::-;;;;;;:::i;:::-;;:::i;178586:131::-;;;:::i;119784:283::-;;;;;;:::i;:::-;;:::i;175379:110::-;;;:::i;148341:50::-;;-1:-1:-1;;;;;;;;;;;148341:50:0;;148440;;-1:-1:-1;;;;;;;;;;;148440:50:0;;162144:198;;;;;;:::i;:::-;;:::i;174804:165::-;;;;;;:::i;:::-;;:::i;175119:110::-;;;:::i;172041:225::-;;;;;;:::i;:::-;;:::i;149446:29::-;;;;;119460:32;;;;;-1:-1:-1;;;;;119460:32:0;;;150072:50;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;150072:50:0;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;8427:15:1;;;8409:34;;8474:2;8459:18;;8452:34;;;;8522:15;;8517:2;8502:18;;8495:43;8569:2;8554:18;;8547:34;;;;8358:3;8343:19;;8140:447;148644:56:0;;-1:-1:-1;;;;;;;;;;;148644:56:0;;171251:120;148058:47;;8806:29:1;148058:47:0;;;8794:42:1;171298:13:0;;8852:12:1;;148058:47:0;;;;;;;;;;;;148050:56;;;:::i;:::-;171338:24;;;;;;9306:19:1;;9350:2;9341:12;;9177:182;171338:24:0;;;;;;;;;;;;;171324:39;;171251:120;:::o;174427:158::-;174520:7;174547:23;;;:10;:23;;;;;:30;-1:-1:-1;;;;;174547:30:0;;174427:158::o;178328:116::-;178385:7;178412:24;-1:-1:-1;;;;;;;;;;;178412:16:0;:24::i;:::-;178405:31;;178328:116;:::o;165418:791::-;-1:-1:-1;;;;;;;;;;;147556:30:0;147574:11;147556:17;:30::i;:::-;-1:-1:-1;;;;;165640:19:0;;::::1;165677:1;165640:19:::0;;;:11:::1;:19;::::0;;;;:25;::::1;165632:67;;;;-1:-1:-1::0;;;165632:67:0::1;;;;;;;:::i;:::-;;;;;;;;;165782:46;::::0;;;;::::1;::::0;;-1:-1:-1;;;;;165791:19:0;;::::1;-1:-1:-1::0;165791:19:0;;;:11:::1;:19;::::0;;;;;;:33:::1;;::::0;;;::::1;165782:46:::0;;;;::::1;::::0;;;;165765:64:::1;::::0;165774:6;;165765:8:::1;:64::i;:::-;165946:58;::::0;;;;::::1;::::0;;;-1:-1:-1;;;;;165946:58:0;::::1;::::0;;-1:-1:-1;;;;;;;;;;;;165971:26:0;:10:::1;165946:58;165971:26:::0;;;;:32;-1:-1:-1;;;165971:32:0;::::1;-1:-1:-1::0;;;;;165971:32:0::1;165946:58:::0;;::::1;::::0;165902:113:::1;::::0;165925:6;;165902:8:::1;:113::i;:::-;-1:-1:-1::0;;;;;166066:19:0;;::::1;;::::0;;;:11:::1;:19;::::0;;;;;:33:::1;;:50:::0;;-1:-1:-1;;;;;;166066:50:0::1;::::0;;::::1;::::0;;::::1;::::0;;166158:43;::::1;::::0;166066:19;166158:43:::1;165418:791:::0;;;:::o;168739:522::-;322:18;:16;:18::i;:::-;168897:14:::1;::::0;168922:332:::1;168942:18:::0;;::::1;168922:332;;;168991:7;;168999:1;168991:10;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;169091:19:0;;::::1;169128:1;169091:19:::0;;;:11:::1;:19;::::0;;;;:25;168982:19;;-1:-1:-1;169091:25:0::1;169083:67;;;;-1:-1:-1::0;;;169083:67:0::1;;;;;;;:::i;:::-;169200:42;::::0;-1:-1:-1;;;169200:42:0;;-1:-1:-1;;;;;3077:32:1;;;169200:42:0::1;::::0;::::1;3059:51:1::0;3126:18;;;3119:34;;;169200:26:0;::::1;::::0;::::1;::::0;3032:18:1;;169200:42:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;168962:3;;;;:::i;:::-;;;168922:332;;;;168886:375;168739:522:::0;;;;:::o;120160:267::-;120238:17;;-1:-1:-1;;;;;120238:17:0;120224:10;:31;120216:63;;;;-1:-1:-1;;;120216:63:0;;10314:2:1;120216:63:0;;;10296:21:1;10353:2;10333:18;;;10326:30;-1:-1:-1;;;10372:18:1;;;10365:49;10431:18;;120216:63:0;10112:343:1;120216:63:0;120319:10;;;120297:45;;120331:10;;-1:-1:-1;;;;;120319:10:0;;;;120297:45;;;120355:10;:23;;-1:-1:-1;;;;;;120355:23:0;;;120368:10;120355:23;;;;;120389:30;;;;;;;120160:267::o;175645:116::-;175699:7;175726:27;-1:-1:-1;;;;;;;;;;;175726:17:0;:27::i;152837:220::-;152967:7;-1:-1:-1;;;;;;;;;;;147556:30:0;147574:11;147556:17;:30::i;:::-;152994:55:::1;153004:6;153012:9;153023:1;153026:22;;152994:9;:55::i;:::-;152987:62:::0;152837:220;-1:-1:-1;;;;152837:220:0:o;162735:1957::-;-1:-1:-1;;;;;;;;;;;147556:30:0;147574:11;147556:17;:30::i;:::-;162981:14:::1;163005:6;-1:-1:-1::0;;;;;162998:20:0::1;;:22;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;162981:39;;163031:25;163066:6;-1:-1:-1::0;;;;;163059:25:0::1;;:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;::::0;;::::1;-1:-1:-1::0;;163059:27:0::1;::::0;::::1;;::::0;::::1;::::0;;;::::1;::::0;::::1;:::i;:::-;-1:-1:-1::0;;;;;163101:21:0;::::1;163158:1;163101:21:::0;;;:13:::1;:21;::::0;;;;;:34;;163031:55;;-1:-1:-1;163158:1:0;;163101:34:::1;::::0;163031:55;;163101:34:::1;:::i;:::-;::::0;;;::::1;::::0;;::::1;::::0;;;;;;;;:45:::1;::::0;;;;;;;;-1:-1:-1;;;;;163101:45:0::1;:59;163097:179;;-1:-1:-1::0;;;;;163216:21:0;::::1;;::::0;;;:13:::1;:21;::::0;;;;;;:34;;::::1;::::0;163238:11;;163216:34:::1;:::i;:::-;::::0;;;::::1;::::0;;::::1;::::0;;;;;;;;:45:::1;::::0;;;;;;;;-1:-1:-1;;;163182:94:0;;-1:-1:-1;;;;;163216:45:0::1;163182:94;::::0;::::1;1283:51:1::0;1256:18;;163182:94:0::1;1137:203:1::0;163097:179:0::1;163379:4;-1:-1:-1::0;;;;;163338:46:0::1;163345:6;-1:-1:-1::0;;;;;163338:27:0::1;;:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;163338:46:0::1;;163334:168;;163461:6;-1:-1:-1::0;;;;;163454:34:0::1;;:36;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;163334:168;163552:16;163571:27;-1:-1:-1::0;;;;;;;;;;;163571:17:0::1;:27::i;:::-;163686:37;::::0;-1:-1:-1;;;163686:37:0;;-1:-1:-1;;;;;1301:32:1;;;163686:37:0::1;::::0;::::1;1283:51:1::0;163552:46:0;;-1:-1:-1;163686:29:0;;::::1;::::0;::::1;::::0;1256:18:1;;163686:37:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;163681:236;;163853:52;::::0;-1:-1:-1;;;163853:52:0;;-1:-1:-1;;;;;1301:32:1;;;163853:52:0::1;::::0;::::1;1283:51:1::0;163853:44:0;::::1;::::0;::::1;::::0;1256:18:1;;163853:52:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;163681:236;163959:33;163969:6;163977:14;163959:9;:33::i;:::-;164112:1;-1:-1:-1::0;;;;;164073:41:0::1;164080:6;-1:-1:-1::0;;;;;164073:25:0::1;;:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;164073:41:0::1;::::0;164069:96:::1;;164131:22;164146:6;164131:14;:22::i;:::-;164248:165;::::0;;::::1;::::0;::::1;::::0;;-1:-1:-1;;;;;164248:165:0;;::::1;::::0;;;::::1;::::0;;::::1;::::0;;;;;::::1;::::0;;;;;;164388:6:::1;:13:::0;;164248:165;;;;;;164226:19;;::::1;-1:-1:-1::0;164226:19:0;;;:11:::1;:19:::0;;;;;:187;;;;;;::::1;-1:-1:-1::0;;;;;;164226:187:0;;::::1;;::::0;;;;;;::::1;::::0;;;;;::::1;::::0;;;;;::::1;::::0;;;::::1;;::::0;;;;::::1;::::0;;::::1;::::0;;;;164468:21;;:13:::1;:21:::0;;;;;;:34;;164238:6;;164468:21;:34:::1;::::0;164490:11;;164468:34:::1;:::i;:::-;::::0;;;::::1;::::0;;;;;;::::1;::::0;;;;;:45:::1;::::0;;;;;;;;:54;;-1:-1:-1;;;;;164468:54:0;;::::1;-1:-1:-1::0;;;;;;164468:54:0;;::::1;;::::0;;;164575:6:::1;:19:::0;;164468:54;164575:19;::::1;::::0;;;;;;;::::1;::::0;;;;::::1;::::0;::::1;::::0;::::1;::::0;;164636:48;;::::1;::::0;164575:19;164636:48:::1;::::0;::::1;::::0;164503:9;160:25:1;;148:2;133:18;;14:177;164636:48:0::1;;;;;;;;162890:1802;;;162735:1957:::0;;;;:::o;166422:704::-;-1:-1:-1;;;;;;;;;;;147556:30:0;147574:11;147556:17;:30::i;:::-;-1:-1:-1;;;;;166632:19:0;;::::1;166669:1;166632:19:::0;;;:11:::1;:19;::::0;;;;:25;::::1;166624:67;;;;-1:-1:-1::0;;;166624:67:0::1;;;;;;;:::i;:::-;166764:21;166788:25;-1:-1:-1::0;;;;;;;;;;;166788:17:0::1;:25::i;:::-;166764:49;;166853:13;-1:-1:-1::0;;;;;166842:24:0::1;:7;-1:-1:-1::0;;;;;166842:24:0::1;;;:68;;;;-1:-1:-1::0;166870:35:0::1;::::0;-1:-1:-1;;;166870:35:0;;-1:-1:-1;;;;;1301:32:1;;;166870:35:0::1;::::0;::::1;1283:51:1::0;166870:20:0;::::1;::::0;::::1;::::0;1256:18:1;;166870:35:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:40:::0;::::1;166842:68;166824:169;;;166937:44;166946:6;166954:26;;;;;;;;166963:13;-1:-1:-1::0;;;;;166954:26:0::1;;;;;166978:1;-1:-1:-1::0;;;;;166954:26:0::1;;;::::0;166937:8:::1;:44::i;:::-;167074:43;::::0;;;;::::1;::::0;;;-1:-1:-1;;;;;167074:43:0;::::1;::::0;;-1:-1:-1;;;;;;;;;;;;167092:18:0;:10:::1;167074:43;167092:18:::0;;;;:24;-1:-1:-1;;;167092:24:0;::::1;-1:-1:-1::0;;;;;167092:24:0::1;167074:43:::0;;::::1;::::0;167057:61:::1;::::0;167066:6;;167057:8:::1;:61::i;:::-;166545:581;166422:704:::0;;;:::o;175913:112::-;175965:7;175992:25;-1:-1:-1;;;;;;;;;;;175992:17:0;:25::i;178066:120::-;178125:7;178152:26;-1:-1:-1;;;;;;;;;;;178152:16:0;:26::i;178861:135::-;178927:7;178954:34;-1:-1:-1;;;;;;;;;;;178954:16:0;:34::i;176710:116::-;176764:7;176791:27;-1:-1:-1;;;;;;;;;;;176791:17:0;:27::i;154057:314::-;154258:7;-1:-1:-1;;;;;;;;;;;147556:30:0;147574:11;147556:17;:30::i;:::-;154298:65:::1;154308:6;154316:9;154327:13;154342:20;154298:9;:65::i;:::-;154278:85:::0;154057:314;-1:-1:-1;;;;;;154057:314:0:o;177806:114::-;177862:7;177889:23;-1:-1:-1;;;;;;;;;;;177889:16:0;:23::i;177552:114::-;177608:7;177635:23;-1:-1:-1;;;;;;;;;;;177635:16:0;:23::i;176179:131::-;176240:7;176267:35;-1:-1:-1;;;;;;;;;;;176267:17:0;:35::i;177279:133::-;177341:7;177368:36;149286:30;177368:17;:36::i;176452:120::-;176508:7;176535:29;148903:23;176535:17;:29::i;149726:23::-;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;149726:23:0;;-1:-1:-1;149726:23:0;:::o;171513:105::-;171568:16;171604:6;171597:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;171597:13:0;;;;;;;;;;;;;;;;;;;;;;;171513:105;:::o;176996:127::-;177055:7;177082:33;-1:-1:-1;;;;;;;;;;;177082:17:0;:33::i;170731:263::-;322:18;:16;:18::i;:::-;170861:22:::1;:51:::0;;;170930:56:::1;::::0;160:25:1;;;170930:56:0::1;::::0;148:2:1;133:18;170930:56:0::1;;;;;;;170731:263:::0;:::o;153399:277::-;153561:7;-1:-1:-1;;;;;;;;;;;147556:30:0;147574:11;147556:17;:30::i;:::-;153601:67:::1;153611:6;153619:9;153630:13;153645:22;;153601:9;:67::i;:::-;153581:87:::0;153399:277;-1:-1:-1;;;;;153399:277:0:o;170294:244::-;322:18;:16;:18::i;:::-;170428:21:::1;::::0;;;:10:::1;:21;::::0;;;;;:41;;-1:-1:-1;;;;;;170428:41:0::1;-1:-1:-1::0;;;;;170428:41:0;::::1;::::0;;::::1;::::0;;;170487:43;;170428:41;;:21;;170487:43:::1;::::0;170428:21;170487:43:::1;170294:244:::0;;:::o;164938:234::-;165025:25;165083:24;165100:6;165083:16;:24::i;:::-;165063:44;;165118:46;165138:6;165146:17;165118:19;:46::i;:::-;164938:234;;;:::o;169637:460::-;322:18;:16;:18::i;:::-;-1:-1:-1;;;;;;;;;;;169881:9:0::1;:27;;:50;;;;;-1:-1:-1::0;;;;;;;;;;;169912:9:0::1;:19;;169881:50;169859:113;;;::::0;-1:-1:-1;;;169859:113:0;;12337:2:1;169859:113:0::1;::::0;::::1;12319:21:1::0;12376:2;12356:18;;;12349:30;-1:-1:-1;;;12395:18:1;;;12388:43;12448:18;;169859:113:0::1;12135:337:1::0;169859:113:0::1;169983:21;::::0;;;:10:::1;:21;::::0;;;;;;;;:47;;-1:-1:-1;;;;;169983:47:0::1;-1:-1:-1::0;;;;;;;;169983:47:0;::::1;;;::::0;;170048:41;;160:25:1;;;169983:21:0;;170048:41:::1;::::0;133:18:1;170048:41:0::1;;;;;;;169637:460:::0;;:::o;167331:1058::-;-1:-1:-1;;;;;;;;;;;147556:30:0;147574:11;147556:17;:30::i;:::-;-1:-1:-1;;;;;167509:19:0;;::::1;167481:25;167509:19:::0;;;:11:::1;:19;::::0;;;;;;;;167481:47;;::::1;::::0;::::1;::::0;;;;;::::1;::::0;;;;;::::1;::::0;;;::::1;::::0;;;;::::1;::::0;::::1;::::0;;;::::1;::::0;;;;;;;::::1;::::0;;::::1;::::0;;;;;167607:54:::1;;;;-1:-1:-1::0;;;167607:54:0::1;;;;;;;:::i;:::-;167722:42;::::0;-1:-1:-1;;;167722:42:0;;-1:-1:-1;;;;;167759:4:0::1;1301:32:1::0;;167722:42:0::1;::::0;::::1;1283:51:1::0;167722:36:0;::::1;::::0;::::1;::::0;1256:18:1;;167722:42:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;167830:19;167852:6;167875:1;167859:6;:13;;;;:17;;;;:::i;:::-;167852:25;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;-1:-1:-1::0;;;;;167852:25:0::1;167830:47;;167970:11;167947:6;167954;:12;;;167947:20;;;;;;;;:::i;:::-;;::::0;;;::::1;::::0;;;;;;::::1;:34:::0;;-1:-1:-1;;;;;;167947:34:0::1;-1:-1:-1::0;;;;;167947:34:0;;::::1;;::::0;;168025:12:::1;::::0;::::1;::::0;167992:24;;::::1;::::0;;:11:::1;:24:::0;;;;;:30:::1;;:45:::0;168084:6:::1;:12:::0;;;::::1;;;;:::i;:::-;;::::0;;;::::1;::::0;;;;;-1:-1:-1;;168084:12:0;;;;;-1:-1:-1;;;;;;168084:12:0::1;::::0;;;;;;;;168177;;-1:-1:-1;;;;;168163:27:0;;::::1;::::0;;:13:::1;:27:::0;;;;;;;168191;;-1:-1:-1;;;168191:27:0;;;;168163;;168191:25;;::::1;::::0;::::1;::::0;:27:::1;::::0;;::::1;::::0;;;;;;;:25;:27:::1;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;::::0;;::::1;-1:-1:-1::0;;168191:27:0::1;::::0;::::1;;::::0;::::1;::::0;;;::::1;::::0;::::1;:::i;:::-;168163:56;;;;;;:::i;:::-;::::0;;;::::1;::::0;;::::1;::::0;;;;;;;;168234:15;;::::1;::::0;168163:97:::1;::::0;;;;;;;;;168156:104;;-1:-1:-1;;;;;;168156:104:0;;::::1;::::0;;;-1:-1:-1;;;;;168324:19:0;::::1;::::0;;;:11:::1;:19:::0;;;;;;168317:26;;;::::1;::::0;;-1:-1:-1;168317:26:0;::::1;::::0;;;::::1;::::0;::::1;::::0;;;;::::1;::::0;;;::::1;::::0;;::::1;::::0;;;168361:20:::1;::::0;168163:97;168361:20:::1;167427:962;;167331:1058:::0;;:::o;178586:131::-;178650:7;178677:32;-1:-1:-1;;;;;;;;;;;178677:16:0;:32::i;119784:283::-;322:18;:16;:18::i;:::-;-1:-1:-1;;;;;119912:28:0;::::1;119904:53;;;::::0;-1:-1:-1;;;119904:53:0;;12944:2:1;119904:53:0::1;::::0;::::1;12926:21:1::0;12983:2;12963:18;;;12956:30;-1:-1:-1;;;13002:18:1;;;12995:42;13054:18;;119904:53:0::1;12742:336:1::0;119904:53:0::1;119968:17;:34:::0;;-1:-1:-1;;;;;;119968:34:0::1;-1:-1:-1::0;;;;;119968:34:0;::::1;::::0;;::::1;::::0;;;120020:39:::1;::::0;::::1;::::0;-1:-1:-1;;120020:39:0::1;119784:283:::0;:::o;175379:110::-;175430:7;175457:24;-1:-1:-1;;;;;;;;;;;175457:17:0;:24::i;162144:198::-;162228:22;162253:24;162270:6;162253:16;:24::i;:::-;162228:49;;162288:46;162300:6;162308:9;162319:14;162288:11;:46::i;:::-;162217:125;162144:198;;:::o;174804:165::-;174896:7;174931:23;;;:10;:23;;;;;:29;-1:-1:-1;;;174931:29:0;;-1:-1:-1;;;;;174931:29:0;;174804:165::o;175119:110::-;175170:7;175197:24;-1:-1:-1;;;;;;;;;;;175197:17:0;:24::i;172041:225::-;-1:-1:-1;;;;;172213:21:0;;172186:7;172213:21;;;:13;:21;;;;;;:34;;;;172235:11;;172213:34;:::i;:::-;;;;;;;;;;;;;;;;:45;;;;;;;;;;;-1:-1:-1;;;;;172213:45:0;;172041:225;-1:-1:-1;;;172041:225:0:o;147703:236::-;147820:10;;-1:-1:-1;;;;;147820:10:0;147806;:24;;:89;;;147865:30;147883:11;147865:17;:30::i;:::-;-1:-1:-1;;;;;147851:44:0;:10;-1:-1:-1;;;;;147851:44:0;;147806:89;147784:147;;;;-1:-1:-1;;;147784:147:0;;13285:2:1;147784:147:0;;;13267:21:1;13324:1;13304:18;;;13297:29;-1:-1:-1;;;13342:18:1;;;13335:38;13390:18;;147784:147:0;13083:331:1;147784:147:0;147703:236;:::o;159462:251::-;159580:16;;-1:-1:-1;;;;;159580:30:0;;159576:130;;159651:16;;159677:15;;;;159627:67;;-1:-1:-1;;;159627:67:0;;-1:-1:-1;;;;;3077:32:1;;;159627:67:0;;;3059:51:1;-1:-1:-1;;;;;159669:24:0;;;3126:18:1;;;3119:34;159627:23:0;;;;;;3032:18:1;;159627:67:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;159576:130;159462:251;;:::o;429:117::-;498:10;;-1:-1:-1;;;;;498:10:0;512;498:24;490:48;;;;-1:-1:-1;;;490:48:0;;13621:2:1;490:48:0;;;13603:21:1;13660:2;13640:18;;;13633:30;-1:-1:-1;;;13679:18:1;;;13672:41;13730:18;;490:48:0;13419:335:1;490:48:0;429:117::o;154752:2330::-;154928:14;154955:29;154987:27;155004:9;154987:16;:27::i;:::-;154955:59;;155076:19;155160:6;-1:-1:-1;;;;;155154:20:0;;:22;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;155154:22:0;;;;;;;;;;;;:::i;:::-;155217:15;155119:156;;;;;;;;;:::i;:::-;;;;;;;;;;;;;155076:210;;155344:21;155418:6;-1:-1:-1;;;;;155412:20:0;;:22;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;155412:22:0;;;;;;;;;;;;:::i;:::-;155441:15;155389:68;;;;;;;;;:::i;:::-;;;;;;;;;;;;;155344:124;;155572:27;-1:-1:-1;;;;;;;;;;;155572:17:0;:27::i;:::-;-1:-1:-1;;;;;155563:54:0;;155632:6;155653:5;155673:7;155703:4;155723:20;155563:191;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;155554:200;;155915:25;155950:6;-1:-1:-1;;;;;155943:25:0;;:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;155943:27:0;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;155985:21:0;;156042:1;155985:21;;;:13;:21;;;;;;:34;;155915:55;;-1:-1:-1;156042:1:0;;155985:34;;155915:55;;155985:34;:::i;:::-;;;;;;;;;;;;;;;;:45;;;;;;;;;-1:-1:-1;;;;;155985:45:0;:59;155981:179;;-1:-1:-1;;;;;156100:21:0;;;;;;:13;:21;;;;;;;:34;;;;156122:11;;156100:34;:::i;:::-;;;;;;;;;;;;;;;;:45;;;;;;;;;-1:-1:-1;;;156066:94:0;;-1:-1:-1;;;;;156100:45:0;156066:94;;;1283:51:1;1256:18;;156066:94:0;1137:203:1;155981:179:0;156228:22;156253:24;156270:6;156253:16;:24::i;:::-;156228:49;;156335:33;156345:6;156353:14;156335:9;:33::i;:::-;156416:22;156431:6;156416:14;:22::i;:::-;156455:18;;156451:90;;156490:39;156507:6;156515:13;156490:16;:39::i;:::-;156624:165;;;;;;;;-1:-1:-1;;;;;156624:165:0;;;;;;;;;;;;;;;;;;;;;;156764:6;:13;;156624:165;;;;;;156602:19;;;-1:-1:-1;156602:19:0;;;:11;:19;;;;;:187;;;;;;;-1:-1:-1;;;;;;156602:187:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;156844:21;;:13;:21;;;;;;:34;;156614:6;;156844:21;:34;;156866:11;;156844:34;:::i;:::-;;;;;;;;;;;;;;;;;:45;;;;;;;;;:54;;-1:-1:-1;;;;;156844:54:0;;;-1:-1:-1;;;;;;156844:54:0;;;;;;;156951:6;:19;;156844:54;156951:19;;;;;;;;;;;;;;;;;;;;;157026:48;;;;156951:19;157026:48;;;;156879:9;160:25:1;;148:2;133:18;;14:177;157026:48:0;;;;;;;;154944:2138;;;;;154752:2330;;;;;;:::o;158270:752::-;-1:-1:-1;;;;;;;;;;;158436:17:0;;:10;:17;;;;;158419:35;;;;;;;;158436:17;158419:35;-1:-1:-1;;;;;158419:35:0;;;;-1:-1:-1;;;158419:35:0;;-1:-1:-1;;;;;158419:35:0;;;;;;;;;;158428:6;;158419:8;:35::i;:::-;-1:-1:-1;;;;;;;;;;;158521:17:0;;:10;:17;;;;;158504:35;;;;;;;;158521:17;158504:35;-1:-1:-1;;;;;158504:35:0;;;;-1:-1:-1;;;158504:35:0;;-1:-1:-1;;;;;158504:35:0;;;;;;;;;;158513:6;;158504:8;:35::i;:::-;-1:-1:-1;;;;;;;;;;;158609:20:0;;:10;:20;;;;;158592:38;;;;;;;;158609:20;158592:38;-1:-1:-1;;;;;158592:38:0;;;;-1:-1:-1;;;158592:38:0;;-1:-1:-1;;;;;158592:38:0;;;;;;;;;;158601:6;;158592:8;:38::i;:::-;-1:-1:-1;;;;;;;;;;;158702:18:0;;:10;:18;;;;;158685:36;;;;;;;;158702:18;158685:36;-1:-1:-1;;;;;158685:36:0;;;;-1:-1:-1;;;158685:36:0;;-1:-1:-1;;;;;158685:36:0;;;;;;;;;;158694:6;;158685:8;:36::i;:::-;-1:-1:-1;;;;;;;;;;;158803:28:0;;:10;:28;;;;;158786:46;;;;;;;;158803:28;158786:46;-1:-1:-1;;;;;158786:46:0;;;;-1:-1:-1;;;158786:46:0;;-1:-1:-1;;;;;158786:46:0;;;;;;;;;;158795:6;;158786:8;:46::i;:::-;158945:58;;;;;;;;;-1:-1:-1;;;;;158945:58:0;;;;-1:-1:-1;;;;;;;;;;;;158970:26:0;:10;158945:58;158970:26;;;;:32;-1:-1:-1;;;158970:32:0;;-1:-1:-1;;;;;158970:32:0;158945:58;;;;158901:113;;158924:6;;158901:8;:113::i;159977:759::-;160085:18;160106:29;148903:23;160106:17;:29::i;:::-;160085:50;-1:-1:-1;;;;;;160195:24:0;;;160191:538;;160318:64;;-1:-1:-1;;;160318:64:0;;160350:4;160318:64;;;3059:51:1;114446:1:0;3126:18:1;;;3119:34;-1:-1:-1;;;;;160318:23:0;;;;;3032:18:1;;160318:64:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;160445:41:0;;-1:-1:-1;;;160445:41:0;;-1:-1:-1;;;;;1301:32:1;;;160445:41:0;;;1283:51:1;160445:29:0;;;-1:-1:-1;160445:29:0;;-1:-1:-1;1256:18:1;;160445:41:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;160539:67:0;;-1:-1:-1;;;160539:67:0;;160574:4;160539:67;;;3059:51:1;114446:1:0;3126:18:1;;;3119:34;-1:-1:-1;;;;;160539:26:0;;;-1:-1:-1;160539:26:0;;-1:-1:-1;3032:18:1;;160539:67:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;160678:39:0;;-1:-1:-1;;;160678:39:0;;-1:-1:-1;;;;;1301:32:1;;;160678:39:0;;;1283:51:1;160678:31:0;;;-1:-1:-1;160678:31:0;;-1:-1:-1;1256:18:1;;160678:39:0;1137:203:1;157286:631:0;157370:22;157405:15;157423:36;149286:30;157423:17;:36::i;:::-;157405:54;-1:-1:-1;;;;;;157514:21:0;;;157510:400;;157650:86;;-1:-1:-1;;;157650:86:0;;-1:-1:-1;;;;;1301:32:1;;;157650:86:0;;;1283:51:1;157650:46:0;;;;;1256:18:1;;157650:86:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;157633:103;;157510:400;;;157865:33;-1:-1:-1;;;;;;;;;;;157865:17:0;:33::i;:::-;157848:50;;157510:400;157394:523;157286:631;;;:::o;116805:716::-;116861:13;116912:14;116929:17;116940:5;116929:10;:17::i;:::-;116949:1;116929:21;116912:38;;116965:20;116999:6;116988:18;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;116988:18:0;-1:-1:-1;116965:41:0;-1:-1:-1;117130:28:0;;;117146:2;117130:28;117187:288;-1:-1:-1;;117219:5:0;-1:-1:-1;;;117356:2:0;117345:14;;117340:30;117219:5;117327:44;117417:2;117408:11;;;-1:-1:-1;117438:21:0;117187:288;117438:21;-1:-1:-1;117496:6:0;116805:716;-1:-1:-1;;;116805:716:0:o;161089:505::-;161288:67;;-1:-1:-1;;;161288:67:0;;161320:4;161288:67;;;3059:51:1;114789:3:0;3126:18:1;;;3119:34;-1:-1:-1;;;;;161288:23:0;;;;;3032:18:1;;161288:67:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;161424:47:0;;-1:-1:-1;;;161424:47:0;;;;;160:25:1;;;-1:-1:-1;;;;;161424:32:0;;;-1:-1:-1;161424:32:0;;-1:-1:-1;133:18:1;;161424:47:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;161516:70:0;;-1:-1:-1;;;161516:70:0;;161551:4;161516:70;;;3059:51:1;114789:3:0;3126:18:1;;;3119:34;-1:-1:-1;;;;;161516:26:0;;;-1:-1:-1;161516:26:0;;-1:-1:-1;3032:18:1;;161516:70:0;2885:274:1;55517:948:0;55570:7;;-1:-1:-1;;;55648:17:0;;55644:106;;-1:-1:-1;;;55686:17:0;;;-1:-1:-1;55732:2:0;55722:12;55644:106;55777:8;55768:5;:17;55764:106;;55815:8;55806:17;;;-1:-1:-1;55852:2:0;55842:12;55764:106;55897:8;55888:5;:17;55884:106;;55935:8;55926:17;;;-1:-1:-1;55972:2:0;55962:12;55884:106;56017:7;56008:5;:16;56004:103;;56054:7;56045:16;;;-1:-1:-1;56090:1:0;56080:11;56004:103;56134:7;56125:5;:16;56121:103;;56171:7;56162:16;;;-1:-1:-1;56207:1:0;56197:11;56121:103;56251:7;56242:5;:16;56238:103;;56288:7;56279:16;;;-1:-1:-1;56324:1:0;56314:11;56238:103;56368:7;56359:5;:16;56355:68;;56406:1;56396:11;56355:68;56451:6;55517:948;-1:-1:-1;;55517:948:0:o;196:250:1:-;281:1;291:113;305:6;302:1;299:13;291:113;;;381:11;;;375:18;362:11;;;355:39;327:2;320:10;291:113;;;-1:-1:-1;;438:1:1;420:16;;413:27;196:250::o;451:271::-;493:3;531:5;525:12;558:6;553:3;546:19;574:76;643:6;636:4;631:3;627:14;620:4;613:5;609:16;574:76;:::i;:::-;704:2;683:15;-1:-1:-1;;679:29:1;670:39;;;;711:4;666:50;;451:271;-1:-1:-1;;451:271:1:o;727:220::-;876:2;865:9;858:21;839:4;896:45;937:2;926:9;922:18;914:6;896:45;:::i;:::-;888:53;727:220;-1:-1:-1;;;727:220:1:o;952:180::-;1011:6;1064:2;1052:9;1043:7;1039:23;1035:32;1032:52;;;1080:1;1077;1070:12;1032:52;-1:-1:-1;1103:23:1;;952:180;-1:-1:-1;952:180:1:o;1527:131::-;-1:-1:-1;;;;;1602:31:1;;1592:42;;1582:70;;1648:1;1645;1638:12;1663:388;1731:6;1739;1792:2;1780:9;1771:7;1767:23;1763:32;1760:52;;;1808:1;1805;1798:12;1760:52;1847:9;1834:23;1866:31;1891:5;1866:31;:::i;:::-;1916:5;-1:-1:-1;1973:2:1;1958:18;;1945:32;1986:33;1945:32;1986:33;:::i;:::-;2038:7;2028:17;;;1663:388;;;;;:::o;2056:824::-;2160:6;2168;2176;2184;2237:2;2225:9;2216:7;2212:23;2208:32;2205:52;;;2253:1;2250;2243:12;2205:52;2293:9;2280:23;2322:18;2363:2;2355:6;2352:14;2349:34;;;2379:1;2376;2369:12;2349:34;2417:6;2406:9;2402:22;2392:32;;2462:7;2455:4;2451:2;2447:13;2443:27;2433:55;;2484:1;2481;2474:12;2433:55;2524:2;2511:16;2550:2;2542:6;2539:14;2536:34;;;2566:1;2563;2556:12;2536:34;2621:7;2614:4;2604:6;2601:1;2597:14;2593:2;2589:23;2585:34;2582:47;2579:67;;;2642:1;2639;2632:12;2579:67;2673:4;2665:13;;;;-1:-1:-1;2697:6:1;-1:-1:-1;;2738:20:1;;2725:34;2768:31;2725:34;2768:31;:::i;:::-;2056:824;;;;-1:-1:-1;2818:5:1;;2870:2;2855:18;2842:32;;-1:-1:-1;;2056:824:1:o;3164:315::-;3232:6;3240;3293:2;3281:9;3272:7;3268:23;3264:32;3261:52;;;3309:1;3306;3299:12;3261:52;3348:9;3335:23;3367:31;3392:5;3367:31;:::i;:::-;3417:5;3469:2;3454:18;;;;3441:32;;-1:-1:-1;;;3164:315:1:o;3484:456::-;3561:6;3569;3577;3630:2;3618:9;3609:7;3605:23;3601:32;3598:52;;;3646:1;3643;3636:12;3598:52;3685:9;3672:23;3704:31;3729:5;3704:31;:::i;:::-;3754:5;-1:-1:-1;3806:2:1;3791:18;;3778:32;;-1:-1:-1;3862:2:1;3847:18;;3834:32;3875:33;3834:32;3875:33;:::i;:::-;3927:7;3917:17;;;3484:456;;;;;:::o;3945:247::-;4004:6;4057:2;4045:9;4036:7;4032:23;4028:32;4025:52;;;4073:1;4070;4063:12;4025:52;4112:9;4099:23;4131:31;4156:5;4131:31;:::i;4389:452::-;4475:6;4483;4491;4499;4552:3;4540:9;4531:7;4527:23;4523:33;4520:53;;;4569:1;4566;4559:12;4520:53;4608:9;4595:23;4627:31;4652:5;4627:31;:::i;:::-;4677:5;4729:2;4714:18;;4701:32;;-1:-1:-1;4780:2:1;4765:18;;4752:32;;4831:2;4816:18;4803:32;;-1:-1:-1;4389:452:1;-1:-1:-1;;;4389:452:1:o;5031:658::-;5202:2;5254:21;;;5324:13;;5227:18;;;5346:22;;;5173:4;;5202:2;5425:15;;;;5399:2;5384:18;;;5173:4;5468:195;5482:6;5479:1;5476:13;5468:195;;;5547:13;;-1:-1:-1;;;;;5543:39:1;5531:52;;5638:15;;;;5603:12;;;;5579:1;5497:9;5468:195;;;-1:-1:-1;5680:3:1;;5031:658;-1:-1:-1;;;;;;5031:658:1:o;5694:383::-;5771:6;5779;5787;5840:2;5828:9;5819:7;5815:23;5811:32;5808:52;;;5856:1;5853;5846:12;5808:52;5895:9;5882:23;5914:31;5939:5;5914:31;:::i;:::-;5964:5;6016:2;6001:18;;5988:32;;-1:-1:-1;6067:2:1;6052:18;;;6039:32;;5694:383;-1:-1:-1;;;5694:383:1:o;6082:315::-;6150:6;6158;6211:2;6199:9;6190:7;6186:23;6182:32;6179:52;;;6227:1;6224;6217:12;6179:52;6263:9;6250:23;6240:33;;6323:2;6312:9;6308:18;6295:32;6336:31;6361:5;6336:31;:::i;6402:248::-;6470:6;6478;6531:2;6519:9;6510:7;6506:23;6502:32;6499:52;;;6547:1;6544;6537:12;6499:52;-1:-1:-1;;6570:23:1;;;6640:2;6625:18;;;6612:32;;-1:-1:-1;6402:248:1:o;6655:127::-;6716:10;6711:3;6707:20;6704:1;6697:31;6747:4;6744:1;6737:15;6771:4;6768:1;6761:15;6787:275;6858:2;6852:9;6923:2;6904:13;;-1:-1:-1;;6900:27:1;6888:40;;6958:18;6943:34;;6979:22;;;6940:62;6937:88;;;7005:18;;:::i;:::-;7041:2;7034:22;6787:275;;-1:-1:-1;6787:275:1:o;7067:187::-;7116:4;7149:18;7141:6;7138:30;7135:56;;;7171:18;;:::i;:::-;-1:-1:-1;7237:2:1;7216:15;-1:-1:-1;;7212:29:1;7243:4;7208:40;;7067:187::o;7259:876::-;7346:6;7354;7362;7415:2;7403:9;7394:7;7390:23;7386:32;7383:52;;;7431:1;7428;7421:12;7383:52;7470:9;7457:23;7489:31;7514:5;7489:31;:::i;:::-;7539:5;-1:-1:-1;7595:2:1;7580:18;;7567:32;7622:18;7611:30;;7608:50;;;7654:1;7651;7644:12;7608:50;7677:22;;7730:4;7722:13;;7718:27;-1:-1:-1;7708:55:1;;7759:1;7756;7749:12;7708:55;7795:2;7782:16;7820:49;7836:32;7865:2;7836:32;:::i;:::-;7820:49;:::i;:::-;7892:2;7885:5;7878:17;7932:7;7927:2;7922;7918;7914:11;7910:20;7907:33;7904:53;;;7953:1;7950;7943:12;7904:53;8008:2;8003;7999;7995:11;7990:2;7983:5;7979:14;7966:45;8052:1;8047:2;8042;8035:5;8031:14;8027:23;8020:34;8073:5;8063:15;;;;;8125:2;8114:9;8110:18;8097:32;8087:42;;7259:876;;;;;:::o;8875:297::-;8993:12;;9040:4;9029:16;;;9023:23;;8993:12;9058:16;;9055:111;;;-1:-1:-1;;9132:4:1;9128:17;;;;9125:1;9121:25;9117:38;9106:50;;8875:297;-1:-1:-1;8875:297:1:o;9364:339::-;9566:2;9548:21;;;9605:2;9585:18;;;9578:30;-1:-1:-1;;;9639:2:1;9624:18;;9617:45;9694:2;9679:18;;9364:339::o;9708:127::-;9769:10;9764:3;9760:20;9757:1;9750:31;9800:4;9797:1;9790:15;9824:4;9821:1;9814:15;9840:127;9901:10;9896:3;9892:20;9889:1;9882:31;9932:4;9929:1;9922:15;9956:4;9953:1;9946:15;9972:135;10011:3;10032:17;;;10029:43;;10052:18;;:::i;:::-;-1:-1:-1;10099:1:1;10088:13;;9972:135::o;10460:251::-;10530:6;10583:2;10571:9;10562:7;10558:23;10554:32;10551:52;;;10599:1;10596;10589:12;10551:52;10631:9;10625:16;10650:31;10675:5;10650:31;:::i;10716:649::-;10796:6;10849:2;10837:9;10828:7;10824:23;10820:32;10817:52;;;10865:1;10862;10855:12;10817:52;10898:9;10892:16;10931:18;10923:6;10920:30;10917:50;;;10963:1;10960;10953:12;10917:50;10986:22;;11039:4;11031:13;;11027:27;-1:-1:-1;11017:55:1;;11068:1;11065;11058:12;11017:55;11097:2;11091:9;11122:49;11138:32;11167:2;11138:32;:::i;11122:49::-;11194:2;11187:5;11180:17;11234:7;11229:2;11224;11220;11216:11;11212:20;11209:33;11206:53;;;11255:1;11252;11245:12;11206:53;11268:67;11332:2;11327;11320:5;11316:14;11311:2;11307;11303:11;11268:67;:::i;11370:289::-;11501:3;11539:6;11533:13;11555:66;11614:6;11609:3;11602:4;11594:6;11590:17;11555:66;:::i;:::-;11637:16;;;;;11370:289;-1:-1:-1;;11370:289:1:o;11664:277::-;11731:6;11784:2;11772:9;11763:7;11759:23;11755:32;11752:52;;;11800:1;11797;11790:12;11752:52;11832:9;11826:16;11885:5;11878:13;11871:21;11864:5;11861:32;11851:60;;11907:1;11904;11897:12;11946:184;12016:6;12069:2;12057:9;12048:7;12044:23;12040:32;12037:52;;;12085:1;12082;12075:12;12037:52;-1:-1:-1;12108:16:1;;11946:184;-1:-1:-1;11946:184:1:o;12477:128::-;12544:9;;;12565:11;;;12562:37;;;12579:18;;:::i;12610:127::-;12671:10;12666:3;12662:20;12659:1;12652:31;12702:4;12699:1;12692:15;12726:4;12723:1;12716:15;13759:800;14140:3;14178:6;14172:13;14194:66;14253:6;14248:3;14241:4;14233:6;14229:17;14194:66;:::i;:::-;-1:-1:-1;;;14282:16:1;;;14307:18;;;14350:13;;14372:78;14350:13;14437:1;14426:13;;14419:4;14407:17;;14372:78;:::i;:::-;-1:-1:-1;;;14513:1:1;14469:20;;;;14505:10;;;14498:29;14551:1;14543:10;;13759:800;-1:-1:-1;;;;13759:800:1:o;14564:771::-;-1:-1:-1;;;14970:3:1;14963:17;14945:3;15009:6;15003:13;15025:74;15092:6;15088:1;15083:3;15079:11;15072:4;15064:6;15060:17;15025:74;:::i;:::-;-1:-1:-1;;;15158:1:1;15118:16;;;15150:10;;;15143:23;15191:13;;15213:75;15191:13;15275:1;15267:10;;15260:4;15248:17;;15213:75;:::i;:::-;15308:17;15327:1;15304:25;;14564:771;-1:-1:-1;;;;14564:771:1:o;15340:655::-;15584:4;15630:1;15626;15621:3;15617:11;15613:19;15671:2;15663:6;15659:15;15648:9;15641:34;15711:3;15706:2;15695:9;15691:18;15684:31;15738:46;15779:3;15768:9;15764:19;15756:6;15738:46;:::i;:::-;15832:9;15824:6;15820:22;15815:2;15804:9;15800:18;15793:50;15860:33;15886:6;15878;15860:33;:::i;:::-;15929:15;;;;15924:2;15909:18;;15902:43;-1:-1:-1;;15976:3:1;15961:19;15954:35;15852:41;15340:655;-1:-1:-1;;;15340:655:1:o
Swarm Source
ipfs://4f62da56a9b8cd75182336b57a2a001fdacade7867d92e13340daa5b26142536
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.