Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 6 from a total of 6 transactions
Latest 18 internal transactions
Advanced mode:
Parent Transaction Hash | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|
21886988 | 11 days ago | Contract Creation | 0 ETH | |||
21886988 | 11 days ago | Contract Creation | 0 ETH | |||
21886988 | 11 days ago | Contract Creation | 0 ETH | |||
21886987 | 11 days ago | Contract Creation | 0 ETH | |||
21886987 | 11 days ago | Contract Creation | 0 ETH | |||
21886987 | 11 days ago | Contract Creation | 0 ETH | |||
21886986 | 11 days ago | Contract Creation | 0 ETH | |||
21886986 | 11 days ago | Contract Creation | 0 ETH | |||
21886986 | 11 days ago | Contract Creation | 0 ETH | |||
21886985 | 11 days ago | Contract Creation | 0 ETH | |||
21886985 | 11 days ago | Contract Creation | 0 ETH | |||
21886985 | 11 days ago | Contract Creation | 0 ETH | |||
21886984 | 11 days ago | Contract Creation | 0 ETH | |||
21886984 | 11 days ago | Contract Creation | 0 ETH | |||
21886984 | 11 days ago | Contract Creation | 0 ETH | |||
21886983 | 11 days ago | Contract Creation | 0 ETH | |||
21886983 | 11 days ago | Contract Creation | 0 ETH | |||
21886983 | 11 days ago | Contract Creation | 0 ETH |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Source Code Verified (Exact Match)
Contract Name:
MultiVaultDeployScript
Compiler Version
v0.8.25+commit.b61c2a91
Optimization Enabled:
Yes with 200 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.25; import "../../src/adapters/SymbioticAdapter.sol"; import "../../src/strategies/RatiosStrategy.sol"; import "../../src/vaults/MultiVault.sol"; import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; contract MultiVaultDeployScript { address public immutable symbioticVaultFactory; RatiosStrategy public immutable strategy; address public immutable multiVaultImplementation; address public immutable symbioticWithdrawalQueueImplementation; constructor( address symbioticVaultFactory_, address strategy_, address multiVaultImplementation_, address symbioticWithdrawalQueueImplementation_ ) { symbioticVaultFactory = symbioticVaultFactory_; strategy = RatiosStrategy(strategy_); multiVaultImplementation = multiVaultImplementation_; symbioticWithdrawalQueueImplementation = symbioticWithdrawalQueueImplementation_; } struct DeployParams { // actors address admin; address proxyAdmin; address curator; // external contracts address symbioticVault; address depositWrapper; address asset; address defaultCollateral; // vault setup uint256 limit; bool depositPause; bool withdrawalPause; string name; string symbol; // strategy setup uint64 minRatioD18; uint64 maxRatioD18; // salt bytes32 salt; } struct Deployment { address multiVault; address symbioticAdapter; DeployParams params; } mapping(bytes32 salt => Deployment) private _deployments; function calculateSalt(DeployParams calldata params) public pure returns (bytes32) { return keccak256(abi.encode(params)); } function deployments(bytes32 salt) public view returns (Deployment memory) { return _deployments[salt]; } function deploy(DeployParams calldata params) external returns (MultiVault multiVault, address symbioticAdapter, DeployParams memory) { bytes32 salt = calculateSalt(params); multiVault = MultiVault( address( new TransparentUpgradeableProxy{salt: salt}( multiVaultImplementation, params.proxyAdmin, new bytes(0) ) ) ); address symbioticAdapterImplementation = address( new SymbioticAdapter{salt: salt}( address(multiVault), symbioticVaultFactory, symbioticWithdrawalQueueImplementation, params.proxyAdmin ) ); symbioticAdapter = address( new TransparentUpgradeableProxy{salt: salt}( symbioticAdapterImplementation, params.proxyAdmin, new bytes(0) ) ); IMultiVault.InitParams memory initParams = IMultiVault.InitParams({ admin: address(this), limit: params.limit, depositPause: params.depositPause, withdrawalPause: params.withdrawalPause, depositWhitelist: params.depositWrapper != address(0), asset: params.asset, name: params.name, symbol: params.symbol, depositStrategy: address(strategy), withdrawalStrategy: address(strategy), rebalanceStrategy: address(strategy), defaultCollateral: params.defaultCollateral, symbioticAdapter: symbioticAdapter, eigenLayerAdapter: address(0), erc4626Adapter: address(0) }); multiVault.initialize(initParams); if (params.depositWrapper != address(0)) { bytes32 SET_DEPOSITOR_WHITELIST_STATUS_ROLE = keccak256("SET_DEPOSITOR_WHITELIST_STATUS_ROLE"); multiVault.grantRole(SET_DEPOSITOR_WHITELIST_STATUS_ROLE, address(this)); multiVault.setDepositorWhitelistStatus(params.depositWrapper, true); multiVault.renounceRole(SET_DEPOSITOR_WHITELIST_STATUS_ROLE, address(this)); } // admin roles multiVault.grantRole(multiVault.DEFAULT_ADMIN_ROLE(), params.admin); multiVault.grantRole(multiVault.SET_FARM_ROLE(), params.admin); // curator roles multiVault.grantRole(multiVault.REBALANCE_ROLE(), params.curator); multiVault.grantRole(multiVault.ADD_SUBVAULT_ROLE(), params.curator); multiVault.grantRole(keccak256("SET_LIMIT_ROLE"), params.curator); multiVault.grantRole(strategy.RATIOS_STRATEGY_SET_RATIOS_ROLE(), params.curator); if (params.symbioticVault != address(0)) { multiVault.grantRole(strategy.RATIOS_STRATEGY_SET_RATIOS_ROLE(), address(this)); multiVault.grantRole(multiVault.ADD_SUBVAULT_ROLE(), address(this)); multiVault.addSubvault(params.symbioticVault, IMultiVaultStorage.Protocol.SYMBIOTIC); address[] memory subvaults = new address[](1); subvaults[0] = address(params.symbioticVault); IRatiosStrategy.Ratio[] memory ratios_ = new IRatiosStrategy.Ratio[](1); ratios_[0] = IRatiosStrategy.Ratio(params.minRatioD18, params.maxRatioD18); strategy.setRatios(address(multiVault), subvaults, ratios_); multiVault.renounceRole(strategy.RATIOS_STRATEGY_SET_RATIOS_ROLE(), address(this)); multiVault.renounceRole(multiVault.ADD_SUBVAULT_ROLE(), address(this)); multiVault.renounceRole(multiVault.DEFAULT_ADMIN_ROLE(), address(this)); } emit Deployed(address(multiVault), symbioticAdapter, salt, params); _deployments[salt] = Deployment(address(multiVault), symbioticAdapter, params); return (multiVault, symbioticAdapter, params); } event Deployed( address indexed multiVault, address indexed symbioticAdapter, bytes32 indexed salt, DeployParams deployParams ); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.25; import "../interfaces/adapters/ISymbioticAdapter.sol"; import {SymbioticWithdrawalQueue} from "../queues/SymbioticWithdrawalQueue.sol"; contract SymbioticAdapter is ISymbioticAdapter { using SafeERC20 for IERC20; /// @inheritdoc IProtocolAdapter address public immutable vault; /// @inheritdoc ISymbioticAdapter IRegistry public immutable vaultFactory; address public immutable withdrawalQueueSingleton; address public immutable proxyAdmin; /// @inheritdoc ISymbioticAdapter mapping(address symbioticVault => address withdrawalQueue) public withdrawalQueues; constructor( address vault_, address vaultFactory_, address withdrawalQueueSingleton_, address proxyAdmin_ ) { vault = vault_; vaultFactory = IRegistry(vaultFactory_); withdrawalQueueSingleton = withdrawalQueueSingleton_; proxyAdmin = proxyAdmin_; } /// @inheritdoc IProtocolAdapter function maxDeposit(address symbioticVault) external view returns (uint256) { ISymbioticVault vault_ = ISymbioticVault(symbioticVault); if (vault_.depositWhitelist() && !vault_.isDepositorWhitelisted(vault)) { return 0; } if (!vault_.isDepositLimit()) { return type(uint256).max; } uint256 activeStake = vault_.activeStake(); uint256 limit = vault_.depositLimit(); if (limit > activeStake) { return limit - activeStake; } return 0; } /// @inheritdoc IProtocolAdapter function assetOf(address symbioticVault) external view returns (address) { return ISymbioticVault(symbioticVault).collateral(); } /// @inheritdoc IProtocolAdapter function stakedAt(address symbioticVault) external view returns (uint256) { return ISymbioticVault(symbioticVault).activeBalanceOf(vault); } /// @inheritdoc IProtocolAdapter function handleVault(address symbioticVault) external returns (address withdrawalQueue) { require(msg.sender == vault, "SymbioticAdapter: only vault"); withdrawalQueue = withdrawalQueues[symbioticVault]; if (withdrawalQueue != address(0)) { return withdrawalQueue; } require(vaultFactory.isEntity(symbioticVault), "SymbioticAdapter: invalid symbiotic vault"); withdrawalQueue = address( new TransparentUpgradeableProxy{salt: keccak256(abi.encodePacked(symbioticVault))}( withdrawalQueueSingleton, proxyAdmin, abi.encodeCall(SymbioticWithdrawalQueue.initialize, (vault, symbioticVault)) ) ); withdrawalQueues[symbioticVault] = withdrawalQueue; } /// @inheritdoc IProtocolAdapter function validateRewardData(bytes calldata data) external pure { require(data.length == 32, "SymbioticAdapter: invalid reward data"); address symbioticFarm = abi.decode(data, (address)); require(symbioticFarm != address(0), "SymbioticAdapter: invalid reward data"); } /// @inheritdoc IProtocolAdapter function pushRewards(address rewardToken, bytes calldata farmData, bytes memory rewardData) external { require(address(this) == vault, "SymbioticAdapter: delegate call only"); address symbioticFarm = abi.decode(rewardData, (address)); IStakerRewards(symbioticFarm).claimRewards(vault, address(rewardToken), farmData); } /// @inheritdoc IProtocolAdapter function withdraw( address symbioticVault, address withdrawalQueue, address receiver, uint256 request, address /* owner */ ) external { require(address(this) == vault, "SymbioticAdapter: delegate call only"); (, uint256 requestedShares) = ISymbioticVault(symbioticVault).withdraw(withdrawalQueue, request); ISymbioticWithdrawalQueue(withdrawalQueue).request(receiver, requestedShares); } /// @inheritdoc IProtocolAdapter function deposit(address symbioticVault, uint256 assets) external { require(address(this) == vault, "SymbioticAdapter: delegate call only"); IERC20(IERC4626(vault).asset()).safeIncreaseAllowance(symbioticVault, assets); ISymbioticVault(symbioticVault).deposit(vault, assets); } /// @inheritdoc IProtocolAdapter function areWithdrawalsPaused(address, /* symbioticVault */ address /* account */ ) external view returns (bool) {} }
// // SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.25; import "../interfaces/strategies/IRatiosStrategy.sol"; contract RatiosStrategy is IRatiosStrategy { /// @inheritdoc IRatiosStrategy uint256 public constant D18 = 1e18; /// @inheritdoc IRatiosStrategy bytes32 public constant RATIOS_STRATEGY_SET_RATIOS_ROLE = keccak256("RATIOS_STRATEGY_SET_RATIOS_ROLE"); /// @inheritdoc IRatiosStrategy mapping(address vault => mapping(address subvault => Ratio)) public ratios; /// @inheritdoc IRatiosStrategy function setRatios(address vault, address[] calldata subvaults, Ratio[] calldata ratios_) external { require( IAccessControl(vault).hasRole(RATIOS_STRATEGY_SET_RATIOS_ROLE, msg.sender), "RatiosStrategy: forbidden" ); require( subvaults.length == ratios_.length, "RatiosStrategy: subvaults and ratios length mismatch" ); IMultiVault multiVault = IMultiVault(vault); uint256 n = subvaults.length; for (uint256 i = 0; i < n; i++) { if (multiVault.indexOfSubvault(subvaults[i]) != 0) { require( ratios_[i].minRatioD18 <= ratios_[i].maxRatioD18 && ratios_[i].maxRatioD18 <= D18, "RatiosStrategy: invalid ratios" ); } else { require( ratios_[i].minRatioD18 == 0 && ratios_[i].maxRatioD18 == 0, "RatiosStrategy: invalid subvault" ); } } mapping(address => Ratio) storage vaultRatios_ = ratios[vault]; for (uint256 i = 0; i < n; i++) { vaultRatios_[subvaults[i]] = ratios_[i]; } emit RatiosSet(vault, subvaults, ratios_); } /// @inheritdoc IRatiosStrategy function calculateState(address vault, bool isDeposit, uint256 increment) public view returns (Amounts[] memory state, uint256 liquid) { IMultiVault multiVault = IMultiVault(vault); uint256 n = multiVault.subvaultsCount(); state = new Amounts[](n); liquid = IERC20(IERC4626(vault).asset()).balanceOf(vault); IDefaultCollateral collateral = multiVault.defaultCollateral(); if (address(collateral) != address(0)) { liquid += collateral.balanceOf(vault); } uint256 totalAssets = liquid; IMultiVaultStorage.Subvault memory subvault; for (uint256 i = 0; i < n; i++) { subvault = multiVault.subvaultAt(i); IProtocolAdapter adapter = multiVault.adapterOf(subvault.protocol); state[i].staked = adapter.stakedAt(subvault.vault); if (!isDeposit && adapter.areWithdrawalsPaused(subvault.vault, vault)) { revert("RatiosStrategy: withdrawals paused"); } if (subvault.withdrawalQueue != address(0)) { state[i].claimable = IWithdrawalQueue(subvault.withdrawalQueue).claimableAssetsOf(vault); state[i].pending = IWithdrawalQueue(subvault.withdrawalQueue).pendingAssetsOf(vault); totalAssets += state[i].staked + state[i].pending + state[i].claimable; } else { totalAssets += state[i].staked; } uint256 maxDeposit = adapter.maxDeposit(subvault.vault); if (type(uint256).max - state[i].staked > maxDeposit) { state[i].max = maxDeposit + state[i].staked; } else { state[i].max = type(uint256).max; } } totalAssets = isDeposit ? totalAssets + increment : totalAssets - increment; mapping(address => Ratio) storage vaultRatios_ = ratios[vault]; for (uint256 i = 0; i < n; i++) { Ratio memory ratio = vaultRatios_[multiVault.subvaultAt(i).vault]; if (ratio.maxRatioD18 == 0) { state[i].max = 0; state[i].min = 0; } else { state[i].max = Math.min(state[i].max, (totalAssets * ratio.maxRatioD18) / D18); state[i].min = Math.min(state[i].max, (totalAssets * ratio.minRatioD18) / D18); } } } /// @inheritdoc IDepositStrategy function calculateDepositAmounts(address vault, uint256 amount) external view override returns (DepositData[] memory data) { (Amounts[] memory state,) = calculateState(vault, true, amount); uint256 n = state.length; for (uint256 i = 0; i < n; i++) { uint256 assets_ = state[i].staked; if (state[i].min > assets_) { state[i].min -= assets_; state[i].max -= assets_; } else if (state[i].max > assets_) { state[i].min = 0; state[i].max -= assets_; } else { state[i].min = 0; state[i].max = 0; } } data = new DepositData[](n); for (uint256 i = 0; i < n && amount != 0; i++) { data[i].subvaultIndex = i; if (state[i].min == 0) { continue; } uint256 assets_ = Math.min(state[i].min, amount); state[i].max -= assets_; amount -= assets_; data[i].deposit = assets_; } for (uint256 i = 0; i < n && amount != 0; i++) { if (state[i].max == 0) { continue; } uint256 assets_ = Math.min(state[i].max, amount); amount -= assets_; data[i].deposit += assets_; } uint256 count = 0; for (uint256 i = 0; i < n; i++) { if (data[i].deposit != 0) { if (count != i) { data[count] = data[i]; } count++; } } assembly { mstore(data, count) } } /// @inheritdoc IWithdrawalStrategy function calculateWithdrawalAmounts(address vault, uint256 amount) external view override returns (WithdrawalData[] memory data) { (Amounts[] memory state, uint256 liquid) = calculateState(vault, false, amount); if (amount <= liquid) { return data; } amount -= liquid; uint256 n = state.length; data = new WithdrawalData[](n); for (uint256 i = 0; i < n && amount != 0; i++) { data[i].subvaultIndex = i; if (state[i].staked > state[i].max) { uint256 extra = state[i].staked - state[i].max; if (extra > amount) { data[i].staked = amount; amount = 0; } else { data[i].staked = extra; amount -= extra; } state[i].staked -= data[i].staked; } } for (uint256 i = 0; i < n && amount != 0; i++) { if (state[i].staked > state[i].min) { uint256 allowed = state[i].staked - state[i].min; if (allowed > amount) { data[i].staked += amount; amount = 0; } else { data[i].staked += allowed; amount -= allowed; state[i].staked -= allowed; } } } for (uint256 i = 0; i < n && amount != 0; i++) { if (state[i].pending > 0) { if (state[i].pending > amount) { data[i].pending += amount; amount = 0; } else { data[i].pending += state[i].pending; amount -= state[i].pending; } } } for (uint256 i = 0; i < n && amount != 0; i++) { if (state[i].claimable > 0) { if (state[i].claimable > amount) { data[i].claimable += amount; amount = 0; } else { data[i].claimable += state[i].claimable; amount -= state[i].claimable; } } } for (uint256 i = 0; i < n && amount != 0; i++) { uint256 staked = state[i].staked; if (staked > 0) { if (staked > amount) { data[i].staked += amount; amount = 0; } else { data[i].staked += staked; amount -= staked; } } } uint256 count = 0; for (uint256 i = 0; i < n; i++) { if (data[i].staked + data[i].pending + data[i].claimable != 0) { if (count != i) { data[count] = data[i]; } count++; } } assembly { mstore(data, count) } } /// @inheritdoc IRebalanceStrategy function calculateRebalanceAmounts(address vault) external view override returns (RebalanceData[] memory data) { (Amounts[] memory state, uint256 liquid) = calculateState(vault, false, 0); uint256 n = state.length; data = new RebalanceData[](n); uint256 totalRequired = 0; uint256 pending = 0; for (uint256 i = 0; i < n; i++) { data[i].subvaultIndex = i; data[i].claimable = state[i].claimable; liquid += state[i].claimable; pending += state[i].pending; if (state[i].staked > state[i].max) { data[i].staked = state[i].staked - state[i].max; pending += data[i].staked; state[i].staked = state[i].max; } if (state[i].min > state[i].staked) { totalRequired += state[i].min - state[i].staked; } } if (totalRequired > liquid + pending) { uint256 unstake = totalRequired - liquid - pending; for (uint256 i = 0; i < n && unstake > 0; i++) { if (state[i].staked > state[i].min) { uint256 allowed = state[i].staked - state[i].min; if (allowed > unstake) { data[i].staked += unstake; unstake = 0; } else { data[i].staked += allowed; unstake -= allowed; } } } } for (uint256 i = 0; i < n && liquid > 0; i++) { if (state[i].staked < state[i].min) { uint256 required = state[i].min - state[i].staked; if (required > liquid) { data[i].deposit = liquid; liquid = 0; } else { data[i].deposit = required; liquid -= required; state[i].max -= data[i].deposit; } } } for (uint256 i = 0; i < n && liquid > 0; i++) { if (state[i].staked < state[i].max) { uint256 allowed = state[i].max - state[i].staked; if (allowed > liquid) { data[i].deposit += liquid; liquid = 0; } else { data[i].deposit += allowed; liquid -= allowed; } } } } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.25; import "../interfaces/vaults/IMultiVault.sol"; import {ERC4626Vault} from "./ERC4626Vault.sol"; import {MultiVaultStorage} from "./MultiVaultStorage.sol"; import {VaultControlStorage} from "./VaultControlStorage.sol"; contract MultiVault is IMultiVault, ERC4626Vault, MultiVaultStorage { using SafeERC20 for IERC20; using Math for uint256; uint256 private constant D6 = 1e6; bytes32 public constant ADD_SUBVAULT_ROLE = keccak256("ADD_SUBVAULT_ROLE"); bytes32 public constant REMOVE_SUBVAULT_ROLE = keccak256("REMOVE_SUBVAULT_ROLE"); bytes32 public constant SET_STRATEGY_ROLE = keccak256("SET_STRATEGY_ROLE"); bytes32 public constant SET_FARM_ROLE = keccak256("SET_FARM_ROLE"); bytes32 public constant REBALANCE_ROLE = keccak256("REBALANCE_ROLE"); bytes32 public constant SET_DEFAULT_COLLATERAL_ROLE = keccak256("SET_DEFAULT_COLLATERAL_ROLE"); bytes32 public constant SET_ADAPTER_ROLE = keccak256("SET_ADAPTER_ROLE"); constructor(bytes32 name_, uint256 version_) VaultControlStorage(name_, version_) MultiVaultStorage(name_, version_) { _disableInitializers(); } // ------------------------------- EXTERNAL VIEW FUNCTIONS ------------------------------- /// @inheritdoc IERC4626 function totalAssets() public view virtual override(IERC4626, ERC4626Upgradeable) returns (uint256 assets_) { address this_ = address(this); assets_ = IERC20(asset()).balanceOf(this_); IDefaultCollateral collateral = defaultCollateral(); if (address(collateral) != address(0)) { assets_ += collateral.balanceOf(this_); } uint256 length = subvaultsCount(); Subvault memory subvault; for (uint256 i = 0; i < length; i++) { subvault = subvaultAt(i); assets_ += adapterOf(subvault.protocol).stakedAt(subvault.vault); if (subvault.withdrawalQueue != address(0)) { assets_ += IWithdrawalQueue(subvault.withdrawalQueue).claimableAssetsOf(this_) + IWithdrawalQueue(subvault.withdrawalQueue).pendingAssetsOf(this_); } } } // ------------------------------- EXTERNAL MUTATIVE FUNCTIONS ------------------------------- /// @inheritdoc IMultiVault function initialize(InitParams calldata initParams) public virtual reinitializer(2) { __initializeERC4626( initParams.admin, initParams.limit, initParams.depositPause, initParams.withdrawalPause, initParams.depositWhitelist, initParams.asset, initParams.name, initParams.symbol ); __initializeMultiVaultStorage( initParams.depositStrategy, initParams.withdrawalStrategy, initParams.rebalanceStrategy, initParams.defaultCollateral, initParams.symbioticAdapter, initParams.eigenLayerAdapter, initParams.erc4626Adapter ); require( initParams.defaultCollateral == address(0) || IDefaultCollateral(initParams.defaultCollateral).asset() == initParams.asset, "MultiVault: default collateral asset does not match the vault asset" ); } /// @inheritdoc IMultiVault function addSubvault(address vault, Protocol protocol) external onlyRole(ADD_SUBVAULT_ROLE) { IProtocolAdapter adapter = adapterOf(protocol); require( adapter.assetOf(vault) == asset(), "MultiVault: subvault asset does not match the vault asset" ); _addSubvault(vault, adapter.handleVault(vault), protocol); } /// @inheritdoc IMultiVault function removeSubvault(address subvault) external onlyRole(REMOVE_SUBVAULT_ROLE) { _removeSubvault(subvault); } /// @inheritdoc IMultiVault function setDepositStrategy(address newDepositStrategy) external onlyRole(SET_STRATEGY_ROLE) { require( newDepositStrategy != address(0), "MultiVault: deposit strategy cannot be zero address" ); _setDepositStrategy(newDepositStrategy); } /// @inheritdoc IMultiVault function setWithdrawalStrategy(address newWithdrawalStrategy) external onlyRole(SET_STRATEGY_ROLE) { require( newWithdrawalStrategy != address(0), "MultiVault: withdrawal strategy cannot be zero address" ); _setWithdrawalStrategy(newWithdrawalStrategy); } /// @inheritdoc IMultiVault function setRebalanceStrategy(address newRebalanceStrategy) external onlyRole(SET_STRATEGY_ROLE) { require( newRebalanceStrategy != address(0), "MultiVault: rebalance strategy cannot be zero address" ); _setRebalanceStrategy(newRebalanceStrategy); } /// @inheritdoc IMultiVault function setDefaultCollateral(address defaultCollateral_) external onlyRole(SET_DEFAULT_COLLATERAL_ROLE) { require( address(defaultCollateral()) == address(0) && defaultCollateral_ != address(0), "MultiVault: default collateral already set or cannot be zero address" ); require( IDefaultCollateral(defaultCollateral_).asset() == asset(), "MultiVault: default collateral asset does not match the vault asset" ); _setDefaultCollateral(defaultCollateral_); } /// @inheritdoc IMultiVault function setSymbioticAdapter(address adapter_) external onlyRole(SET_ADAPTER_ROLE) { require(adapter_ != address(0), "MultiVault: adapter cannot be zero address"); _setSymbioticAdapter(adapter_); } /// @inheritdoc IMultiVault function setEigenLayerAdapter(address adapter_) external onlyRole(SET_ADAPTER_ROLE) { require(adapter_ != address(0), "MultiVault: adapter cannot be zero address"); _setEigenLayerAdapter(adapter_); } /// @inheritdoc IMultiVault function setERC4626Adapter(address adapter_) external onlyRole(SET_ADAPTER_ROLE) { require(adapter_ != address(0), "MultiVault: adapter cannot be zero address"); _setERC4626Adapter(adapter_); } /// @inheritdoc IMultiVault function setRewardsData(uint256 farmId, RewardData calldata rewardData) external onlyRole(SET_FARM_ROLE) { if (rewardData.token != address(0)) { require( rewardData.token != asset() && rewardData.token != address(defaultCollateral()), "MultiVault: reward token cannot be the same as the asset or default collateral" ); require(rewardData.curatorFeeD6 <= D6, "MultiVault: curator fee exceeds 100%"); require( rewardData.distributionFarm != address(0), "MultiVault: distribution farm address cannot be zero" ); if (rewardData.curatorFeeD6 != 0) { require( rewardData.curatorTreasury != address(0), "MultiVault: curator treasury address cannot be zero when fee is set" ); } adapterOf(rewardData.protocol).validateRewardData(rewardData.data); } _setRewardData(farmId, rewardData); } /// @inheritdoc IMultiVault function rebalance() external onlyRole(REBALANCE_ROLE) { address this_ = address(this); IRebalanceStrategy.RebalanceData[] memory data = rebalanceStrategy().calculateRebalanceAmounts(this_); for (uint256 i = 0; i < data.length; i++) { _withdraw(data[i].subvaultIndex, data[i].staked, 0, data[i].claimable, this_, this_); } IDefaultCollateral collateral = defaultCollateral(); if (address(collateral) != address(0)) { uint256 balance = collateral.balanceOf(this_); if (balance != 0) { collateral.withdraw(this_, balance); } } for (uint256 i = 0; i < data.length; i++) { _deposit(data[i].subvaultIndex, data[i].deposit); } _depositIntoCollateral(); emit Rebalance(data, block.timestamp); } /// @inheritdoc IMultiVault function pushRewards(uint256 farmId, bytes calldata farmData) external nonReentrant { require(farmIdsContains(farmId), "MultiVault: farm not found"); IMultiVaultStorage.RewardData memory data = rewardData(farmId); IERC20 rewardToken = IERC20(data.token); address this_ = address(this); uint256 rewardAmount = rewardToken.balanceOf(this_); Address.functionDelegateCall( address(adapterOf(data.protocol)), abi.encodeCall( IProtocolAdapter.pushRewards, (address(rewardToken), farmData, data.data) ) ); rewardAmount = rewardToken.balanceOf(this_) - rewardAmount; if (rewardAmount == 0) { return; } uint256 curatorFee = rewardAmount.mulDiv(data.curatorFeeD6, D6); if (curatorFee != 0) { rewardToken.safeTransfer(data.curatorTreasury, curatorFee); } rewardAmount = rewardAmount - curatorFee; if (rewardAmount != 0) { rewardToken.safeTransfer(data.distributionFarm, rewardAmount); } emit RewardsPushed(farmId, rewardAmount, curatorFee, block.timestamp); } // ------------------------------- INTERNAL MUTATIVE FUNCTIONS ------------------------------- /// @dev Deposits assets into the specified subvault function _deposit(uint256 subvaultIndex, uint256 assets) private { if (assets == 0) { return; } Subvault memory subvault = subvaultAt(subvaultIndex); Address.functionDelegateCall( address(adapterOf(subvault.protocol)), abi.encodeCall(IProtocolAdapter.deposit, (subvault.vault, assets)) ); } /// @dev Withdraws assets from the specified subvault function _withdraw( uint256 subvaultIndex, uint256 request, uint256 pending, uint256 claimable, address owner, address receiver ) private { Subvault memory subvault = subvaultAt(subvaultIndex); address this_ = address(this); if (claimable != 0) { IWithdrawalQueue(subvault.withdrawalQueue).claim(this_, receiver, claimable); } if (pending != 0) { IWithdrawalQueue(subvault.withdrawalQueue).transferPendingAssets(receiver, pending); } if (request != 0) { Address.functionDelegateCall( address(adapterOf(subvault.protocol)), abi.encodeCall( IProtocolAdapter.withdraw, (subvault.vault, subvault.withdrawalQueue, receiver, request, owner) ) ); } } /// @dev Deposits assets into the default collateral function _depositIntoCollateral() private { IDefaultCollateral collateral = defaultCollateral(); if (address(collateral) == address(0)) { return; } uint256 limit_ = collateral.limit(); uint256 supply_ = collateral.totalSupply(); if (supply_ >= limit_) { return; } address this_ = address(this); IERC20 asset_ = IERC20(asset()); uint256 assets = asset_.balanceOf(this_).min(limit_ - supply_); if (assets == 0) { return; } asset_.safeIncreaseAllowance(address(collateral), assets); collateral.deposit(this_, assets); emit DepositIntoCollateral(assets); } function _deposit(address caller, address receiver, uint256 assets, uint256 shares) internal virtual override { address this_ = address(this); IDepositStrategy.DepositData[] memory data = depositStrategy().calculateDepositAmounts(this_, assets); super._deposit(caller, receiver, assets, shares); for (uint256 i = 0; i < data.length; i++) { if (data[i].deposit != 0) { _deposit(data[i].subvaultIndex, data[i].deposit); assets -= data[i].deposit; } } _depositIntoCollateral(); } function _withdraw( address caller, address receiver, address owner, uint256 assets, uint256 shares ) internal virtual override { address this_ = address(this); IWithdrawalStrategy.WithdrawalData[] memory data = withdrawalStrategy().calculateWithdrawalAmounts(this_, assets); if (caller != owner) { _spendAllowance(owner, caller, shares); } _burn(owner, shares); uint256 liquid = assets; IWithdrawalStrategy.WithdrawalData memory d; for (uint256 i = 0; i < data.length; i++) { d = data[i]; _withdraw(d.subvaultIndex, d.staked, d.pending, d.claimable, owner, receiver); liquid -= d.staked + d.pending + d.claimable; } if (liquid != 0) { IERC20 asset_ = IERC20(asset()); uint256 balance = asset_.balanceOf(this_); if (balance < liquid) { if (balance != 0) { asset_.safeTransfer(receiver, balance); liquid -= balance; } defaultCollateral().withdraw(receiver, liquid); } else { asset_.safeTransfer(receiver, liquid); } } // emitting event with transferred + new pending assets emit Withdraw(caller, receiver, owner, assets, shares); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/transparent/TransparentUpgradeableProxy.sol) pragma solidity ^0.8.20; import {ERC1967Utils} from "../ERC1967/ERC1967Utils.sol"; import {ERC1967Proxy} from "../ERC1967/ERC1967Proxy.sol"; import {IERC1967} from "../../interfaces/IERC1967.sol"; import {ProxyAdmin} from "./ProxyAdmin.sol"; /** * @dev Interface for {TransparentUpgradeableProxy}. In order to implement transparency, {TransparentUpgradeableProxy} * does not implement this interface directly, and its upgradeability mechanism is implemented by an internal dispatch * mechanism. The compiler is unaware that these functions are implemented by {TransparentUpgradeableProxy} and will not * include them in the ABI so this interface must be used to interact with it. */ interface ITransparentUpgradeableProxy is IERC1967 { function upgradeToAndCall(address, bytes calldata) external payable; } /** * @dev This contract implements a proxy that is upgradeable through an associated {ProxyAdmin} instance. * * To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector * clashing], which can potentially be used in an attack, this contract uses the * https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two * things that go hand in hand: * * 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if * that call matches the {ITransparentUpgradeableProxy-upgradeToAndCall} function exposed by the proxy itself. * 2. If the admin calls the proxy, it can call the `upgradeToAndCall` function but any other call won't be forwarded to * the implementation. If the admin tries to call a function on the implementation it will fail with an error indicating * the proxy admin cannot fallback to the target implementation. * * These properties mean that the admin account can only be used for upgrading the proxy, so it's best if it's a * dedicated account that is not used for anything else. This will avoid headaches due to sudden errors when trying to * call a function from the proxy implementation. For this reason, the proxy deploys an instance of {ProxyAdmin} and * allows upgrades only if they come through it. You should think of the `ProxyAdmin` instance as the administrative * interface of the proxy, including the ability to change who can trigger upgrades by transferring ownership. * * NOTE: The real interface of this proxy is that defined in `ITransparentUpgradeableProxy`. This contract does not * inherit from that interface, and instead `upgradeToAndCall` is implicitly implemented using a custom dispatch * mechanism in `_fallback`. Consequently, the compiler will not produce an ABI for this contract. This is necessary to * fully implement transparency without decoding reverts caused by selector clashes between the proxy and the * implementation. * * NOTE: This proxy does not inherit from {Context} deliberately. The {ProxyAdmin} of this contract won't send a * meta-transaction in any way, and any other meta-transaction setup should be made in the implementation contract. * * IMPORTANT: This contract avoids unnecessary storage reads by setting the admin only during construction as an * immutable variable, preventing any changes thereafter. However, the admin slot defined in ERC-1967 can still be * overwritten by the implementation logic pointed to by this proxy. In such cases, the contract may end up in an * undesirable state where the admin slot is different from the actual admin. * * WARNING: It is not recommended to extend this contract to add additional external functions. If you do so, the * compiler will not check that there are no selector conflicts, due to the note above. A selector clash between any new * function and the functions declared in {ITransparentUpgradeableProxy} will be resolved in favor of the new one. This * could render the `upgradeToAndCall` function inaccessible, preventing upgradeability and compromising transparency. */ contract TransparentUpgradeableProxy is ERC1967Proxy { // An immutable address for the admin to avoid unnecessary SLOADs before each call // at the expense of removing the ability to change the admin once it's set. // This is acceptable if the admin is always a ProxyAdmin instance or similar contract // with its own ability to transfer the permissions to another account. address private immutable _admin; /** * @dev The proxy caller is the current admin, and can't fallback to the proxy target. */ error ProxyDeniedAdminAccess(); /** * @dev Initializes an upgradeable proxy managed by an instance of a {ProxyAdmin} with an `initialOwner`, * backed by the implementation at `_logic`, and optionally initialized with `_data` as explained in * {ERC1967Proxy-constructor}. */ constructor(address _logic, address initialOwner, bytes memory _data) payable ERC1967Proxy(_logic, _data) { _admin = address(new ProxyAdmin(initialOwner)); // Set the storage value and emit an event for ERC-1967 compatibility ERC1967Utils.changeAdmin(_proxyAdmin()); } /** * @dev Returns the admin of this proxy. */ function _proxyAdmin() internal virtual returns (address) { return _admin; } /** * @dev If caller is the admin process the call internally, otherwise transparently fallback to the proxy behavior. */ function _fallback() internal virtual override { if (msg.sender == _proxyAdmin()) { if (msg.sig != ITransparentUpgradeableProxy.upgradeToAndCall.selector) { revert ProxyDeniedAdminAccess(); } else { _dispatchUpgradeToAndCall(); } } else { super._fallback(); } } /** * @dev Upgrade the implementation of the proxy. See {ERC1967Utils-upgradeToAndCall}. * * Requirements: * * - If `data` is empty, `msg.value` must be zero. */ function _dispatchUpgradeToAndCall() private { (address newImplementation, bytes memory data) = abi.decode(msg.data[4:], (address, bytes)); ERC1967Utils.upgradeToAndCall(newImplementation, data); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.25; import {ISymbioticWithdrawalQueue} from "../queues/ISymbioticWithdrawalQueue.sol"; import {IProtocolAdapter} from "./IProtocolAdapter.sol"; import {IERC20, IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol"; import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {IRegistry} from "@symbiotic/core/interfaces/common/IRegistry.sol"; import {IVault as ISymbioticVault} from "@symbiotic/core/interfaces/vault/IVault.sol"; import {IStakerRewards} from "@symbiotic/rewards/interfaces/stakerRewards/IStakerRewards.sol"; interface ISymbioticAdapter is IProtocolAdapter { function withdrawalQueues(address symbioticVault) external view returns (address withdrawalQueue); function vaultFactory() external view returns (IRegistry); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.25; import "../interfaces/queues/ISymbioticWithdrawalQueue.sol"; contract SymbioticWithdrawalQueue is ISymbioticWithdrawalQueue, Initializable { using SafeERC20 for IERC20; using Math for uint256; /// @inheritdoc IWithdrawalQueue address public immutable claimer; /// @inheritdoc ISymbioticWithdrawalQueue address public vault; /// @inheritdoc ISymbioticWithdrawalQueue ISymbioticVault public symbioticVault; /// @inheritdoc ISymbioticWithdrawalQueue address public collateral; mapping(uint256 epoch => EpochData data) private _epochData; mapping(address account => AccountData data) private _accountData; constructor(address claimer_) { claimer = claimer_; _disableInitializers(); } function initialize(address vault_, address symbioticVault_) external initializer { __init_SymbioticWithdrawalQueue(vault_, symbioticVault_); } function __init_SymbioticWithdrawalQueue(address vault_, address symbioticVault_) internal onlyInitializing { vault = vault_; symbioticVault = ISymbioticVault(symbioticVault_); collateral = ISymbioticVault(symbioticVault_).collateral(); } /// @inheritdoc ISymbioticWithdrawalQueue function getCurrentEpoch() public view returns (uint256) { return symbioticVault.currentEpoch(); } /// @inheritdoc ISymbioticWithdrawalQueue function getAccountData(address account) external view returns ( uint256 sharesToClaimPrev, uint256 sharesToClaim, uint256 claimableAssets, uint256 claimEpoch ) { AccountData storage accountData = _accountData[account]; claimEpoch = accountData.claimEpoch; sharesToClaimPrev = claimEpoch == 0 ? 0 : accountData.sharesToClaim[claimEpoch - 1]; sharesToClaim = accountData.sharesToClaim[claimEpoch]; claimableAssets = accountData.claimableAssets; } /// @inheritdoc ISymbioticWithdrawalQueue function getEpochData(uint256 epoch) external view returns (EpochData memory) { return _epochData[epoch]; } /// @inheritdoc ISymbioticWithdrawalQueue function pendingAssets() public view returns (uint256) { uint256 epoch = getCurrentEpoch(); address this_ = address(this); ISymbioticVault symbioticVault_ = symbioticVault; return symbioticVault_.withdrawalsOf(epoch, this_) + symbioticVault_.withdrawalsOf(epoch + 1, this_); } /// @inheritdoc ISymbioticWithdrawalQueue function pendingAssetsOf(address account) public view returns (uint256 assets) { uint256 epoch = getCurrentEpoch(); AccountData storage accountData = _accountData[account]; assets += _withdrawalsOf(epoch, accountData.sharesToClaim[epoch]); epoch += 1; assets += _withdrawalsOf(epoch, accountData.sharesToClaim[epoch]); } /// @inheritdoc ISymbioticWithdrawalQueue function claimableAssetsOf(address account) public view returns (uint256 assets) { AccountData storage accountData = _accountData[account]; assets = accountData.claimableAssets; uint256 currentEpoch = getCurrentEpoch(); uint256 epoch = accountData.claimEpoch; if (epoch > 0 && _isClaimableInSymbiotic(epoch - 1, currentEpoch)) { assets += _claimable(accountData, epoch - 1); } if (_isClaimableInSymbiotic(epoch, currentEpoch)) { assets += _claimable(accountData, epoch); } } /// @inheritdoc ISymbioticWithdrawalQueue function request(address account, uint256 amount) external { require(msg.sender == vault, "SymbioticWithdrawalQueue: forbidden"); if (amount == 0) { return; } AccountData storage accountData = _accountData[account]; uint256 epoch = getCurrentEpoch(); _handlePendingEpochs(accountData, epoch); epoch = epoch + 1; EpochData storage epochData = _epochData[epoch]; epochData.sharesToClaim += amount; accountData.sharesToClaim[epoch] += amount; accountData.claimEpoch = epoch; emit WithdrawalRequested(account, epoch, amount); } /// @inheritdoc IWithdrawalQueue function transferPendingAssets(address to, uint256 amount) external { address from = msg.sender; if (amount == 0 || from == to) { return; } uint256 epoch = getCurrentEpoch(); uint256 nextEpoch = epoch + 1; AccountData storage fromData = _accountData[from]; AccountData storage toData = _accountData[to]; _handlePendingEpochs(fromData, epoch); _handlePendingEpochs(toData, epoch); uint256 nextSharesToClaim = fromData.sharesToClaim[nextEpoch]; uint256 nextPending = _withdrawalsOf(nextEpoch, nextSharesToClaim); if (nextPending >= amount) { uint256 shares = nextSharesToClaim.mulDiv(amount, nextPending); fromData.sharesToClaim[nextEpoch] -= shares; toData.sharesToClaim[nextEpoch] += shares; toData.claimEpoch = nextEpoch; emit Transfer(from, to, nextEpoch, shares); } else { uint256 currentSharesToClaim = fromData.sharesToClaim[epoch]; uint256 currentPending = _withdrawalsOf(epoch, currentSharesToClaim); require( nextPending + currentPending >= amount, "SymbioticWithdrawalQueue: insufficient pending assets" ); if (nextSharesToClaim != 0) { toData.sharesToClaim[nextEpoch] += nextSharesToClaim; delete fromData.sharesToClaim[nextEpoch]; amount -= nextPending; emit Transfer(from, to, nextEpoch, nextSharesToClaim); } uint256 shares = currentSharesToClaim.mulDiv(amount, currentPending); fromData.sharesToClaim[epoch] = currentSharesToClaim - shares; toData.sharesToClaim[epoch] += shares; toData.claimEpoch = nextEpoch; emit Transfer(from, to, epoch, shares); } } /// @inheritdoc ISymbioticWithdrawalQueue function pull(uint256 epoch) public { require( _isClaimableInSymbiotic(epoch, getCurrentEpoch()), "SymbioticWithdrawalQueue: invalid epoch" ); _pullFromSymbioticForEpoch(epoch); } /// @inheritdoc ISymbioticWithdrawalQueue function claim(address account, address recipient, uint256 maxAmount) external returns (uint256 amount) { address sender = msg.sender; require(sender == account || sender == claimer, "SymbioticWithdrawalQueue: forbidden"); AccountData storage accountData = _accountData[account]; _handlePendingEpochs(accountData, getCurrentEpoch()); amount = accountData.claimableAssets; if (amount == 0) { return 0; } if (amount <= maxAmount) { accountData.claimableAssets = 0; } else { amount = maxAmount; accountData.claimableAssets -= maxAmount; } if (amount != 0) { IERC20(collateral).safeTransfer(recipient, amount); } emit Claimed(account, recipient, amount); } /// @inheritdoc ISymbioticWithdrawalQueue function handlePendingEpochs(address account) public { _handlePendingEpochs(_accountData[account], getCurrentEpoch()); } /** * @notice Calculates the amount of collateral that will be withdrawn for the given `shares` at the specified epoch. * @param epoch The epoch number in the Symbiotic Vault. * @param shares The amount of withdrawal shares. * @return assets The corresponding amount of collateral that will be withdrawn based on the `shares`. */ function _withdrawalsOf(uint256 epoch, uint256 shares) private view returns (uint256) { if (shares == 0) { return 0; } return shares.mulDiv( symbioticVault.withdrawalsOf(epoch, address(this)), _epochData[epoch].sharesToClaim ); } /** * @notice Claims collateral from the Symbiotic Vault for the given account at the current and previous epochs. * @dev This function updates the `epochData` and `accountData` mappings accordingly. * @param accountData The storage struct containing specific claim data for the account. * @param currentEpoch The current epoch in the Symbiotic Vault. * * @custom:requirements * - If `claimEpoch` is zero, no claims are made for `epochEpoch` - 1. * - If `claimEpoch` is non-zero, collateral is claimed for both `claimEpoch` and `claimEpoch`-1. * - Ensures that both `claimEpoch` and `claimEpoch`-1 are claimable. * * @custom:effects * - Emits `EpochClaimed` event when claims are successfully made. */ function _handlePendingEpochs(AccountData storage accountData, uint256 currentEpoch) private { uint256 epoch = accountData.claimEpoch; if (epoch > 0) { _handlePendingEpoch(accountData, epoch - 1, currentEpoch); } _handlePendingEpoch(accountData, epoch, currentEpoch); } /** * @notice Claims collateral from the Symbiotic Vault for the given `epoch`. * @dev This function updates the `epochData` and `accountData` mappings. * @param accountData The storage struct containing specific claim data for the account. * @param epoch The epoch number from which the claim is made. * @param currentEpoch The current epoch in the Symbiotic Vault. * * @custom:requirements * - If `epoch` is not claimable, no claims are made. * * @custom:effects * - Emits `EpochClaimed` event when claims are successfully made. */ function _handlePendingEpoch( AccountData storage accountData, uint256 epoch, uint256 currentEpoch ) private { if (!_isClaimableInSymbiotic(epoch, currentEpoch)) { return; } uint256 shares = accountData.sharesToClaim[epoch]; if (shares == 0) { return; } _pullFromSymbioticForEpoch(epoch); EpochData storage epochData = _epochData[epoch]; uint256 assets = shares.mulDiv(epochData.claimableAssets, epochData.sharesToClaim); epochData.sharesToClaim -= shares; epochData.claimableAssets -= assets; accountData.claimableAssets += assets; delete accountData.sharesToClaim[epoch]; } /** * @notice Claims collateral from the Symbiotic Vault for the given `epoch`. * @dev This function ensures that the withdrawals for the specified `epoch` are not claimed from the Symbiotic Vault. * @param epoch The epoch number for which the collateral is being claimed. * * @custom:requirements * - Checks that the collateral for the given `epoch` has not already been claimed. * - Checks whether there are any claimable withdrawals for the given `epoch`. * * @custom:effects * - Emits `EpochClaimed` event when the claim is successful. */ function _pullFromSymbioticForEpoch(uint256 epoch) private { EpochData storage epochData = _epochData[epoch]; if (epochData.isClaimed) { return; } epochData.isClaimed = true; address this_ = address(this); ISymbioticVault symbioticVault_ = symbioticVault; if (symbioticVault_.isWithdrawalsClaimed(epoch, this_)) { return; } if (symbioticVault_.withdrawalsOf(epoch, this_) == 0) { return; } uint256 claimedAssets = symbioticVault_.claim(this_, epoch); epochData.claimableAssets = claimedAssets; emit EpochClaimed(epoch, claimedAssets); } /** * @notice Returns the claimable collateral amount for a given `accountData` at a specific `epoch`. * @param accountData The storage struct containing specific claim data for the account. * @param epoch The epoch number at which the claim is being checked. * @return The amount of claimable collateral corresponding to the given account's shares at the specified epoch. */ function _claimable(AccountData storage accountData, uint256 epoch) private view returns (uint256) { uint256 shares = accountData.sharesToClaim[epoch]; if (shares == 0) { return 0; } EpochData storage epochData = _epochData[epoch]; if (epochData.isClaimed) { return shares.mulDiv(epochData.claimableAssets, epochData.sharesToClaim); } return _withdrawalsOf(epoch, shares); } /** * @notice Determines whether the given `epoch` is claimable based on the current epoch. * @param epoch The epoch number to check. * @param currentEpoch The current epoch in the Symbiotic Vault. * @return True if the epoch is claimable (i.e., it is less than the current epoch), false otherwise. */ function _isClaimableInSymbiotic(uint256 epoch, uint256 currentEpoch) private pure returns (bool) { return epoch < currentEpoch; } }
// // SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.25; import {IDefaultCollateral, IERC20} from "../tokens/IDefaultCollateral.sol"; import { IMultiVault, IMultiVaultStorage, IProtocolAdapter, IWithdrawalQueue } from "../vaults/IMultiVault.sol"; import {IDepositStrategy} from "./IDepositStrategy.sol"; import {IRebalanceStrategy} from "./IRebalanceStrategy.sol"; import {IWithdrawalStrategy} from "./IWithdrawalStrategy.sol"; import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol"; import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol"; import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; interface IRatiosStrategy is IDepositStrategy, IWithdrawalStrategy, IRebalanceStrategy { struct Ratio { uint64 minRatioD18; uint64 maxRatioD18; } struct Amounts { uint256 min; uint256 max; uint256 claimable; uint256 pending; uint256 staked; } function D18() external view returns (uint256); function RATIOS_STRATEGY_SET_RATIOS_ROLE() external view returns (bytes32); function ratios(address vault, address subvault) external view returns (uint64 minRatioD18, uint64 maxRatioD18); function setRatios(address vault, address[] calldata subvaults, Ratio[] calldata ratios) external; function calculateState(address vault, bool isDeposit, uint256 increment) external view returns (Amounts[] memory state, uint256 liquid); event RatiosSet(address indexed vault, address[] subvaults, Ratio[] ratios); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.25; import "./IMultiVaultStorage.sol"; interface IMultiVault is IMultiVaultStorage { struct InitParams { address admin; uint256 limit; bool depositPause; bool withdrawalPause; bool depositWhitelist; address asset; string name; string symbol; address depositStrategy; address withdrawalStrategy; address rebalanceStrategy; address defaultCollateral; address symbioticAdapter; address eigenLayerAdapter; address erc4626Adapter; } function initialize(InitParams calldata initParams) external; function rebalance() external; function addSubvault(address vault, Protocol protocol) external; function removeSubvault(address subvault) external; function setDepositStrategy(address newDepositStrategy) external; function setWithdrawalStrategy(address newWithdrawalStrategy) external; function setRebalanceStrategy(address newRebalanceStrategy) external; function setRewardsData(uint256 farmId, RewardData calldata rewardData) external; function setDefaultCollateral(address defaultCollateral_) external; function setSymbioticAdapter(address adapter_) external; function setEigenLayerAdapter(address adapter_) external; function setERC4626Adapter(address adapter_) external; function pushRewards(uint256 farmId, bytes calldata data) external; event Rebalance(IRebalanceStrategy.RebalanceData[] data, uint256 timestamp); event DepositIntoCollateral(uint256 assets); event RewardsPushed( uint256 indexed farmId, uint256 indexed rewardAmount, uint256 indexed curatorFee, uint256 timestamp ); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.25; import "../interfaces/vaults/IERC4626Vault.sol"; import {VaultControl} from "./VaultControl.sol"; abstract contract ERC4626Vault is VaultControl, ERC4626Upgradeable, IERC4626Vault { bytes32[16] private _reserved; // Reserved storage space for backward compatibility. /** * @notice Initializes the ERC4626 vault with the provided settings, including admin, limits, pause states, and token details. * @param _admin The address of the admin to be granted control over the vault. * @param _limit The initial deposit limit for the vault. * @param _depositPause The initial state of the `depositPause` flag. * @param _withdrawalPause The initial state of the `withdrawalPause` flag. * @param _depositWhitelist The initial state of the `depositWhitelist` flag. * @param _asset The address of the underlying ERC20 asset for the ERC4626 vault. * @param _name The name of the ERC20 token representing shares of the vault. * @param _symbol The symbol of the ERC20 token representing shares of the vault. * * @custom:effects * - Initializes the vault control settings, including admin, limits, and pause states, via `__initializeVaultControl`. * - Initializes the ERC20 token properties with the provided `_name` and `_symbol`. * - Initializes the ERC4626 vault with the provided underlying asset (`_asset`). * * @dev This function is protected by the `onlyInitializing` modifier, ensuring it is only called during the initialization phase of the contract. */ function __initializeERC4626( address _admin, uint256 _limit, bool _depositPause, bool _withdrawalPause, bool _depositWhitelist, address _asset, string memory _name, string memory _symbol ) internal onlyInitializing { __initializeVaultControl(_admin, _limit, _depositPause, _withdrawalPause, _depositWhitelist); __ERC20_init(_name, _symbol); __ERC4626_init(IERC20(_asset)); } /// @inheritdoc IERC4626 function maxMint(address account) public view virtual override(ERC4626Upgradeable, IERC4626) returns (uint256) { uint256 assets = maxDeposit(account); if (assets == type(uint256).max) { return type(uint256).max; } return convertToShares(assets); } /// @inheritdoc IERC4626 function maxDeposit(address account) public view virtual override(ERC4626Upgradeable, IERC4626) returns (uint256) { if (depositPause()) { return 0; } if (depositWhitelist() && !isDepositorWhitelisted(account)) { return 0; } uint256 limit_ = limit(); if (limit_ == type(uint256).max) { return type(uint256).max; } uint256 assets_ = totalAssets(); return limit_ >= assets_ ? limit_ - assets_ : 0; } /// @inheritdoc IERC4626 function maxWithdraw(address account) public view virtual override(ERC4626Upgradeable, IERC4626) returns (uint256) { if (withdrawalPause()) { return 0; } return super.maxWithdraw(account); } /// @inheritdoc IERC4626 function maxRedeem(address account) public view virtual override(ERC4626Upgradeable, IERC4626) returns (uint256) { if (withdrawalPause()) { return 0; } return super.maxRedeem(account); } /// @inheritdoc IERC4626Vault function deposit(uint256 assets, address receiver, address referral) public virtual returns (uint256 shares) { shares = deposit(assets, receiver); emit ReferralDeposit(assets, receiver, referral); } /// @inheritdoc IERC4626 function deposit(uint256 assets, address receiver) public virtual override(ERC4626Upgradeable, IERC4626) nonReentrant returns (uint256) { return super.deposit(assets, receiver); } /// @inheritdoc IERC4626 function mint(uint256 shares, address receiver) public virtual override(ERC4626Upgradeable, IERC4626) nonReentrant returns (uint256) { return super.mint(shares, receiver); } /// @inheritdoc IERC4626 function withdraw(uint256 assets, address receiver, address owner) public virtual override(ERC4626Upgradeable, IERC4626) nonReentrant returns (uint256) { return super.withdraw(assets, receiver, owner); } /// @inheritdoc IERC4626 function redeem(uint256 shares, address receiver, address owner) public virtual override(ERC4626Upgradeable, IERC4626) nonReentrant returns (uint256) { return super.redeem(shares, receiver, owner); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.25; import "../interfaces/vaults/IMultiVaultStorage.sol"; contract MultiVaultStorage is IMultiVaultStorage, Initializable { using EnumerableSet for EnumerableSet.UintSet; bytes32 private immutable storageSlotRef; constructor(bytes32 name_, uint256 version_) { storageSlotRef = keccak256( abi.encode( uint256( keccak256( abi.encodePacked( "mellow.simple-lrt.storage.MultiVaultStorage", name_, version_ ) ) ) - 1 ) ) & ~bytes32(uint256(0xff)); } function _multiStorage() private view returns (MultiStorage storage $) { bytes32 slot = storageSlotRef; assembly { $.slot := slot } } /// ------------------------------- EXTERNAL VIEW FUNCTIONS ------------------------------- /// @inheritdoc IMultiVaultStorage function subvaultsCount() public view returns (uint256) { return _multiStorage().subvaults.length; } /// @inheritdoc IMultiVaultStorage function subvaultAt(uint256 index) public view returns (Subvault memory) { return _multiStorage().subvaults[index]; } /// @inheritdoc IMultiVaultStorage function indexOfSubvault(address subvault) public view returns (uint256) { return _multiStorage().indexOfSubvault[subvault]; } /// @inheritdoc IMultiVaultStorage function defaultCollateral() public view returns (IDefaultCollateral) { return IDefaultCollateral(_multiStorage().defaultCollateral); } /// @inheritdoc IMultiVaultStorage function depositStrategy() public view returns (IDepositStrategy) { return IDepositStrategy(_multiStorage().depositStrategy); } /// @inheritdoc IMultiVaultStorage function withdrawalStrategy() public view returns (IWithdrawalStrategy) { return IWithdrawalStrategy(_multiStorage().withdrawalStrategy); } /// @inheritdoc IMultiVaultStorage function rebalanceStrategy() public view returns (IRebalanceStrategy) { return IRebalanceStrategy(_multiStorage().rebalanceStrategy); } /// @inheritdoc IMultiVaultStorage function symbioticAdapter() public view returns (IProtocolAdapter) { return IProtocolAdapter(_multiStorage().symbioticAdapter); } /// @inheritdoc IMultiVaultStorage function eigenLayerAdapter() public view returns (IProtocolAdapter) { return IProtocolAdapter(_multiStorage().eigenLayerAdapter); } /// @inheritdoc IMultiVaultStorage function erc4626Adapter() public view returns (IProtocolAdapter) { return IProtocolAdapter(_multiStorage().erc4626Adapter); } /// @inheritdoc IMultiVaultStorage function rewardData(uint256 farmId) public view returns (RewardData memory) { return _multiStorage().rewardData[farmId]; } /// @inheritdoc IMultiVaultStorage function farmIds() public view returns (uint256[] memory) { return _multiStorage().farmIds.values(); } /// @inheritdoc IMultiVaultStorage function farmCount() public view returns (uint256) { return _multiStorage().farmIds.length(); } /// @inheritdoc IMultiVaultStorage function farmIdAt(uint256 index) public view returns (uint256) { return _multiStorage().farmIds.at(index); } /// @inheritdoc IMultiVaultStorage function farmIdsContains(uint256 farmId) public view returns (bool) { return _multiStorage().farmIds.contains(farmId); } /// @inheritdoc IMultiVaultStorage function adapterOf(Protocol protocol) public view returns (IProtocolAdapter adapter) { if (protocol == Protocol.SYMBIOTIC) { adapter = symbioticAdapter(); } else if (protocol == Protocol.EIGEN_LAYER) { adapter = eigenLayerAdapter(); } else if (protocol == Protocol.ERC4626) { adapter = erc4626Adapter(); } require(address(adapter) != address(0), "MultiVault: unsupported protocol"); } /// ------------------------------- INTERNAL MUTATIVE FUNCTIONS ------------------------------- function __initializeMultiVaultStorage( address depositStrategy_, address withdrawalStrategy_, address rebalanceStrategy_, address defaultCollateral_, address symbioticAdapter_, address eigenLayerAdapter_, address erc4626Adapter_ ) internal onlyInitializing { _setDepositStrategy(depositStrategy_); _setWithdrawalStrategy(withdrawalStrategy_); _setRebalanceStrategy(rebalanceStrategy_); _setDefaultCollateral(defaultCollateral_); _setSymbioticAdapter(symbioticAdapter_); _setEigenLayerAdapter(eigenLayerAdapter_); _setERC4626Adapter(erc4626Adapter_); } function _setSymbioticAdapter(address symbioticAdapter_) internal { _multiStorage().symbioticAdapter = symbioticAdapter_; emit SymbioticAdapterSet(symbioticAdapter_); } function _setEigenLayerAdapter(address eigenLayerAdapter_) internal { _multiStorage().eigenLayerAdapter = eigenLayerAdapter_; emit EigenLayerAdapterSet(eigenLayerAdapter_); } function _setERC4626Adapter(address erc4626Adapter_) internal { _multiStorage().erc4626Adapter = erc4626Adapter_; emit ERC4626AdapterSet(erc4626Adapter_); } function _setDepositStrategy(address newDepositStrategy) internal { _multiStorage().depositStrategy = newDepositStrategy; emit DepositStrategySet(newDepositStrategy); } function _setWithdrawalStrategy(address newWithdrawalStrategy) internal { _multiStorage().withdrawalStrategy = newWithdrawalStrategy; emit WithdrawalStrategySet(newWithdrawalStrategy); } function _setRebalanceStrategy(address newRebalanceStrategy) internal { _multiStorage().rebalanceStrategy = newRebalanceStrategy; emit RebalanceStrategySet(newRebalanceStrategy); } function _setDefaultCollateral(address defaultCollateral_) internal { _multiStorage().defaultCollateral = defaultCollateral_; emit DefaultCollateralSet(defaultCollateral_); } function _addSubvault(address vault, address withdrawalQueue, Protocol protocol) internal { MultiStorage storage $ = _multiStorage(); require($.indexOfSubvault[vault] == 0, "MultiVaultStorage: subvault already exists"); $.subvaults.push(Subvault(protocol, vault, withdrawalQueue)); uint256 index = $.subvaults.length; $.indexOfSubvault[vault] = index; emit SubvaultAdded(vault, withdrawalQueue, protocol, index - 1); } function _removeSubvault(address vault) internal { MultiStorage storage $ = _multiStorage(); uint256 index = $.indexOfSubvault[vault]; require(index != 0, "MultiVaultStorage: subvault not found"); index--; uint256 last = $.subvaults.length - 1; emit SubvaultRemoved(vault, index); if (index < last) { Subvault memory lastSubvault = $.subvaults[last]; $.subvaults[index] = lastSubvault; $.indexOfSubvault[lastSubvault.vault] = index + 1; emit SubvaultIndexChanged(lastSubvault.vault, last, index); } $.subvaults.pop(); delete $.indexOfSubvault[vault]; } function _setRewardData(uint256 farmId, RewardData memory data) internal { MultiStorage storage $ = _multiStorage(); if (data.token == address(0)) { if ($.farmIds.remove(farmId)) { delete $.rewardData[farmId]; emit RewardDataRemoved(farmId); } } else { $.rewardData[farmId] = data; $.farmIds.add(farmId); emit RewardDataSet(farmId, data); } } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.25; import "../interfaces/vaults/IVaultControlStorage.sol"; abstract contract VaultControlStorage is IVaultControlStorage, Initializable, ContextUpgradeable { bytes32 private immutable storageSlotRef; constructor(bytes32 name_, uint256 version_) { storageSlotRef = keccak256( abi.encode( uint256( keccak256( abi.encodePacked( "mellow.simple-lrt.storage.VaultControlStorage", name_, version_ ) ) ) - 1 ) ) & ~bytes32(uint256(0xff)); } /** * @notice Initializes the Vault storage with the provided settings for limit, pause states, and whitelist. * @param _limit The initial value for the Vault's deposit limit. * @param _depositPause The initial state for the `depositPause` flag. * @param _withdrawalPause The initial state for the `withdrawalPause` flag. * @param _depositWhitelist The initial state for the `depositWhitelist` flag. * * @custom:requirements * - This function MUST not be called more than once; it is intended for one-time initialization. * * @custom:effects * - Sets the provided limit, pause states, and whitelist state in the Vault's storage. * - Emits the `LimitSet` event after the limit is set. * - Emits the `DepositPauseSet` event after the deposit pause state is set. * - Emits the `WithdrawalPauseSet` event after the withdrawal pause state is set. * - Emits the `DepositWhitelistSet` event after the deposit whitelist state is set. * * @dev This function is protected by the `onlyInitializing` modifier to ensure it is only called during the contract's initialization phase. */ function __initializeVaultControlStorage( uint256 _limit, bool _depositPause, bool _withdrawalPause, bool _depositWhitelist ) internal onlyInitializing { _setLimit(_limit); _setDepositPause(_depositPause); _setWithdrawalPause(_withdrawalPause); _setDepositWhitelist(_depositWhitelist); } /// @inheritdoc IVaultControlStorage function depositPause() public view returns (bool) { return _vaultStorage().depositPause; } /// @inheritdoc IVaultControlStorage function withdrawalPause() public view returns (bool) { return _vaultStorage().withdrawalPause; } /// @inheritdoc IVaultControlStorage function limit() public view returns (uint256) { return _vaultStorage().limit; } /// @inheritdoc IVaultControlStorage function depositWhitelist() public view returns (bool) { return _vaultStorage().depositWhitelist; } /// @inheritdoc IVaultControlStorage function isDepositorWhitelisted(address account) public view returns (bool) { return _vaultStorage().isDepositorWhitelisted[account]; } /** * @notice Sets a new `limit` for the Vault. * @param _limit The new limit for the Vault. * * @custom:effects * - Updates the Vault's `limit` in storage. * - Emits the `LimitSet` event with the new limit, current timestamp, and the caller's address. */ function _setLimit(uint256 _limit) internal { Storage storage s = _vaultStorage(); s.limit = _limit; emit LimitSet(_limit, block.timestamp, _msgSender()); } /** * @notice Sets a new `depositPause` state for the Vault. * @param _paused The new value for the `depositPause` state. * * @custom:effects * - Updates the Vault's `depositPause` state in storage. * - Emits the `DepositPauseSet` event with the new pause state, current timestamp, and the caller's address. */ function _setDepositPause(bool _paused) internal { Storage storage s = _vaultStorage(); s.depositPause = _paused; emit DepositPauseSet(_paused, block.timestamp, _msgSender()); } /** * @notice Sets a new `withdrawalPause` state for the Vault. * @param _paused The new value for the `withdrawalPause` state. * * @custom:effects * - Updates the Vault's `withdrawalPause` state in storage. * - Emits the `WithdrawalPauseSet` event with the new pause state, current timestamp, and the caller's address. */ function _setWithdrawalPause(bool _paused) internal { Storage storage s = _vaultStorage(); s.withdrawalPause = _paused; emit WithdrawalPauseSet(_paused, block.timestamp, _msgSender()); } /** * @notice Sets a new `depositWhitelist` state for the Vault. * @param _status The new value for the `depositWhitelist` state. * * @custom:effects * - Updates the Vault's `depositWhitelist` state in storage. * - Emits the `DepositWhitelistSet` event with the new whitelist status, current timestamp, and the caller's address. */ function _setDepositWhitelist(bool _status) internal { Storage storage s = _vaultStorage(); s.depositWhitelist = _status; emit DepositWhitelistSet(_status, block.timestamp, _msgSender()); } /** * @notice Sets a new whitelist `status` for the given `account`. * @param account The address of the account to update. * @param status The new whitelist status for the account. * * @custom:effects * - Updates the whitelist status of the `account` in storage. * - Emits the `DepositorWhitelistStatusSet` event with the account, new status, current timestamp, and the caller's address. */ function _setDepositorWhitelistStatus(address account, bool status) internal { Storage storage s = _vaultStorage(); s.isDepositorWhitelisted[account] = status; emit DepositorWhitelistStatusSet(account, status, block.timestamp, _msgSender()); } /** * @notice Accesses the storage slot for the Vault's data. * @return $ A reference to the `Storage` struct for the Vault. * * @dev This function uses inline assembly to access a predefined storage slot. */ function _vaultStorage() private view returns (Storage storage $) { bytes32 slot = storageSlotRef; assembly { $.slot := slot } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Utils.sol) pragma solidity ^0.8.20; import {IBeacon} from "../beacon/IBeacon.sol"; import {Address} from "../../utils/Address.sol"; import {StorageSlot} from "../../utils/StorageSlot.sol"; /** * @dev This abstract contract provides getters and event emitting update functions for * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots. */ library ERC1967Utils { // We re-declare ERC-1967 events here because they can't be used directly from IERC1967. // This will be fixed in Solidity 0.8.21. At that point we should remove these events. /** * @dev Emitted when the implementation is upgraded. */ event Upgraded(address indexed implementation); /** * @dev Emitted when the admin account has changed. */ event AdminChanged(address previousAdmin, address newAdmin); /** * @dev Emitted when the beacon is changed. */ event BeaconUpgraded(address indexed beacon); /** * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1. */ // solhint-disable-next-line private-vars-leading-underscore bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; /** * @dev The `implementation` of the proxy is invalid. */ error ERC1967InvalidImplementation(address implementation); /** * @dev The `admin` of the proxy is invalid. */ error ERC1967InvalidAdmin(address admin); /** * @dev The `beacon` of the proxy is invalid. */ error ERC1967InvalidBeacon(address beacon); /** * @dev An upgrade function sees `msg.value > 0` that may be lost. */ error ERC1967NonPayable(); /** * @dev Returns the current implementation address. */ function getImplementation() internal view returns (address) { return StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value; } /** * @dev Stores a new address in the EIP1967 implementation slot. */ function _setImplementation(address newImplementation) private { if (newImplementation.code.length == 0) { revert ERC1967InvalidImplementation(newImplementation); } StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation; } /** * @dev Performs implementation upgrade with additional setup call if data is nonempty. * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected * to avoid stuck value in the contract. * * Emits an {IERC1967-Upgraded} event. */ function upgradeToAndCall(address newImplementation, bytes memory data) internal { _setImplementation(newImplementation); emit Upgraded(newImplementation); if (data.length > 0) { Address.functionDelegateCall(newImplementation, data); } else { _checkNonPayable(); } } /** * @dev Storage slot with the admin of the contract. * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1. */ // solhint-disable-next-line private-vars-leading-underscore bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; /** * @dev Returns the current admin. * * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using * the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103` */ function getAdmin() internal view returns (address) { return StorageSlot.getAddressSlot(ADMIN_SLOT).value; } /** * @dev Stores a new address in the EIP1967 admin slot. */ function _setAdmin(address newAdmin) private { if (newAdmin == address(0)) { revert ERC1967InvalidAdmin(address(0)); } StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin; } /** * @dev Changes the admin of the proxy. * * Emits an {IERC1967-AdminChanged} event. */ function changeAdmin(address newAdmin) internal { emit AdminChanged(getAdmin(), newAdmin); _setAdmin(newAdmin); } /** * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy. * This is the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1. */ // solhint-disable-next-line private-vars-leading-underscore bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; /** * @dev Returns the current beacon. */ function getBeacon() internal view returns (address) { return StorageSlot.getAddressSlot(BEACON_SLOT).value; } /** * @dev Stores a new beacon in the EIP1967 beacon slot. */ function _setBeacon(address newBeacon) private { if (newBeacon.code.length == 0) { revert ERC1967InvalidBeacon(newBeacon); } StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon; address beaconImplementation = IBeacon(newBeacon).implementation(); if (beaconImplementation.code.length == 0) { revert ERC1967InvalidImplementation(beaconImplementation); } } /** * @dev Change the beacon and trigger a setup call if data is nonempty. * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected * to avoid stuck value in the contract. * * Emits an {IERC1967-BeaconUpgraded} event. * * CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since * it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for * efficiency. */ function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal { _setBeacon(newBeacon); emit BeaconUpgraded(newBeacon); if (data.length > 0) { Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data); } else { _checkNonPayable(); } } /** * @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract * if an upgrade doesn't perform an initialization call. */ function _checkNonPayable() private { if (msg.value > 0) { revert ERC1967NonPayable(); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Proxy.sol) pragma solidity ^0.8.20; import {Proxy} from "../Proxy.sol"; import {ERC1967Utils} from "./ERC1967Utils.sol"; /** * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an * implementation address that can be changed. This address is stored in storage in the location specified by * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the * implementation behind the proxy. */ contract ERC1967Proxy is Proxy { /** * @dev Initializes the upgradeable proxy with an initial implementation specified by `implementation`. * * If `_data` is nonempty, it's used as data in a delegate call to `implementation`. This will typically be an * encoded function call, and allows initializing the storage of the proxy like a Solidity constructor. * * Requirements: * * - If `data` is empty, `msg.value` must be zero. */ constructor(address implementation, bytes memory _data) payable { ERC1967Utils.upgradeToAndCall(implementation, _data); } /** * @dev Returns the current implementation address. * * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using * the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc` */ function _implementation() internal view virtual override returns (address) { return ERC1967Utils.getImplementation(); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1967.sol) pragma solidity ^0.8.20; /** * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC. */ interface IERC1967 { /** * @dev Emitted when the implementation is upgraded. */ event Upgraded(address indexed implementation); /** * @dev Emitted when the admin account has changed. */ event AdminChanged(address previousAdmin, address newAdmin); /** * @dev Emitted when the beacon is changed. */ event BeaconUpgraded(address indexed beacon); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/transparent/ProxyAdmin.sol) pragma solidity ^0.8.20; import {ITransparentUpgradeableProxy} from "./TransparentUpgradeableProxy.sol"; import {Ownable} from "../../access/Ownable.sol"; /** * @dev This is an auxiliary contract meant to be assigned as the admin of a {TransparentUpgradeableProxy}. For an * explanation of why you would want to use this see the documentation for {TransparentUpgradeableProxy}. */ contract ProxyAdmin is Ownable { /** * @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgrade(address)` * and `upgradeAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called, * while `upgradeAndCall` will invoke the `receive` function if the second argument is the empty byte string. * If the getter returns `"5.0.0"`, only `upgradeAndCall(address,bytes)` is present, and the second argument must * be the empty byte string if no function should be called, making it impossible to invoke the `receive` function * during an upgrade. */ string public constant UPGRADE_INTERFACE_VERSION = "5.0.0"; /** * @dev Sets the initial owner who can perform upgrades. */ constructor(address initialOwner) Ownable(initialOwner) {} /** * @dev Upgrades `proxy` to `implementation` and calls a function on the new implementation. * See {TransparentUpgradeableProxy-_dispatchUpgradeToAndCall}. * * Requirements: * * - This contract must be the admin of `proxy`. * - If `data` is empty, `msg.value` must be zero. */ function upgradeAndCall( ITransparentUpgradeableProxy proxy, address implementation, bytes memory data ) public payable virtual onlyOwner { proxy.upgradeToAndCall{value: msg.value}(implementation, data); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.25; import {IWithdrawalQueue} from "./IWithdrawalQueue.sol"; import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import {IERC20, SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; import {IVault as ISymbioticVault} from "@symbiotic/core/interfaces/vault/IVault.sol"; /** * @title ISymbioticWithdrawalQueue * @notice Interface to handle the withdrawal process from the Symbiotic Vault. * @dev This interface is an extension of IWithdrawalQueue for interacting specifically with the Symbiotic Vault. */ interface ISymbioticWithdrawalQueue is IWithdrawalQueue { /** * @notice Struct to hold epoch-related data. * @param isClaimed Indicates whether the epoch has been claimed. * @param sharesToClaim The amount of shares to be claimed. * @param claimableAssets The amount of assets that can be claimed. */ struct EpochData { bool isClaimed; uint256 sharesToClaim; uint256 claimableAssets; } /** * @notice Struct to store account-related data for withdrawals. * @param sharesToClaim A mapping of epochs to shares to be claimed for a given epoch. * @param claimableAssets The total amount of assets that can be claimed. * @param claimEpoch The most recent epoch requested for withdrawal. */ struct AccountData { mapping(uint256 => uint256) sharesToClaim; uint256 claimableAssets; uint256 claimEpoch; } /** * @notice Returns the address of the associated MellowSymbioticVault. * @return vault The address of the MellowSymbioticVault. */ function vault() external view returns (address); /** * @notice Returns the address of the associated Symbiotic Vault. * @return symbioticVault The address of the Symbiotic Vault. */ function symbioticVault() external view returns (ISymbioticVault); /** * @notice Returns the address of the collateral token used by the vault. * @dev The collateral token is the same as the vault's asset. * @return collateralAddress The address of the collateral token. */ function collateral() external view returns (address); /** * @notice Returns the current epoch of the Symbiotic Vault. * @return currentEpoch The current epoch of the Symbiotic Vault. */ function getCurrentEpoch() external view returns (uint256); /** * @notice Returns the data for a specific account. * @param account The address of the account to retrieve data for. * @return sharesToClaimPrev The amount of shares to claim for the epoch before the last requested epoch. * @return sharesToClaim The amount of shares to claim for the last requested epoch. * @return claimableAssets The total amount of assets that can be claimed. * @return claimEpoch The most recent epoch requested for withdrawal. */ function getAccountData(address account) external view returns ( uint256 sharesToClaimPrev, uint256 sharesToClaim, uint256 claimableAssets, uint256 claimEpoch ); /** * @notice Returns the data for a specific epoch. * @param epoch The epoch number to retrieve data for. * @return epochData The data for the specified epoch. */ function getEpochData(uint256 epoch) external view returns (EpochData memory); /** * @notice Returns the total amount of pending assets awaiting withdrawal. * @dev This amount may decrease due to slashing events in the Symbiotic Vault. * @return assets The total amount of assets pending withdrawal. */ function pendingAssets() external view returns (uint256); /** * @notice Returns the amount of assets in the withdrawal queue for a specific account that cannot be claimed yet. * @param account The address of the account. * @return assets The amount of pending assets in the withdrawal queue for the account. */ function pendingAssetsOf(address account) external view returns (uint256 assets); /** * @notice Returns the amount of assets that can be claimed by an account. * @param account The address of the account. * @return assets The amount of assets claimable by the account. */ function claimableAssetsOf(address account) external view returns (uint256 assets); /** * @notice Requests the withdrawal of a specified amount of collateral for a given account. * @param account The address of the account requesting the withdrawal. * @param amount The amount of collateral to withdraw. * * @custom:requirements * - `msg.sender` MUST be the vault. * - `amount` MUST be greater than zero. * * @custom:effects * - Emits a `WithdrawalRequested` event. */ function request(address account, uint256 amount) external; /** * @notice Claims assets from the Symbiotic Vault for a specified epoch to the Withdrawal Queue address. * @param epoch The epoch number. * @dev Emits an EpochClaimed event. */ function pull(uint256 epoch) external; /** * @notice Finalizes the withdrawal process for a specific account and transfers assets to the recipient. * @param account The address of the account requesting the withdrawal. * @param recipient The address of the recipient receiving the withdrawn assets. * @param maxAmount The maximum amount of assets to withdraw. * @return amount The actual amount of assets withdrawn. */ function claim(address account, address recipient, uint256 maxAmount) external returns (uint256 amount); /** * @notice Handles the pending epochs for a specific account and makes assets claimable for recent epochs. * @param account The address of the account. * @dev Emits an EpochClaimed event. */ function handlePendingEpochs(address account) external; /// @notice Emitted when a withdrawal request is created. event WithdrawalRequested(address indexed account, uint256 indexed epoch, uint256 amount); /// @notice Emitted when assets are successfully claimed for a specific epoch. event EpochClaimed(uint256 indexed epoch, uint256 claimedAssets); /// @notice Emitted when assets are successfully withdrawn and transferred to a recipient. event Claimed(address indexed account, address indexed recipient, uint256 amount); /// @notice Emitted when pending assets are successfully transferred from one account to another. event Transfer(address indexed from, address indexed to, uint256 indexed epoch, uint256 amount); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.25; interface IProtocolAdapter { function vault() external view returns (address); function maxDeposit(address subvault) external view returns (uint256); function stakedAt(address subvault) external view returns (uint256); function assetOf(address subvault) external view returns (address); function validateRewardData(bytes calldata data) external view; function pushRewards(address rewardToken, bytes calldata farmData, bytes memory rewardData) external; function withdraw( address subvault, address withdrawalQueue, address receiver, uint256 request, address owner ) external; function deposit(address subvault, uint256 assets) external; function handleVault(address subvault) external returns (address withdrawalQueue); function areWithdrawalsPaused(address subvault, address account) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC4626.sol) pragma solidity ^0.8.20; import {IERC20} from "../token/ERC20/IERC20.sol"; import {IERC20Metadata} from "../token/ERC20/extensions/IERC20Metadata.sol"; /** * @dev Interface of the ERC4626 "Tokenized Vault Standard", as defined in * https://eips.ethereum.org/EIPS/eip-4626[ERC-4626]. */ interface IERC4626 is IERC20, IERC20Metadata { event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares); event Withdraw( address indexed sender, address indexed receiver, address indexed owner, uint256 assets, uint256 shares ); /** * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing. * * - MUST be an ERC-20 token contract. * - MUST NOT revert. */ function asset() external view returns (address assetTokenAddress); /** * @dev Returns the total amount of the underlying asset that is “managed” by Vault. * * - SHOULD include any compounding that occurs from yield. * - MUST be inclusive of any fees that are charged against assets in the Vault. * - MUST NOT revert. */ function totalAssets() external view returns (uint256 totalManagedAssets); /** * @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal * scenario where all the conditions are met. * * - MUST NOT be inclusive of any fees that are charged against assets in the Vault. * - MUST NOT show any variations depending on the caller. * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange. * - MUST NOT revert. * * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and * from. */ function convertToShares(uint256 assets) external view returns (uint256 shares); /** * @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal * scenario where all the conditions are met. * * - MUST NOT be inclusive of any fees that are charged against assets in the Vault. * - MUST NOT show any variations depending on the caller. * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange. * - MUST NOT revert. * * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and * from. */ function convertToAssets(uint256 shares) external view returns (uint256 assets); /** * @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver, * through a deposit call. * * - MUST return a limited value if receiver is subject to some deposit limit. * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited. * - MUST NOT revert. */ function maxDeposit(address receiver) external view returns (uint256 maxAssets); /** * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given * current on-chain conditions. * * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit * call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called * in the same transaction. * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the * deposit would be accepted, regardless if the user has enough tokens approved, etc. * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees. * - MUST NOT revert. * * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in * share price or some other type of condition, meaning the depositor will lose assets by depositing. */ function previewDeposit(uint256 assets) external view returns (uint256 shares); /** * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens. * * - MUST emit the Deposit event. * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the * deposit execution, and are accounted for during deposit. * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not * approving enough underlying tokens to the Vault contract, etc). * * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token. */ function deposit(uint256 assets, address receiver) external returns (uint256 shares); /** * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call. * - MUST return a limited value if receiver is subject to some mint limit. * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted. * - MUST NOT revert. */ function maxMint(address receiver) external view returns (uint256 maxShares); /** * @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given * current on-chain conditions. * * - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call * in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the * same transaction. * - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint * would be accepted, regardless if the user has enough tokens approved, etc. * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees. * - MUST NOT revert. * * NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in * share price or some other type of condition, meaning the depositor will lose assets by minting. */ function previewMint(uint256 shares) external view returns (uint256 assets); /** * @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens. * * - MUST emit the Deposit event. * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint * execution, and are accounted for during mint. * - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not * approving enough underlying tokens to the Vault contract, etc). * * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token. */ function mint(uint256 shares, address receiver) external returns (uint256 assets); /** * @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the * Vault, through a withdraw call. * * - MUST return a limited value if owner is subject to some withdrawal limit or timelock. * - MUST NOT revert. */ function maxWithdraw(address owner) external view returns (uint256 maxAssets); /** * @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block, * given current on-chain conditions. * * - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw * call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if * called * in the same transaction. * - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though * the withdrawal would be accepted, regardless if the user has enough shares, etc. * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees. * - MUST NOT revert. * * NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in * share price or some other type of condition, meaning the depositor will lose assets by depositing. */ function previewWithdraw(uint256 assets) external view returns (uint256 shares); /** * @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver. * * - MUST emit the Withdraw event. * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the * withdraw execution, and are accounted for during withdraw. * - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner * not having enough shares, etc). * * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed. * Those methods should be performed separately. */ function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares); /** * @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault, * through a redeem call. * * - MUST return a limited value if owner is subject to some withdrawal limit or timelock. * - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock. * - MUST NOT revert. */ function maxRedeem(address owner) external view returns (uint256 maxShares); /** * @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block, * given current on-chain conditions. * * - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call * in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the * same transaction. * - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the * redemption would be accepted, regardless if the user has enough shares, etc. * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees. * - MUST NOT revert. * * NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in * share price or some other type of condition, meaning the depositor will lose assets by redeeming. */ function previewRedeem(uint256 shares) external view returns (uint256 assets); /** * @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver. * * - MUST emit the Withdraw event. * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the * redeem execution, and are accounted for during redeem. * - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner * not having enough shares, etc). * * NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed. * Those methods should be performed separately. */ function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "../IERC20.sol"; import {IERC20Permit} from "../extensions/IERC20Permit.sol"; import {Address} from "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; /** * @dev An operation with an ERC20 token failed. */ error SafeERC20FailedOperation(address token); /** * @dev Indicates a failed `decreaseAllowance` request. */ error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease); /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value))); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value))); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); forceApprove(token, spender, oldAllowance + value); } /** * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no * value, non-reverting calls are assumed to be successful. */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal { unchecked { uint256 currentAllowance = token.allowance(address(this), spender); if (currentAllowance < requestedDecrease) { revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease); } forceApprove(token, spender, currentAllowance - requestedDecrease); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value)); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0))); _callOptionalReturn(token, approvalCall); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data); if (returndata.length != 0 && !abi.decode(returndata, (bool))) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false // and not revert is the subcall reverts. (bool success, bytes memory returndata) = address(token).call(data); return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IRegistry { error EntityNotExist(); /** * @notice Emitted when an entity is added. * @param entity address of the added entity */ event AddEntity(address indexed entity); /** * @notice Get if a given address is an entity. * @param account address to check * @return if the given address is an entity */ function isEntity( address account ) external view returns (bool); /** * @notice Get a total number of entities. * @return total number of entities added */ function totalEntities() external view returns (uint256); /** * @notice Get an entity given its index. * @param index index of the entity to get * @return address of the entity */ function entity( uint256 index ) external view returns (address); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {IMigratableEntity} from "../common/IMigratableEntity.sol"; import {IVaultStorage} from "./IVaultStorage.sol"; interface IVault is IMigratableEntity, IVaultStorage { error AlreadyClaimed(); error AlreadySet(); error DelegatorAlreadyInitialized(); error DepositLimitReached(); error InsufficientClaim(); error InsufficientDeposit(); error InsufficientRedemption(); error InsufficientWithdrawal(); error InvalidAccount(); error InvalidCaptureEpoch(); error InvalidClaimer(); error InvalidCollateral(); error InvalidDelegator(); error InvalidEpoch(); error InvalidEpochDuration(); error InvalidLengthEpochs(); error InvalidOnBehalfOf(); error InvalidRecipient(); error InvalidSlasher(); error MissingRoles(); error NotDelegator(); error NotSlasher(); error NotWhitelistedDepositor(); error SlasherAlreadyInitialized(); error TooMuchRedeem(); error TooMuchWithdraw(); /** * @notice Initial parameters needed for a vault deployment. * @param collateral vault's underlying collateral * @param burner vault's burner to issue debt to (e.g., 0xdEaD or some unwrapper contract) * @param epochDuration duration of the vault epoch (it determines sync points for withdrawals) * @param depositWhitelist if enabling deposit whitelist * @param isDepositLimit if enabling deposit limit * @param depositLimit deposit limit (maximum amount of the collateral that can be in the vault simultaneously) * @param defaultAdminRoleHolder address of the initial DEFAULT_ADMIN_ROLE holder * @param depositWhitelistSetRoleHolder address of the initial DEPOSIT_WHITELIST_SET_ROLE holder * @param depositorWhitelistRoleHolder address of the initial DEPOSITOR_WHITELIST_ROLE holder * @param isDepositLimitSetRoleHolder address of the initial IS_DEPOSIT_LIMIT_SET_ROLE holder * @param depositLimitSetRoleHolder address of the initial DEPOSIT_LIMIT_SET_ROLE holder */ struct InitParams { address collateral; address burner; uint48 epochDuration; bool depositWhitelist; bool isDepositLimit; uint256 depositLimit; address defaultAdminRoleHolder; address depositWhitelistSetRoleHolder; address depositorWhitelistRoleHolder; address isDepositLimitSetRoleHolder; address depositLimitSetRoleHolder; } /** * @notice Hints for an active balance. * @param activeSharesOfHint hint for the active shares of checkpoint * @param activeStakeHint hint for the active stake checkpoint * @param activeSharesHint hint for the active shares checkpoint */ struct ActiveBalanceOfHints { bytes activeSharesOfHint; bytes activeStakeHint; bytes activeSharesHint; } /** * @notice Emitted when a deposit is made. * @param depositor account that made the deposit * @param onBehalfOf account the deposit was made on behalf of * @param amount amount of the collateral deposited * @param shares amount of the active shares minted */ event Deposit(address indexed depositor, address indexed onBehalfOf, uint256 amount, uint256 shares); /** * @notice Emitted when a withdrawal is made. * @param withdrawer account that made the withdrawal * @param claimer account that needs to claim the withdrawal * @param amount amount of the collateral withdrawn * @param burnedShares amount of the active shares burned * @param mintedShares amount of the epoch withdrawal shares minted */ event Withdraw( address indexed withdrawer, address indexed claimer, uint256 amount, uint256 burnedShares, uint256 mintedShares ); /** * @notice Emitted when a claim is made. * @param claimer account that claimed * @param recipient account that received the collateral * @param epoch epoch the collateral was claimed for * @param amount amount of the collateral claimed */ event Claim(address indexed claimer, address indexed recipient, uint256 epoch, uint256 amount); /** * @notice Emitted when a batch claim is made. * @param claimer account that claimed * @param recipient account that received the collateral * @param epochs epochs the collateral was claimed for * @param amount amount of the collateral claimed */ event ClaimBatch(address indexed claimer, address indexed recipient, uint256[] epochs, uint256 amount); /** * @notice Emitted when a slash happens. * @param amount amount of the collateral to slash * @param captureTimestamp time point when the stake was captured * @param slashedAmount real amount of the collateral slashed */ event OnSlash(uint256 amount, uint48 captureTimestamp, uint256 slashedAmount); /** * @notice Emitted when a deposit whitelist status is enabled/disabled. * @param status if enabled deposit whitelist */ event SetDepositWhitelist(bool status); /** * @notice Emitted when a depositor whitelist status is set. * @param account account for which the whitelist status is set * @param status if whitelisted the account */ event SetDepositorWhitelistStatus(address indexed account, bool status); /** * @notice Emitted when a deposit limit status is enabled/disabled. * @param status if enabled deposit limit */ event SetIsDepositLimit(bool status); /** * @notice Emitted when a deposit limit is set. * @param limit deposit limit (maximum amount of the collateral that can be in the vault simultaneously) */ event SetDepositLimit(uint256 limit); /** * @notice Emitted when a delegator is set. * @param delegator vault's delegator to delegate the stake to networks and operators * @dev Can be set only once. */ event SetDelegator(address indexed delegator); /** * @notice Emitted when a slasher is set. * @param slasher vault's slasher to provide a slashing mechanism to networks * @dev Can be set only once. */ event SetSlasher(address indexed slasher); /** * @notice Check if the vault is fully initialized (a delegator and a slasher are set). * @return if the vault is fully initialized */ function isInitialized() external view returns (bool); /** * @notice Get a total amount of the collateral that can be slashed. * @return total amount of the slashable collateral */ function totalStake() external view returns (uint256); /** * @notice Get an active balance for a particular account at a given timestamp using hints. * @param account account to get the active balance for * @param timestamp time point to get the active balance for the account at * @param hints hints for checkpoints' indexes * @return active balance for the account at the timestamp */ function activeBalanceOfAt( address account, uint48 timestamp, bytes calldata hints ) external view returns (uint256); /** * @notice Get an active balance for a particular account. * @param account account to get the active balance for * @return active balance for the account */ function activeBalanceOf( address account ) external view returns (uint256); /** * @notice Get withdrawals for a particular account at a given epoch (zero if claimed). * @param epoch epoch to get the withdrawals for the account at * @param account account to get the withdrawals for * @return withdrawals for the account at the epoch */ function withdrawalsOf(uint256 epoch, address account) external view returns (uint256); /** * @notice Get a total amount of the collateral that can be slashed for a given account. * @param account account to get the slashable collateral for * @return total amount of the account's slashable collateral */ function slashableBalanceOf( address account ) external view returns (uint256); /** * @notice Deposit collateral into the vault. * @param onBehalfOf account the deposit is made on behalf of * @param amount amount of the collateral to deposit * @return depositedAmount real amount of the collateral deposited * @return mintedShares amount of the active shares minted */ function deposit( address onBehalfOf, uint256 amount ) external returns (uint256 depositedAmount, uint256 mintedShares); /** * @notice Withdraw collateral from the vault (it will be claimable after the next epoch). * @param claimer account that needs to claim the withdrawal * @param amount amount of the collateral to withdraw * @return burnedShares amount of the active shares burned * @return mintedShares amount of the epoch withdrawal shares minted */ function withdraw(address claimer, uint256 amount) external returns (uint256 burnedShares, uint256 mintedShares); /** * @notice Redeem collateral from the vault (it will be claimable after the next epoch). * @param claimer account that needs to claim the withdrawal * @param shares amount of the active shares to redeem * @return withdrawnAssets amount of the collateral withdrawn * @return mintedShares amount of the epoch withdrawal shares minted */ function redeem(address claimer, uint256 shares) external returns (uint256 withdrawnAssets, uint256 mintedShares); /** * @notice Claim collateral from the vault. * @param recipient account that receives the collateral * @param epoch epoch to claim the collateral for * @return amount amount of the collateral claimed */ function claim(address recipient, uint256 epoch) external returns (uint256 amount); /** * @notice Claim collateral from the vault for multiple epochs. * @param recipient account that receives the collateral * @param epochs epochs to claim the collateral for * @return amount amount of the collateral claimed */ function claimBatch(address recipient, uint256[] calldata epochs) external returns (uint256 amount); /** * @notice Slash callback for burning collateral. * @param amount amount to slash * @param captureTimestamp time point when the stake was captured * @return slashedAmount real amount of the collateral slashed * @dev Only the slasher can call this function. */ function onSlash(uint256 amount, uint48 captureTimestamp) external returns (uint256 slashedAmount); /** * @notice Enable/disable deposit whitelist. * @param status if enabling deposit whitelist * @dev Only a DEPOSIT_WHITELIST_SET_ROLE holder can call this function. */ function setDepositWhitelist( bool status ) external; /** * @notice Set a depositor whitelist status. * @param account account for which the whitelist status is set * @param status if whitelisting the account * @dev Only a DEPOSITOR_WHITELIST_ROLE holder can call this function. */ function setDepositorWhitelistStatus(address account, bool status) external; /** * @notice Enable/disable deposit limit. * @param status if enabling deposit limit * @dev Only a IS_DEPOSIT_LIMIT_SET_ROLE holder can call this function. */ function setIsDepositLimit( bool status ) external; /** * @notice Set a deposit limit. * @param limit deposit limit (maximum amount of the collateral that can be in the vault simultaneously) * @dev Only a DEPOSIT_LIMIT_SET_ROLE holder can call this function. */ function setDepositLimit( uint256 limit ) external; /** * @notice Set a delegator. * @param delegator vault's delegator to delegate the stake to networks and operators * @dev Can be set only once. */ function setDelegator( address delegator ) external; /** * @notice Set a slasher. * @param slasher vault's slasher to provide a slashing mechanism to networks * @dev Can be set only once. */ function setSlasher( address slasher ) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IStakerRewards { /** * @notice Emitted when a reward is distributed. * @param network network on behalf of which the reward is distributed * @param token address of the token * @param amount amount of tokens * @param data some used data */ event DistributeRewards(address indexed network, address indexed token, uint256 amount, bytes data); /** * @notice Get a version of the staker rewards contract (different versions mean different interfaces). * @return version of the staker rewards contract * @dev Must return 1 for this one. */ function version() external view returns (uint64); /** * @notice Get an amount of rewards claimable by a particular account of a given token. * @param token address of the token * @param account address of the claimer * @param data some data to use * @return amount of claimable tokens */ function claimable(address token, address account, bytes calldata data) external view returns (uint256); /** * @notice Distribute rewards on behalf of a particular network using a given token. * @param network network on behalf of which the reward to distribute * @param token address of the token * @param amount amount of tokens * @param data some data to use */ function distributeRewards(address network, address token, uint256 amount, bytes calldata data) external; /** * @notice Claim rewards using a given token. * @param recipient address of the tokens' recipient * @param token address of the token * @param data some data to use */ function claimRewards(address recipient, address token, bytes calldata data) external; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.25; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface IDefaultCollateral is IERC20 { /** * @notice Emitted when debt is issued. * @param issuer address of the debt's issuer * @param recipient address that should receive the underlying asset * @param debtIssued amount of the debt issued */ event IssueDebt(address indexed issuer, address indexed recipient, uint256 debtIssued); /** * @notice Emitted when debt is repaid. * @param issuer address of the debt's issuer * @param recipient address that received the underlying asset * @param debtRepaid amount of the debt repaid */ event RepayDebt(address indexed issuer, address indexed recipient, uint256 debtRepaid); /** * @notice Get the collateral's underlying asset. * @return asset address of the underlying asset */ function asset() external view returns (address); /** * @notice Get a total amount of repaid debt. * @return total repaid debt */ function totalRepaidDebt() external view returns (uint256); /** * @notice Get an amount of repaid debt created by a particular issuer. * @param issuer address of the debt's issuer * @return particular issuer's repaid debt */ function issuerRepaidDebt(address issuer) external view returns (uint256); /** * @notice Get an amount of repaid debt to a particular recipient. * @param recipient address that received the underlying asset * @return particular recipient's repaid debt */ function recipientRepaidDebt(address recipient) external view returns (uint256); /** * @notice Get an amount of repaid debt for a particular issuer-recipient pair. * @param issuer address of the debt's issuer * @param recipient address that received the underlying asset * @return particular pair's repaid debt */ function repaidDebt(address issuer, address recipient) external view returns (uint256); /** * @notice Get a total amount of debt. * @return total debt */ function totalDebt() external view returns (uint256); /** * @notice Get a current debt created by a particular issuer. * @param issuer address of the debt's issuer * @return particular issuer's debt */ function issuerDebt(address issuer) external view returns (uint256); /** * @notice Get a current debt to a particular recipient. * @param recipient address that should receive the underlying asset * @return particular recipient's debt */ function recipientDebt(address recipient) external view returns (uint256); /** * @notice Get a current debt for a particular issuer-recipient pair. * @param issuer address of the debt's issuer * @param recipient address that should receive the underlying asset * @return particular pair's debt */ function debt(address issuer, address recipient) external view returns (uint256); /** * @notice Burn a given amount of the collateral, and increase a debt of the underlying asset for the caller. * @param recipient address that should receive the underlying asset * @param amount amount of the collateral */ function issueDebt(address recipient, uint256 amount) external; error NotLimitIncreaser(); error InsufficientDeposit(); error ExceedsLimit(); error InsufficientWithdraw(); error InsufficientIssueDebt(); /** * @notice Emmited when deposit happens. * @param depositor address of the depositor * @param recipient address of the collateral's recipient * @param amount amount of the collateral minted */ event Deposit(address indexed depositor, address indexed recipient, uint256 amount); /** * @notice Emmited when withdrawal happens. * @param withdrawer address of the withdrawer * @param recipient address of the underlying asset's recipient * @param amount amount of the collateral burned */ event Withdraw(address indexed withdrawer, address indexed recipient, uint256 amount); /** * @notice Emmited when limit is increased. * @param amount amount to increase the limit by */ event IncreaseLimit(uint256 amount); /** * @notice Emmited when new limit increaser is set. * @param limitIncreaser address of the new limit increaser */ event SetLimitIncreaser(address indexed limitIncreaser); /** * @notice Get a maximum possible collateral total supply. * @return maximum collateral total supply */ function limit() external view returns (uint256); /** * @notice Get an address of the limit increaser. * @return address of the limit increaser */ function limitIncreaser() external view returns (address); /** * @notice Deposit a given amount of the underlying asset, and mint the collateral to a particular recipient. * @param recipient address of the collateral's recipient * @param amount amount of the underlying asset * @return amount of the collateral minted */ function deposit(address recipient, uint256 amount) external returns (uint256); /** * @notice Deposit a given amount of the underlying asset using a permit functionality, and mint the collateral to a particular recipient. * @param recipient address of the collateral's recipient * @param amount amount of the underlying asset * @param deadline timestamp of the signature's deadline * @param v v component of the signature * @param r r component of the signature * @param s s component of the signature * @return amount of the collateral minted */ function deposit( address recipient, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external returns (uint256); /** * @notice Withdraw a given amount of the underlying asset, and transfer it to a particular recipient. * @param recipient address of the underlying asset's recipient * @param amount amount of the underlying asset */ function withdraw(address recipient, uint256 amount) external; /** * @notice Increase a limit of maximum collateral total supply. * @param amount amount to increase the limit by * @dev Called only by limitIncreaser. */ function increaseLimit(uint256 amount) external; /** * @notice Set a new limit increaser. * @param limitIncreaser address of the new limit increaser * @dev Called only by limitIncreaser. */ function setLimitIncreaser(address limitIncreaser) external; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.25; interface IDepositStrategy { struct DepositData { uint256 subvaultIndex; uint256 deposit; } function calculateDepositAmounts(address vault, uint256 assets) external view returns (DepositData[] memory subvaultsData); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.25; interface IRebalanceStrategy { struct RebalanceData { uint256 subvaultIndex; uint256 deposit; uint256 claimable; uint256 staked; } function calculateRebalanceAmounts(address vault) external view returns (RebalanceData[] memory subvaultsData); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.25; interface IWithdrawalStrategy { struct WithdrawalData { uint256 subvaultIndex; uint256 claimable; uint256 pending; uint256 staked; } function calculateWithdrawalAmounts(address vault, uint256 amount) external view returns (WithdrawalData[] memory subvaultsData); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol) pragma solidity ^0.8.20; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControl { /** * @dev The `account` is missing a role. */ error AccessControlUnauthorizedAccount(address account, bytes32 neededRole); /** * @dev The caller of a function is not the expected one. * * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}. */ error AccessControlBadConfirmation(); /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` * * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. */ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, an admin role * bearer except when using {AccessControl-_setupRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) external view returns (bool); /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {AccessControl-_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) external view returns (bytes32); /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) external; /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) external; /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `callerConfirmation`. */ function renounceRole(bytes32 role, address callerConfirmation) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol) pragma solidity ^0.8.20; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @dev Muldiv operation overflow. */ error MathOverflowedMulDiv(); enum Rounding { Floor, // Toward negative infinity Ceil, // Toward positive infinity Trunc, // Toward zero Expand // Away from zero } /** * @dev Returns the addition of two unsigned integers, with an overflow flag. */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } } /** * @dev Returns the subtraction of two unsigned integers, with an overflow flag. */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b > a) return (false, 0); return (true, a - b); } } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a / b); } } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a % b); } } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds towards infinity instead * of rounding towards zero. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { if (b == 0) { // Guarantee the same behavior as in a regular Solidity division. return a / b; } // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or * denominator == 0. * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by * Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0 = x * y; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. if (denominator <= prod1) { revert MathOverflowedMulDiv(); } /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. // Always >= 1. See https://cs.stackexchange.com/q/138556/92363. uint256 twos = denominator & (0 - denominator); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also // works in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded * towards zero. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256 of a positive value rounded towards zero. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0); } } /** * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers. */ function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) { return uint8(rounding) % 2 == 1; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.25; import {IProtocolAdapter} from "../adapters/IProtocolAdapter.sol"; import {IWithdrawalQueue} from "../queues/IWithdrawalQueue.sol"; import {IDepositStrategy} from "../strategies/IDepositStrategy.sol"; import {IRebalanceStrategy} from "../strategies/IRebalanceStrategy.sol"; import {IWithdrawalStrategy} from "../strategies/IWithdrawalStrategy.sol"; import {IDefaultCollateral} from "../tokens/IDefaultCollateral.sol"; import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import { ERC4626Upgradeable, IERC4626 } from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC4626Upgradeable.sol"; import {IERC20, SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {Address} from "@openzeppelin/contracts/utils/Address.sol"; import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; interface IMultiVaultStorage { enum Protocol { SYMBIOTIC, EIGEN_LAYER, ERC4626 } struct Subvault { Protocol protocol; address vault; address withdrawalQueue; } struct RewardData { address distributionFarm; address curatorTreasury; address token; uint256 curatorFeeD6; Protocol protocol; bytes data; } struct MultiStorage { address depositStrategy; address withdrawalStrategy; address rebalanceStrategy; Subvault[] subvaults; mapping(address subvault => uint256 index) indexOfSubvault; mapping(uint256 id => RewardData) rewardData; EnumerableSet.UintSet farmIds; address defaultCollateral; address symbioticAdapter; address eigenLayerAdapter; address erc4626Adapter; bytes32[16] _gap; } function subvaultsCount() external view returns (uint256); function subvaultAt(uint256 index) external view returns (Subvault memory); function indexOfSubvault(address subvault) external view returns (uint256); function farmIds() external view returns (uint256[] memory); function farmCount() external view returns (uint256); function farmIdAt(uint256 index) external view returns (uint256); function farmIdsContains(uint256 farmId) external view returns (bool); function defaultCollateral() external view returns (IDefaultCollateral); function depositStrategy() external view returns (IDepositStrategy); function withdrawalStrategy() external view returns (IWithdrawalStrategy); function rebalanceStrategy() external view returns (IRebalanceStrategy); function eigenLayerAdapter() external view returns (IProtocolAdapter); function symbioticAdapter() external view returns (IProtocolAdapter); function erc4626Adapter() external view returns (IProtocolAdapter); function adapterOf(Protocol protocol) external view returns (IProtocolAdapter); function rewardData(uint256 farmId) external view returns (RewardData memory); event SubvaultAdded( address indexed subvault, address withdrawalQueue, Protocol protocol, uint256 subvaultIndex ); event SubvaultRemoved(address indexed subvault, uint256 subvaultIndex); event SubvaultIndexChanged(address indexed subvault, uint256 oldIndex, uint256 newIndex); event RewardDataRemoved(uint256 indexed farmId); event RewardDataSet(uint256 indexed farmId, RewardData data); event DefaultCollateralSet(address indexed defaultCollateral); event DepositStrategySet(address indexed depositStrategy); event WithdrawalStrategySet(address indexed withdrawalStrategy); event RebalanceStrategySet(address indexed rebalanceStrategy); event SymbioticAdapterSet(address indexed symbioticAdapter); event EigenLayerAdapterSet(address indexed eigenLayerAdapter); event ERC4626AdapterSet(address indexed erc4626Adapter); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.25; import { ERC4626Upgradeable, IERC4626 } from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC4626Upgradeable.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; /** * @title IERC4626Vault * @notice Extension of the IERC4626 interface that introduces a `deposit` method with an additional referral address parameter. * @dev This interface enhances the standard ERC4626 vault by adding referral-based deposits. * @dev Also extends the VaultControl interface for managing deposit limits, deposit pause and withdrawal pause. */ interface IERC4626Vault is IERC4626 { /** * @notice Emitted when a deposit is made through a referral. * @param assets The amount of underlying tokens deposited. * @param receiver The address receiving the vault shares. * @param referral The address of the referral involved in the deposit. */ event ReferralDeposit(uint256 assets, address receiver, address referral); /** * @notice Mints vault shares to the `receiver` by depositing a specified amount of `assets` with an associated `referral`. * @param assets The amount of underlying tokens to be deposited. * @param receiver The address that will receive the vault shares. * @param referral The address of the referral associated with the deposit. * @return shares The amount of vault shares minted to the `receiver`. * * @custom:requirements * - The `assets` to be deposited MUST be greater than 0. * * @custom:effects * - Transfers the underlying tokens (`assets`) from the sender to the vault. * - Mints the corresponding `shares` to the `receiver`. * - Deposits the `assets` into the underlying bond. * - Emits a `ReferralDeposit` event. */ function deposit(uint256 assets, address receiver, address referral) external returns (uint256 shares); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.25; import "../interfaces/vaults/IVaultControl.sol"; import {VaultControlStorage} from "./VaultControlStorage.sol"; abstract contract VaultControl is IVaultControl, VaultControlStorage, ReentrancyGuardUpgradeable, AccessControlEnumerableUpgradeable { bytes32 private constant SET_LIMIT_ROLE = keccak256("SET_LIMIT_ROLE"); bytes32 private constant PAUSE_WITHDRAWALS_ROLE = keccak256("PAUSE_WITHDRAWALS_ROLE"); bytes32 private constant UNPAUSE_WITHDRAWALS_ROLE = keccak256("UNPAUSE_WITHDRAWALS_ROLE"); bytes32 private constant PAUSE_DEPOSITS_ROLE = keccak256("PAUSE_DEPOSITS_ROLE"); bytes32 private constant UNPAUSE_DEPOSITS_ROLE = keccak256("UNPAUSE_DEPOSITS_ROLE"); bytes32 private constant SET_DEPOSIT_WHITELIST_ROLE = keccak256("SET_DEPOSIT_WHITELIST_ROLE"); bytes32 private constant SET_DEPOSITOR_WHITELIST_STATUS_ROLE = keccak256("SET_DEPOSITOR_WHITELIST_STATUS_ROLE"); /** * @notice Initializes the vault control settings, including roles, limits, and pause states. * @param _admin The address of the admin who will be granted the `DEFAULT_ADMIN_ROLE`. * @param _limit The initial limit on deposits for the vault. * @param _depositPause A boolean indicating whether deposits should be paused initially. * @param _withdrawalPause A boolean indicating whether withdrawals should be paused initially. * @param _depositWhitelist A boolean indicating whether a deposit whitelist should be enabled initially. * * @dev This function performs the following steps: * - Initializes the reentrancy guard to prevent reentrancy attacks. * - Initializes the access control system, setting up roles and permissions. * - Grants the `DEFAULT_ADMIN_ROLE` to the specified `_admin` address. * - Initializes the vault control storage with the specified limits, pause states, and whitelist configuration. * - This function is intended to be called during the initialization phase and is protected by the `onlyInitializing` modifier. */ function __initializeVaultControl( address _admin, uint256 _limit, bool _depositPause, bool _withdrawalPause, bool _depositWhitelist ) internal onlyInitializing { __ReentrancyGuard_init(); __AccessControlEnumerable_init(); _grantRole(DEFAULT_ADMIN_ROLE, _admin); __initializeVaultControlStorage(_limit, _depositPause, _withdrawalPause, _depositWhitelist); } /// @inheritdoc IVaultControl function setLimit(uint256 _limit) external onlyRole(SET_LIMIT_ROLE) { _setLimit(_limit); } /// @inheritdoc IVaultControl function pauseWithdrawals() external onlyRole(PAUSE_WITHDRAWALS_ROLE) { _setWithdrawalPause(true); _revokeRole(PAUSE_WITHDRAWALS_ROLE, _msgSender()); } /// @inheritdoc IVaultControl function unpauseWithdrawals() external onlyRole(UNPAUSE_WITHDRAWALS_ROLE) { _setWithdrawalPause(false); } /// @inheritdoc IVaultControl function pauseDeposits() external onlyRole(PAUSE_DEPOSITS_ROLE) { _setDepositPause(true); _revokeRole(PAUSE_DEPOSITS_ROLE, _msgSender()); } /// @inheritdoc IVaultControl function unpauseDeposits() external onlyRole(UNPAUSE_DEPOSITS_ROLE) { _setDepositPause(false); } /// @inheritdoc IVaultControl function setDepositWhitelist(bool status) external onlyRole(SET_DEPOSIT_WHITELIST_ROLE) { _setDepositWhitelist(status); } /// @inheritdoc IVaultControl function setDepositorWhitelistStatus(address account, bool status) external onlyRole(SET_DEPOSITOR_WHITELIST_STATUS_ROLE) { _setDepositorWhitelistStatus(account, status); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.25; import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import {ContextUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol"; /** * @title IVaultControlStorage * @notice Interface for interacting with the storage and control states of a vault. * @dev Provides functions to manage deposit and withdrawal controls, limits, and whitelisting of depositors. */ interface IVaultControlStorage { /** * @notice Storage structure for vault control data. * @dev Used to manage vault settings such as deposit and withdrawal states, limits, and whitelist functionality. * @param depositPause Indicates if deposits are currently paused. * @param withdrawalPause Indicates if withdrawals are currently paused. * @param limit The current limit on deposits. * @param depositWhitelist Indicates if the deposit whitelist is enabled. * @param isDepositorWhitelisted Mapping to track the whitelist status of each depositor by address. */ struct Storage { bool depositPause; bool withdrawalPause; uint256 limit; bool depositWhitelist; mapping(address => bool) isDepositorWhitelisted; } /** * @notice Returns the current value of the `depositPause` state. * @dev When `true`, deposits into the vault are paused. * @return paused The current state of the deposit pause. */ function depositPause() external view returns (bool); /** * @notice Returns the current value of the `withdrawalPause` state. * @dev When `true`, withdrawals from the vault are paused. * @return paused The current state of the withdrawal pause. */ function withdrawalPause() external view returns (bool); /** * @notice Returns the current deposit limit. * @dev This limit can be applied to control the maximum allowed deposits. * @return limit The current limit value. */ function limit() external view returns (uint256); /** * @notice Returns the current value of the `depositWhitelist` state. * @dev When `true`, only whitelisted addresses are allowed to deposit into the vault. * @return whitelistEnabled The current state of the deposit whitelist. */ function depositWhitelist() external view returns (bool); /** * @notice Checks whether a given account is whitelisted for deposits. * @param account The address of the account to check. * @return isWhitelisted `true` if the account is whitelisted, `false` otherwise. */ function isDepositorWhitelisted(address account) external view returns (bool); /** * @notice Emitted when the vault's deposit limit is updated. * @param limit The new limit value. * @param timestamp The time at which the limit was set. * @param sender The address of the account that set the new limit. */ event LimitSet(uint256 limit, uint256 timestamp, address sender); /** * @notice Emitted when the deposit pause state is updated. * @param paused The new state of the deposit pause (`true` for paused, `false` for unpaused). * @param timestamp The time at which the pause state was set. * @param sender The address of the account that set the new state. */ event DepositPauseSet(bool paused, uint256 timestamp, address sender); /** * @notice Emitted when the withdrawal pause state is updated. * @param paused The new state of the withdrawal pause (`true` for paused, `false` for unpaused). * @param timestamp The time at which the pause state was set. * @param sender The address of the account that set the new state. */ event WithdrawalPauseSet(bool paused, uint256 timestamp, address sender); /** * @notice Emitted when the deposit whitelist state is updated. * @param status The new state of the deposit whitelist (`true` for enabled, `false` for disabled). * @param timestamp The time at which the whitelist state was set. * @param sender The address of the account that set the new state. */ event DepositWhitelistSet(bool status, uint256 timestamp, address sender); /** * @notice Emitted when a depositor's whitelist status is updated. * @param account The address of the account whose whitelist status was updated. * @param status The new whitelist status (`true` for whitelisted, `false` for not whitelisted). * @param timestamp The time at which the whitelist status was set. * @param sender The address of the account that set the new status. */ event DepositorWhitelistStatusSet( address account, bool status, uint256 timestamp, address sender ); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol) pragma solidity ^0.8.20; /** * @dev This is the interface that {BeaconProxy} expects of its beacon. */ interface IBeacon { /** * @dev Must return an address that can be used as a delegate call target. * * {UpgradeableBeacon} will check that this address is a contract. */ function implementation() external view returns (address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol) pragma solidity ^0.8.20; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev The ETH balance of the account is not enough to perform the operation. */ error AddressInsufficientBalance(address account); /** * @dev There's no code at `target` (it is not a contract). */ error AddressEmptyCode(address target); /** * @dev A call to an address target failed. The target may have reverted. */ error FailedInnerCall(); /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { if (address(this).balance < amount) { revert AddressInsufficientBalance(address(this)); } (bool success, ) = recipient.call{value: amount}(""); if (!success) { revert FailedInnerCall(); } } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason or custom error, it is bubbled * up by this function (like regular Solidity function calls). However, if * the call reverted with no returned reason, this function reverts with a * {FailedInnerCall} error. * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { if (address(this).balance < value) { revert AddressInsufficientBalance(address(this)); } (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an * unsuccessful call. */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata ) internal view returns (bytes memory) { if (!success) { _revert(returndata); } else { // only check if target is a contract if the call was successful and the return data is empty // otherwise we already know that it was a contract if (returndata.length == 0 && target.code.length == 0) { revert AddressEmptyCode(target); } return returndata; } } /** * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the * revert reason or with a default {FailedInnerCall} error. */ function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) { if (!success) { _revert(returndata); } else { return returndata; } } /** * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}. */ function _revert(bytes memory returndata) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert FailedInnerCall(); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol) // This file was procedurally generated from scripts/generate/templates/StorageSlot.js. pragma solidity ^0.8.20; /** * @dev Library for reading and writing primitive types to specific storage slots. * * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. * This library helps with reading and writing to such slots without the need for inline assembly. * * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. * * Example usage to set ERC1967 implementation slot: * ```solidity * contract ERC1967 { * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; * * function _getImplementation() internal view returns (address) { * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; * } * * function _setImplementation(address newImplementation) internal { * require(newImplementation.code.length > 0); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` */ library StorageSlot { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } struct StringSlot { string value; } struct BytesSlot { bytes value; } /** * @dev Returns an `AddressSlot` with member `value` located at `slot`. */ function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `StringSlot` with member `value` located at `slot`. */ function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `StringSlot` representation of the string storage pointer `store`. */ function getStringSlot(string storage store) internal pure returns (StringSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := store.slot } } /** * @dev Returns an `BytesSlot` with member `value` located at `slot`. */ function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`. */ function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := store.slot } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/Proxy.sol) pragma solidity ^0.8.20; /** * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to * be specified by overriding the virtual {_implementation} function. * * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a * different contract through the {_delegate} function. * * The success and return data of the delegated call will be returned back to the caller of the proxy. */ abstract contract Proxy { /** * @dev Delegates the current call to `implementation`. * * This function does not return to its internal call site, it will return directly to the external caller. */ function _delegate(address implementation) internal virtual { assembly { // Copy msg.data. We take full control of memory in this inline assembly // block because it will not return to Solidity code. We overwrite the // Solidity scratch pad at memory position 0. calldatacopy(0, 0, calldatasize()) // Call the implementation. // out and outsize are 0 because we don't know the size yet. let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0) // Copy the returned data. returndatacopy(0, 0, returndatasize()) switch result // delegatecall returns 0 on error. case 0 { revert(0, returndatasize()) } default { return(0, returndatasize()) } } } /** * @dev This is a virtual function that should be overridden so it returns the address to which the fallback * function and {_fallback} should delegate. */ function _implementation() internal view virtual returns (address); /** * @dev Delegates the current call to the address returned by `_implementation()`. * * This function does not return to its internal call site, it will return directly to the external caller. */ function _fallback() internal virtual { _delegate(_implementation()); } /** * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other * function in the contract matches the call data. */ fallback() external payable virtual { _fallback(); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol) pragma solidity ^0.8.20; import {Context} from "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * The initial owner is set to the address provided by the deployer. This can * later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; /** * @dev The caller account is not authorized to perform an operation. */ error OwnableUnauthorizedAccount(address account); /** * @dev The owner is not a valid owner account. (eg. `address(0)`) */ error OwnableInvalidOwner(address owner); event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the address provided by the deployer as the initial owner. */ constructor(address initialOwner) { if (initialOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(initialOwner); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { if (owner() != _msgSender()) { revert OwnableUnauthorizedAccount(_msgSender()); } } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { if (newOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.25; /** * @title IWithdrawalQueue * @notice Interface to handle the withdrawal process from the underlying vault. * @dev Provides functions to manage withdrawals, claimable assets, and interactions with vault epochs. */ interface IWithdrawalQueue { /** * @notice Returns the pending collateral amount for a specific account. * @param account The address of the account. * @return pendingAssets The total amount of pending collateral for the account. */ function pendingAssetsOf(address account) external view returns (uint256); /** * @notice Returns the claimable collateral amount for a specific account. * @param account The address of the account. * @return claimableAssets The total amount of claimable collateral for the account. */ function claimableAssetsOf(address account) external view returns (uint256); /** * @notice Claims collateral from the External Vault for a specified epoch. * @param epoch The epoch number from which to claim collateral. * * @custom:requirements * - The epoch MUST be claimable. * - There MUST be claimable withdrawals for the given epoch. * * @custom:effects * - Emits an `EpochClaimed` event. */ function pull(uint256 epoch) external; /** * @notice Finalizes the collateral claim process for a specific account and transfers it to the recipient. * @dev Transfers the lesser of the claimable amount or the specified maximum amount to the recipient. * @param account The address of the account to claim collateral from. * @param recipient The address of the recipient receiving the collateral. * @param maxAmount The maximum amount of collateral to be claimed. * @return amount The actual amount of collateral claimed and transferred. * * @custom:requirements * - `msg.sender` MUST be the vault or the account itself. * - The claimable amount MUST be greater than zero. * - There MUST be claimable withdrawals for the given account. * * @custom:effects * - Emits a `Claimed` event. */ function claim(address account, address recipient, uint256 maxAmount) external returns (uint256 amount); function transferPendingAssets(address recipient, uint256 assets) external; function claimer() external view returns (address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.20; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ```solidity * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Storage of the initializable contract. * * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions * when using with upgradeable contracts. * * @custom:storage-location erc7201:openzeppelin.storage.Initializable */ struct InitializableStorage { /** * @dev Indicates that the contract has been initialized. */ uint64 _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool _initializing; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00; /** * @dev The contract is already initialized. */ error InvalidInitialization(); /** * @dev The contract is not initializing. */ error NotInitializing(); /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint64 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in * production. * * Emits an {Initialized} event. */ modifier initializer() { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); // Cache values to avoid duplicated sloads bool isTopLevelCall = !$._initializing; uint64 initialized = $._initialized; // Allowed calls: // - initialSetup: the contract is not in the initializing state and no previous version was // initialized // - construction: the contract is initialized at version 1 (no reininitialization) and the // current contract is just being deployed bool initialSetup = initialized == 0 && isTopLevelCall; bool construction = initialized == 1 && address(this).code.length == 0; if (!initialSetup && !construction) { revert InvalidInitialization(); } $._initialized = 1; if (isTopLevelCall) { $._initializing = true; } _; if (isTopLevelCall) { $._initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint64 version) { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); if ($._initializing || $._initialized >= version) { revert InvalidInitialization(); } $._initialized = version; $._initializing = true; _; $._initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { _checkInitializing(); _; } /** * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}. */ function _checkInitializing() internal view virtual { if (!_isInitializing()) { revert NotInitializing(); } } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); if ($._initializing) { revert InvalidInitialization(); } if ($._initialized != type(uint64).max) { $._initialized = type(uint64).max; emit Initialized(type(uint64).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint64) { return _getInitializableStorage()._initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _getInitializableStorage()._initializing; } /** * @dev Returns a pointer to the storage namespace. */ // solhint-disable-next-line var-name-mixedcase function _getInitializableStorage() private pure returns (InitializableStorage storage $) { assembly { $.slot := INITIALIZABLE_STORAGE } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the value of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the value of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves a `value` amount of tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 value) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the * allowance mechanism. `value` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 value) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.20; import {IERC20} from "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. * * ==== Security Considerations * * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be * considered as an intention to spend the allowance in any specific way. The second is that because permits have * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be * generally recommended is: * * ```solidity * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} * doThing(..., value); * } * * function doThing(..., uint256 value) public { * token.safeTransferFrom(msg.sender, address(this), value); * ... * } * ``` * * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also * {SafeERC20-safeTransferFrom}). * * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so * contracts should have entry points that don't rely on permit. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. * * CAUTION: See Security Considerations above. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IMigratableEntity { error AlreadyInitialized(); error NotFactory(); error NotInitialized(); /** * @notice Get the factory's address. * @return address of the factory */ function FACTORY() external view returns (address); /** * @notice Get the entity's version. * @return version of the entity * @dev Starts from 1. */ function version() external view returns (uint64); /** * @notice Initialize this entity contract by using a given data and setting a particular version and owner. * @param initialVersion initial version of the entity * @param owner initial owner of the entity * @param data some data to use */ function initialize(uint64 initialVersion, address owner, bytes calldata data) external; /** * @notice Migrate this entity to a particular newer version using a given data. * @param newVersion new version of the entity * @param data some data to use */ function migrate(uint64 newVersion, bytes calldata data) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IVaultStorage { error InvalidTimestamp(); error NoPreviousEpoch(); /** * @notice Get a deposit whitelist enabler/disabler's role. * @return identifier of the whitelist enabler/disabler role */ function DEPOSIT_WHITELIST_SET_ROLE() external view returns (bytes32); /** * @notice Get a depositor whitelist status setter's role. * @return identifier of the depositor whitelist status setter role */ function DEPOSITOR_WHITELIST_ROLE() external view returns (bytes32); /** * @notice Get a deposit limit enabler/disabler's role. * @return identifier of the deposit limit enabler/disabler role */ function IS_DEPOSIT_LIMIT_SET_ROLE() external view returns (bytes32); /** * @notice Get a deposit limit setter's role. * @return identifier of the deposit limit setter role */ function DEPOSIT_LIMIT_SET_ROLE() external view returns (bytes32); /** * @notice Get the delegator factory's address. * @return address of the delegator factory */ function DELEGATOR_FACTORY() external view returns (address); /** * @notice Get the slasher factory's address. * @return address of the slasher factory */ function SLASHER_FACTORY() external view returns (address); /** * @notice Get a vault collateral. * @return address of the underlying collateral */ function collateral() external view returns (address); /** * @notice Get a burner to issue debt to (e.g., 0xdEaD or some unwrapper contract). * @return address of the burner */ function burner() external view returns (address); /** * @notice Get a delegator (it delegates the vault's stake to networks and operators). * @return address of the delegator */ function delegator() external view returns (address); /** * @notice Get if the delegator is initialized. * @return if the delegator is initialized */ function isDelegatorInitialized() external view returns (bool); /** * @notice Get a slasher (it provides networks a slashing mechanism). * @return address of the slasher */ function slasher() external view returns (address); /** * @notice Get if the slasher is initialized. * @return if the slasher is initialized */ function isSlasherInitialized() external view returns (bool); /** * @notice Get a time point of the epoch duration set. * @return time point of the epoch duration set */ function epochDurationInit() external view returns (uint48); /** * @notice Get a duration of the vault epoch. * @return duration of the epoch */ function epochDuration() external view returns (uint48); /** * @notice Get an epoch at a given timestamp. * @param timestamp time point to get the epoch at * @return epoch at the timestamp * @dev Reverts if the timestamp is less than the start of the epoch 0. */ function epochAt( uint48 timestamp ) external view returns (uint256); /** * @notice Get a current vault epoch. * @return current epoch */ function currentEpoch() external view returns (uint256); /** * @notice Get a start of the current vault epoch. * @return start of the current epoch */ function currentEpochStart() external view returns (uint48); /** * @notice Get a start of the previous vault epoch. * @return start of the previous epoch * @dev Reverts if the current epoch is 0. */ function previousEpochStart() external view returns (uint48); /** * @notice Get a start of the next vault epoch. * @return start of the next epoch */ function nextEpochStart() external view returns (uint48); /** * @notice Get if the deposit whitelist is enabled. * @return if the deposit whitelist is enabled */ function depositWhitelist() external view returns (bool); /** * @notice Get if a given account is whitelisted as a depositor. * @param account address to check * @return if the account is whitelisted as a depositor */ function isDepositorWhitelisted( address account ) external view returns (bool); /** * @notice Get if the deposit limit is set. * @return if the deposit limit is set */ function isDepositLimit() external view returns (bool); /** * @notice Get a deposit limit (maximum amount of the active stake that can be in the vault simultaneously). * @return deposit limit */ function depositLimit() external view returns (uint256); /** * @notice Get a total number of active shares in the vault at a given timestamp using a hint. * @param timestamp time point to get the total number of active shares at * @param hint hint for the checkpoint index * @return total number of active shares at the timestamp */ function activeSharesAt(uint48 timestamp, bytes memory hint) external view returns (uint256); /** * @notice Get a total number of active shares in the vault. * @return total number of active shares */ function activeShares() external view returns (uint256); /** * @notice Get a total amount of active stake in the vault at a given timestamp using a hint. * @param timestamp time point to get the total active stake at * @param hint hint for the checkpoint index * @return total amount of active stake at the timestamp */ function activeStakeAt(uint48 timestamp, bytes memory hint) external view returns (uint256); /** * @notice Get a total amount of active stake in the vault. * @return total amount of active stake */ function activeStake() external view returns (uint256); /** * @notice Get a total number of active shares for a particular account at a given timestamp using a hint. * @param account account to get the number of active shares for * @param timestamp time point to get the number of active shares for the account at * @param hint hint for the checkpoint index * @return number of active shares for the account at the timestamp */ function activeSharesOfAt(address account, uint48 timestamp, bytes memory hint) external view returns (uint256); /** * @notice Get a number of active shares for a particular account. * @param account account to get the number of active shares for * @return number of active shares for the account */ function activeSharesOf( address account ) external view returns (uint256); /** * @notice Get a total amount of the withdrawals at a given epoch. * @param epoch epoch to get the total amount of the withdrawals at * @return total amount of the withdrawals at the epoch */ function withdrawals( uint256 epoch ) external view returns (uint256); /** * @notice Get a total number of withdrawal shares at a given epoch. * @param epoch epoch to get the total number of withdrawal shares at * @return total number of withdrawal shares at the epoch */ function withdrawalShares( uint256 epoch ) external view returns (uint256); /** * @notice Get a number of withdrawal shares for a particular account at a given epoch (zero if claimed). * @param epoch epoch to get the number of withdrawal shares for the account at * @param account account to get the number of withdrawal shares for * @return number of withdrawal shares for the account at the epoch */ function withdrawalSharesOf(uint256 epoch, address account) external view returns (uint256); /** * @notice Get if the withdrawals are claimed for a particular account at a given epoch. * @param epoch epoch to check the withdrawals for the account at * @param account account to check the withdrawals for * @return if the withdrawals are claimed for the account at the epoch */ function isWithdrawalsClaimed(uint256 epoch, address account) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC4626.sol) pragma solidity ^0.8.20; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import {ERC20Upgradeable} from "../ERC20Upgradeable.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol"; import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; import {Initializable} from "../../../proxy/utils/Initializable.sol"; /** * @dev Implementation of the ERC4626 "Tokenized Vault Standard" as defined in * https://eips.ethereum.org/EIPS/eip-4626[EIP-4626]. * * This extension allows the minting and burning of "shares" (represented using the ERC20 inheritance) in exchange for * underlying "assets" through standardized {deposit}, {mint}, {redeem} and {burn} workflows. This contract extends * the ERC20 standard. Any additional extensions included along it would affect the "shares" token represented by this * contract and not the "assets" token which is an independent contract. * * [CAUTION] * ==== * In empty (or nearly empty) ERC-4626 vaults, deposits are at high risk of being stolen through frontrunning * with a "donation" to the vault that inflates the price of a share. This is variously known as a donation or inflation * attack and is essentially a problem of slippage. Vault deployers can protect against this attack by making an initial * deposit of a non-trivial amount of the asset, such that price manipulation becomes infeasible. Withdrawals may * similarly be affected by slippage. Users can protect against this attack as well as unexpected slippage in general by * verifying the amount received is as expected, using a wrapper that performs these checks such as * https://github.com/fei-protocol/ERC4626#erc4626router-and-base[ERC4626Router]. * * Since v4.9, this implementation uses virtual assets and shares to mitigate that risk. The `_decimalsOffset()` * corresponds to an offset in the decimal representation between the underlying asset's decimals and the vault * decimals. This offset also determines the rate of virtual shares to virtual assets in the vault, which itself * determines the initial exchange rate. While not fully preventing the attack, analysis shows that the default offset * (0) makes it non-profitable, as a result of the value being captured by the virtual shares (out of the attacker's * donation) matching the attacker's expected gains. With a larger offset, the attack becomes orders of magnitude more * expensive than it is profitable. More details about the underlying math can be found * xref:erc4626.adoc#inflation-attack[here]. * * The drawback of this approach is that the virtual shares do capture (a very small) part of the value being accrued * to the vault. Also, if the vault experiences losses, the users try to exit the vault, the virtual shares and assets * will cause the first user to exit to experience reduced losses in detriment to the last users that will experience * bigger losses. Developers willing to revert back to the pre-v4.9 behavior just need to override the * `_convertToShares` and `_convertToAssets` functions. * * To learn more, check out our xref:ROOT:erc4626.adoc[ERC-4626 guide]. * ==== */ abstract contract ERC4626Upgradeable is Initializable, ERC20Upgradeable, IERC4626 { using Math for uint256; /// @custom:storage-location erc7201:openzeppelin.storage.ERC4626 struct ERC4626Storage { IERC20 _asset; uint8 _underlyingDecimals; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ERC4626")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant ERC4626StorageLocation = 0x0773e532dfede91f04b12a73d3d2acd361424f41f76b4fb79f090161e36b4e00; function _getERC4626Storage() private pure returns (ERC4626Storage storage $) { assembly { $.slot := ERC4626StorageLocation } } /** * @dev Attempted to deposit more assets than the max amount for `receiver`. */ error ERC4626ExceededMaxDeposit(address receiver, uint256 assets, uint256 max); /** * @dev Attempted to mint more shares than the max amount for `receiver`. */ error ERC4626ExceededMaxMint(address receiver, uint256 shares, uint256 max); /** * @dev Attempted to withdraw more assets than the max amount for `receiver`. */ error ERC4626ExceededMaxWithdraw(address owner, uint256 assets, uint256 max); /** * @dev Attempted to redeem more shares than the max amount for `receiver`. */ error ERC4626ExceededMaxRedeem(address owner, uint256 shares, uint256 max); /** * @dev Set the underlying asset contract. This must be an ERC20-compatible contract (ERC20 or ERC777). */ function __ERC4626_init(IERC20 asset_) internal onlyInitializing { __ERC4626_init_unchained(asset_); } function __ERC4626_init_unchained(IERC20 asset_) internal onlyInitializing { ERC4626Storage storage $ = _getERC4626Storage(); (bool success, uint8 assetDecimals) = _tryGetAssetDecimals(asset_); $._underlyingDecimals = success ? assetDecimals : 18; $._asset = asset_; } /** * @dev Attempts to fetch the asset decimals. A return value of false indicates that the attempt failed in some way. */ function _tryGetAssetDecimals(IERC20 asset_) private view returns (bool, uint8) { (bool success, bytes memory encodedDecimals) = address(asset_).staticcall( abi.encodeCall(IERC20Metadata.decimals, ()) ); if (success && encodedDecimals.length >= 32) { uint256 returnedDecimals = abi.decode(encodedDecimals, (uint256)); if (returnedDecimals <= type(uint8).max) { return (true, uint8(returnedDecimals)); } } return (false, 0); } /** * @dev Decimals are computed by adding the decimal offset on top of the underlying asset's decimals. This * "original" value is cached during construction of the vault contract. If this read operation fails (e.g., the * asset has not been created yet), a default of 18 is used to represent the underlying asset's decimals. * * See {IERC20Metadata-decimals}. */ function decimals() public view virtual override(IERC20Metadata, ERC20Upgradeable) returns (uint8) { ERC4626Storage storage $ = _getERC4626Storage(); return $._underlyingDecimals + _decimalsOffset(); } /** @dev See {IERC4626-asset}. */ function asset() public view virtual returns (address) { ERC4626Storage storage $ = _getERC4626Storage(); return address($._asset); } /** @dev See {IERC4626-totalAssets}. */ function totalAssets() public view virtual returns (uint256) { ERC4626Storage storage $ = _getERC4626Storage(); return $._asset.balanceOf(address(this)); } /** @dev See {IERC4626-convertToShares}. */ function convertToShares(uint256 assets) public view virtual returns (uint256) { return _convertToShares(assets, Math.Rounding.Floor); } /** @dev See {IERC4626-convertToAssets}. */ function convertToAssets(uint256 shares) public view virtual returns (uint256) { return _convertToAssets(shares, Math.Rounding.Floor); } /** @dev See {IERC4626-maxDeposit}. */ function maxDeposit(address) public view virtual returns (uint256) { return type(uint256).max; } /** @dev See {IERC4626-maxMint}. */ function maxMint(address) public view virtual returns (uint256) { return type(uint256).max; } /** @dev See {IERC4626-maxWithdraw}. */ function maxWithdraw(address owner) public view virtual returns (uint256) { return _convertToAssets(balanceOf(owner), Math.Rounding.Floor); } /** @dev See {IERC4626-maxRedeem}. */ function maxRedeem(address owner) public view virtual returns (uint256) { return balanceOf(owner); } /** @dev See {IERC4626-previewDeposit}. */ function previewDeposit(uint256 assets) public view virtual returns (uint256) { return _convertToShares(assets, Math.Rounding.Floor); } /** @dev See {IERC4626-previewMint}. */ function previewMint(uint256 shares) public view virtual returns (uint256) { return _convertToAssets(shares, Math.Rounding.Ceil); } /** @dev See {IERC4626-previewWithdraw}. */ function previewWithdraw(uint256 assets) public view virtual returns (uint256) { return _convertToShares(assets, Math.Rounding.Ceil); } /** @dev See {IERC4626-previewRedeem}. */ function previewRedeem(uint256 shares) public view virtual returns (uint256) { return _convertToAssets(shares, Math.Rounding.Floor); } /** @dev See {IERC4626-deposit}. */ function deposit(uint256 assets, address receiver) public virtual returns (uint256) { uint256 maxAssets = maxDeposit(receiver); if (assets > maxAssets) { revert ERC4626ExceededMaxDeposit(receiver, assets, maxAssets); } uint256 shares = previewDeposit(assets); _deposit(_msgSender(), receiver, assets, shares); return shares; } /** @dev See {IERC4626-mint}. * * As opposed to {deposit}, minting is allowed even if the vault is in a state where the price of a share is zero. * In this case, the shares will be minted without requiring any assets to be deposited. */ function mint(uint256 shares, address receiver) public virtual returns (uint256) { uint256 maxShares = maxMint(receiver); if (shares > maxShares) { revert ERC4626ExceededMaxMint(receiver, shares, maxShares); } uint256 assets = previewMint(shares); _deposit(_msgSender(), receiver, assets, shares); return assets; } /** @dev See {IERC4626-withdraw}. */ function withdraw(uint256 assets, address receiver, address owner) public virtual returns (uint256) { uint256 maxAssets = maxWithdraw(owner); if (assets > maxAssets) { revert ERC4626ExceededMaxWithdraw(owner, assets, maxAssets); } uint256 shares = previewWithdraw(assets); _withdraw(_msgSender(), receiver, owner, assets, shares); return shares; } /** @dev See {IERC4626-redeem}. */ function redeem(uint256 shares, address receiver, address owner) public virtual returns (uint256) { uint256 maxShares = maxRedeem(owner); if (shares > maxShares) { revert ERC4626ExceededMaxRedeem(owner, shares, maxShares); } uint256 assets = previewRedeem(shares); _withdraw(_msgSender(), receiver, owner, assets, shares); return assets; } /** * @dev Internal conversion function (from assets to shares) with support for rounding direction. */ function _convertToShares(uint256 assets, Math.Rounding rounding) internal view virtual returns (uint256) { return assets.mulDiv(totalSupply() + 10 ** _decimalsOffset(), totalAssets() + 1, rounding); } /** * @dev Internal conversion function (from shares to assets) with support for rounding direction. */ function _convertToAssets(uint256 shares, Math.Rounding rounding) internal view virtual returns (uint256) { return shares.mulDiv(totalAssets() + 1, totalSupply() + 10 ** _decimalsOffset(), rounding); } /** * @dev Deposit/mint common workflow. */ function _deposit(address caller, address receiver, uint256 assets, uint256 shares) internal virtual { ERC4626Storage storage $ = _getERC4626Storage(); // If _asset is ERC777, `transferFrom` can trigger a reentrancy BEFORE the transfer happens through the // `tokensToSend` hook. On the other hand, the `tokenReceived` hook, that is triggered after the transfer, // calls the vault, which is assumed not malicious. // // Conclusion: we need to do the transfer before we mint so that any reentrancy would happen before the // assets are transferred and before the shares are minted, which is a valid state. // slither-disable-next-line reentrancy-no-eth SafeERC20.safeTransferFrom($._asset, caller, address(this), assets); _mint(receiver, shares); emit Deposit(caller, receiver, assets, shares); } /** * @dev Withdraw/redeem common workflow. */ function _withdraw( address caller, address receiver, address owner, uint256 assets, uint256 shares ) internal virtual { ERC4626Storage storage $ = _getERC4626Storage(); if (caller != owner) { _spendAllowance(owner, caller, shares); } // If _asset is ERC777, `transfer` can trigger a reentrancy AFTER the transfer happens through the // `tokensReceived` hook. On the other hand, the `tokensToSend` hook, that is triggered before the transfer, // calls the vault, which is assumed not malicious. // // Conclusion: we need to do the transfer after the burn so that any reentrancy would happen after the // shares are burned and after the assets are transferred, which is a valid state. _burn(owner, shares); SafeERC20.safeTransfer($._asset, receiver, assets); emit Withdraw(caller, receiver, owner, assets, shares); } function _decimalsOffset() internal view virtual returns (uint8) { return 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol) // This file was procedurally generated from scripts/generate/templates/EnumerableSet.js. pragma solidity ^0.8.20; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ```solidity * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. * * [WARNING] * ==== * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure * unusable. * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. * * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an * array of EnumerableSet. * ==== */ library EnumerableSet { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position is the index of the value in the `values` array plus 1. // Position 0 is used to mean a value is not in the set. mapping(bytes32 value => uint256) _positions; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._positions[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We cache the value's position to prevent multiple reads from the same storage slot uint256 position = set._positions[value]; if (position != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 valueIndex = position - 1; uint256 lastIndex = set._values.length - 1; if (valueIndex != lastIndex) { bytes32 lastValue = set._values[lastIndex]; // Move the lastValue to the index where the value to delete is set._values[valueIndex] = lastValue; // Update the tracked position of the lastValue (that was just moved) set._positions[lastValue] = position; } // Delete the slot where the moved value was stored set._values.pop(); // Delete the tracked position for the deleted slot delete set._positions[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._positions[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { return set._values[index]; } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function _values(Set storage set) private view returns (bytes32[] memory) { return set._values; } // Bytes32Set struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, index); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { bytes32[] memory store = _values(set._inner); bytes32[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint160(uint256(_at(set._inner, index)))); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(AddressSet storage set) internal view returns (address[] memory) { bytes32[] memory store = _values(set._inner); address[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values in the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(UintSet storage set) internal view returns (uint256[] memory) { bytes32[] memory store = _values(set._inner); uint256[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.25; import "./IVaultControlStorage.sol"; import {AccessControlEnumerableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/extensions/AccessControlEnumerableUpgradeable.sol"; import {ERC4626Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC4626Upgradeable.sol"; import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; /** * @title IVaultControl * @notice Interface for controlling the operational state of a vault, including deposits, withdrawals, limits, and whitelisting. * @dev Extends IVaultControlStorage for managing storage and settings related to vault operations. */ interface IVaultControl is IVaultControlStorage { /** * @notice Sets a new limit for the vault to restrict the total value of assets held. * @dev Can only be called by an address with the `SET_LIMIT_ROLE`. * @param _limit The new limit value to be set. */ function setLimit(uint256 _limit) external; /** * @notice Pauses withdrawals from the vault. * @dev Once paused, no withdrawals can be processed until unpaused. * @dev Can only be called by an address with the `PAUSE_WITHDRAWALS_ROLE`. * @custom:effects * - Emits a `WithdrawalPauseSet` event with `paused` set to `true`. * - Revokes the `PAUSE_WITHDRAWALS_ROLE` from `msg.sender` */ function pauseWithdrawals() external; /** * @notice Unpauses withdrawals from the vault. * @dev Once unpaused, withdrawals can be processed again. * @dev Can only be called by an address with the `UNPAUSE_WITHDRAWALS_ROLE`. * @custom:effects * - Emits a `WithdrawalPauseSet` event with `paused` set to `false`. */ function unpauseWithdrawals() external; /** * @notice Pauses deposits into the vault. * @dev Once paused, no deposits can be made until unpaused. * @dev Can only be called by an address with the `PAUSE_DEPOSITS_ROLE`. * @custom:effects * - Emits a `DepositPauseSet` event with `paused` set to `true`. * - Revokes the `PAUSE_DEPOSITS_ROLE` from `msg.sender` */ function pauseDeposits() external; /** * @notice Unpauses deposits into the vault. * @dev Once unpaused, deposits can be made again. * @dev Can only be called by an address with the `UNPAUSE_DEPOSITS_ROLE`. * @custom:effects * - Emits a `DepositPauseSet` event with `paused` set to `false`. */ function unpauseDeposits() external; /** * @notice Sets the deposit whitelist status for the vault. * @dev When the whitelist is enabled, only addresses on the whitelist can deposit into the vault. * @dev Can only be called by an address with the `SET_DEPOSIT_WHITELIST_ROLE`. * @param status The new whitelist status (`true` to enable, `false` to disable). * @custom:effects * - Emits a `DepositWhitelistSet` event indicating the new whitelist status. */ function setDepositWhitelist(bool status) external; /** * @notice Updates the whitelist status of a specific account. * @dev Allows the contract to grant or revoke the ability of an account to make deposits based on the whitelist. * @dev Can only be called by an address with the `SET_DEPOSITOR_WHITELIST_STATUS_ROLE`. * @param account The address of the account to be updated. * @param status The new whitelist status for the account (`true` for whitelisted, `false` for not whitelisted). * @custom:effects * - Emits a `DepositorWhitelistStatusSet` event indicating the updated whitelist status for the account. */ function setDepositorWhitelistStatus(address account, bool status) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) pragma solidity ^0.8.20; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) pragma solidity ^0.8.20; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import {ContextUpgradeable} from "../../utils/ContextUpgradeable.sol"; import {IERC20Errors} from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol"; import {Initializable} from "../../proxy/utils/Initializable.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * * TIP: For a detailed writeup see our guide * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * The default value of {decimals} is 18. To change this, you should override * this function so it returns a different value. * * We have followed general OpenZeppelin Contracts guidelines: functions revert * instead returning `false` on failure. This behavior is nonetheless * conventional and does not conflict with the expectations of ERC20 * applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. */ abstract contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20, IERC20Metadata, IERC20Errors { /// @custom:storage-location erc7201:openzeppelin.storage.ERC20 struct ERC20Storage { mapping(address account => uint256) _balances; mapping(address account => mapping(address spender => uint256)) _allowances; uint256 _totalSupply; string _name; string _symbol; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ERC20")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant ERC20StorageLocation = 0x52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00; function _getERC20Storage() private pure returns (ERC20Storage storage $) { assembly { $.slot := ERC20StorageLocation } } /** * @dev Sets the values for {name} and {symbol}. * * All two of these values are immutable: they can only be set once during * construction. */ function __ERC20_init(string memory name_, string memory symbol_) internal onlyInitializing { __ERC20_init_unchained(name_, symbol_); } function __ERC20_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing { ERC20Storage storage $ = _getERC20Storage(); $._name = name_; $._symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual returns (string memory) { ERC20Storage storage $ = _getERC20Storage(); return $._name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual returns (string memory) { ERC20Storage storage $ = _getERC20Storage(); return $._symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5.05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the default value returned by this function, unless * it's overridden. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual returns (uint256) { ERC20Storage storage $ = _getERC20Storage(); return $._totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual returns (uint256) { ERC20Storage storage $ = _getERC20Storage(); return $._balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `to` cannot be the zero address. * - the caller must have a balance of at least `value`. */ function transfer(address to, uint256 value) public virtual returns (bool) { address owner = _msgSender(); _transfer(owner, to, value); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual returns (uint256) { ERC20Storage storage $ = _getERC20Storage(); return $._allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * NOTE: If `value` is the maximum `uint256`, the allowance is not updated on * `transferFrom`. This is semantically equivalent to an infinite approval. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 value) public virtual returns (bool) { address owner = _msgSender(); _approve(owner, spender, value); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * NOTE: Does not update the allowance if the current allowance * is the maximum `uint256`. * * Requirements: * * - `from` and `to` cannot be the zero address. * - `from` must have a balance of at least `value`. * - the caller must have allowance for ``from``'s tokens of at least * `value`. */ function transferFrom(address from, address to, uint256 value) public virtual returns (bool) { address spender = _msgSender(); _spendAllowance(from, spender, value); _transfer(from, to, value); return true; } /** * @dev Moves a `value` amount of tokens from `from` to `to`. * * This internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * NOTE: This function is not virtual, {_update} should be overridden instead. */ function _transfer(address from, address to, uint256 value) internal { if (from == address(0)) { revert ERC20InvalidSender(address(0)); } if (to == address(0)) { revert ERC20InvalidReceiver(address(0)); } _update(from, to, value); } /** * @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from` * (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding * this function. * * Emits a {Transfer} event. */ function _update(address from, address to, uint256 value) internal virtual { ERC20Storage storage $ = _getERC20Storage(); if (from == address(0)) { // Overflow check required: The rest of the code assumes that totalSupply never overflows $._totalSupply += value; } else { uint256 fromBalance = $._balances[from]; if (fromBalance < value) { revert ERC20InsufficientBalance(from, fromBalance, value); } unchecked { // Overflow not possible: value <= fromBalance <= totalSupply. $._balances[from] = fromBalance - value; } } if (to == address(0)) { unchecked { // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply. $._totalSupply -= value; } } else { unchecked { // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256. $._balances[to] += value; } } emit Transfer(from, to, value); } /** * @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0). * Relies on the `_update` mechanism * * Emits a {Transfer} event with `from` set to the zero address. * * NOTE: This function is not virtual, {_update} should be overridden instead. */ function _mint(address account, uint256 value) internal { if (account == address(0)) { revert ERC20InvalidReceiver(address(0)); } _update(address(0), account, value); } /** * @dev Destroys a `value` amount of tokens from `account`, lowering the total supply. * Relies on the `_update` mechanism. * * Emits a {Transfer} event with `to` set to the zero address. * * NOTE: This function is not virtual, {_update} should be overridden instead */ function _burn(address account, uint256 value) internal { if (account == address(0)) { revert ERC20InvalidSender(address(0)); } _update(account, address(0), value); } /** * @dev Sets `value` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. * * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument. */ function _approve(address owner, address spender, uint256 value) internal { _approve(owner, spender, value, true); } /** * @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event. * * By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by * `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any * `Approval` event during `transferFrom` operations. * * Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to * true using the following override: * ``` * function _approve(address owner, address spender, uint256 value, bool) internal virtual override { * super._approve(owner, spender, value, true); * } * ``` * * Requirements are the same as {_approve}. */ function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual { ERC20Storage storage $ = _getERC20Storage(); if (owner == address(0)) { revert ERC20InvalidApprover(address(0)); } if (spender == address(0)) { revert ERC20InvalidSpender(address(0)); } $._allowances[owner][spender] = value; if (emitEvent) { emit Approval(owner, spender, value); } } /** * @dev Updates `owner` s allowance for `spender` based on spent `value`. * * Does not update the allowance value in case of infinite allowance. * Revert if not enough allowance is available. * * Does not emit an {Approval} event. */ function _spendAllowance(address owner, address spender, uint256 value) internal virtual { uint256 currentAllowance = allowance(owner, spender); if (currentAllowance != type(uint256).max) { if (currentAllowance < value) { revert ERC20InsufficientAllowance(spender, currentAllowance, value); } unchecked { _approve(owner, spender, currentAllowance - value, false); } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol) pragma solidity ^0.8.20; import {IAccessControlEnumerable} from "@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol"; import {AccessControlUpgradeable} from "../AccessControlUpgradeable.sol"; import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import {Initializable} from "../../proxy/utils/Initializable.sol"; /** * @dev Extension of {AccessControl} that allows enumerating the members of each role. */ abstract contract AccessControlEnumerableUpgradeable is Initializable, IAccessControlEnumerable, AccessControlUpgradeable { using EnumerableSet for EnumerableSet.AddressSet; /// @custom:storage-location erc7201:openzeppelin.storage.AccessControlEnumerable struct AccessControlEnumerableStorage { mapping(bytes32 role => EnumerableSet.AddressSet) _roleMembers; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.AccessControlEnumerable")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant AccessControlEnumerableStorageLocation = 0xc1f6fe24621ce81ec5827caf0253cadb74709b061630e6b55e82371705932000; function _getAccessControlEnumerableStorage() private pure returns (AccessControlEnumerableStorage storage $) { assembly { $.slot := AccessControlEnumerableStorageLocation } } function __AccessControlEnumerable_init() internal onlyInitializing { } function __AccessControlEnumerable_init_unchained() internal onlyInitializing { } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId); } /** * @dev Returns one of the accounts that have `role`. `index` must be a * value between 0 and {getRoleMemberCount}, non-inclusive. * * Role bearers are not sorted in any particular way, and their ordering may * change at any point. * * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure * you perform all queries on the same block. See the following * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] * for more information. */ function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) { AccessControlEnumerableStorage storage $ = _getAccessControlEnumerableStorage(); return $._roleMembers[role].at(index); } /** * @dev Returns the number of accounts that have `role`. Can be used * together with {getRoleMember} to enumerate all bearers of a role. */ function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) { AccessControlEnumerableStorage storage $ = _getAccessControlEnumerableStorage(); return $._roleMembers[role].length(); } /** * @dev Overload {AccessControl-_grantRole} to track enumerable memberships */ function _grantRole(bytes32 role, address account) internal virtual override returns (bool) { AccessControlEnumerableStorage storage $ = _getAccessControlEnumerableStorage(); bool granted = super._grantRole(role, account); if (granted) { $._roleMembers[role].add(account); } return granted; } /** * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships */ function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) { AccessControlEnumerableStorage storage $ = _getAccessControlEnumerableStorage(); bool revoked = super._revokeRole(role, account); if (revoked) { $._roleMembers[role].remove(account); } return revoked; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol) pragma solidity ^0.8.20; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuardUpgradeable is Initializable { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant NOT_ENTERED = 1; uint256 private constant ENTERED = 2; /// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard struct ReentrancyGuardStorage { uint256 _status; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant ReentrancyGuardStorageLocation = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00; function _getReentrancyGuardStorage() private pure returns (ReentrancyGuardStorage storage $) { assembly { $.slot := ReentrancyGuardStorageLocation } } /** * @dev Unauthorized reentrant call. */ error ReentrancyGuardReentrantCall(); function __ReentrancyGuard_init() internal onlyInitializing { __ReentrancyGuard_init_unchained(); } function __ReentrancyGuard_init_unchained() internal onlyInitializing { ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); $._status = NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); // On the first call to nonReentrant, _status will be NOT_ENTERED if ($._status == ENTERED) { revert ReentrancyGuardReentrantCall(); } // Any calls to nonReentrant after this point will fail $._status = ENTERED; } function _nonReentrantAfter() private { ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) $._status = NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); return $._status == ENTERED; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol) pragma solidity ^0.8.20; /** * @dev Standard ERC20 Errors * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens. */ interface IERC20Errors { /** * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. * @param balance Current balance for the interacting account. * @param needed Minimum amount required to perform a transfer. */ error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed); /** * @dev Indicates a failure with the token `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. */ error ERC20InvalidSender(address sender); /** * @dev Indicates a failure with the token `receiver`. Used in transfers. * @param receiver Address to which tokens are being transferred. */ error ERC20InvalidReceiver(address receiver); /** * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers. * @param spender Address that may be allowed to operate on tokens without being their owner. * @param allowance Amount of tokens a `spender` is allowed to operate with. * @param needed Minimum amount required to perform a transfer. */ error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed); /** * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. * @param approver Address initiating an approval operation. */ error ERC20InvalidApprover(address approver); /** * @dev Indicates a failure with the `spender` to be approved. Used in approvals. * @param spender Address that may be allowed to operate on tokens without being their owner. */ error ERC20InvalidSpender(address spender); } /** * @dev Standard ERC721 Errors * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens. */ interface IERC721Errors { /** * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20. * Used in balance queries. * @param owner Address of the current owner of a token. */ error ERC721InvalidOwner(address owner); /** * @dev Indicates a `tokenId` whose `owner` is the zero address. * @param tokenId Identifier number of a token. */ error ERC721NonexistentToken(uint256 tokenId); /** * @dev Indicates an error related to the ownership over a particular token. Used in transfers. * @param sender Address whose tokens are being transferred. * @param tokenId Identifier number of a token. * @param owner Address of the current owner of a token. */ error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner); /** * @dev Indicates a failure with the token `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. */ error ERC721InvalidSender(address sender); /** * @dev Indicates a failure with the token `receiver`. Used in transfers. * @param receiver Address to which tokens are being transferred. */ error ERC721InvalidReceiver(address receiver); /** * @dev Indicates a failure with the `operator`’s approval. Used in transfers. * @param operator Address that may be allowed to operate on tokens without being their owner. * @param tokenId Identifier number of a token. */ error ERC721InsufficientApproval(address operator, uint256 tokenId); /** * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. * @param approver Address initiating an approval operation. */ error ERC721InvalidApprover(address approver); /** * @dev Indicates a failure with the `operator` to be approved. Used in approvals. * @param operator Address that may be allowed to operate on tokens without being their owner. */ error ERC721InvalidOperator(address operator); } /** * @dev Standard ERC1155 Errors * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens. */ interface IERC1155Errors { /** * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. * @param balance Current balance for the interacting account. * @param needed Minimum amount required to perform a transfer. * @param tokenId Identifier number of a token. */ error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId); /** * @dev Indicates a failure with the token `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. */ error ERC1155InvalidSender(address sender); /** * @dev Indicates a failure with the token `receiver`. Used in transfers. * @param receiver Address to which tokens are being transferred. */ error ERC1155InvalidReceiver(address receiver); /** * @dev Indicates a failure with the `operator`’s approval. Used in transfers. * @param operator Address that may be allowed to operate on tokens without being their owner. * @param owner Address of the current owner of a token. */ error ERC1155MissingApprovalForAll(address operator, address owner); /** * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. * @param approver Address initiating an approval operation. */ error ERC1155InvalidApprover(address approver); /** * @dev Indicates a failure with the `operator` to be approved. Used in approvals. * @param operator Address that may be allowed to operate on tokens without being their owner. */ error ERC1155InvalidOperator(address operator); /** * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation. * Used in batch transfers. * @param idsLength Length of the array of token identifiers * @param valuesLength Length of the array of token amounts */ error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol) pragma solidity ^0.8.20; import {IAccessControl} from "../IAccessControl.sol"; /** * @dev External interface of AccessControlEnumerable declared to support ERC165 detection. */ interface IAccessControlEnumerable is IAccessControl { /** * @dev Returns one of the accounts that have `role`. `index` must be a * value between 0 and {getRoleMemberCount}, non-inclusive. * * Role bearers are not sorted in any particular way, and their ordering may * change at any point. * * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure * you perform all queries on the same block. See the following * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] * for more information. */ function getRoleMember(bytes32 role, uint256 index) external view returns (address); /** * @dev Returns the number of accounts that have `role`. Can be used * together with {getRoleMember} to enumerate all bearers of a role. */ function getRoleMemberCount(bytes32 role) external view returns (uint256); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol) pragma solidity ^0.8.20; import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol"; import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol"; import {ERC165Upgradeable} from "../utils/introspection/ERC165Upgradeable.sol"; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Contract module that allows children to implement role-based access * control mechanisms. This is a lightweight version that doesn't allow enumerating role * members except through off-chain means by accessing the contract event logs. Some * applications may benefit from on-chain enumerability, for those cases see * {AccessControlEnumerable}. * * Roles are referred to by their `bytes32` identifier. These should be exposed * in the external API and be unique. The best way to achieve this is by * using `public constant` hash digests: * * ```solidity * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); * ``` * * Roles can be used to represent a set of permissions. To restrict access to a * function call, use {hasRole}: * * ```solidity * function foo() public { * require(hasRole(MY_ROLE, msg.sender)); * ... * } * ``` * * Roles can be granted and revoked dynamically via the {grantRole} and * {revokeRole} functions. Each role has an associated admin role, and only * accounts that have a role's admin role can call {grantRole} and {revokeRole}. * * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means * that only accounts with this role will be able to grant or revoke other * roles. More complex role relationships can be created by using * {_setRoleAdmin}. * * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to * grant and revoke this role. Extra precautions should be taken to secure * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} * to enforce additional security measures for this role. */ abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControl, ERC165Upgradeable { struct RoleData { mapping(address account => bool) hasRole; bytes32 adminRole; } bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; /// @custom:storage-location erc7201:openzeppelin.storage.AccessControl struct AccessControlStorage { mapping(bytes32 role => RoleData) _roles; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.AccessControl")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant AccessControlStorageLocation = 0x02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800; function _getAccessControlStorage() private pure returns (AccessControlStorage storage $) { assembly { $.slot := AccessControlStorageLocation } } /** * @dev Modifier that checks that an account has a specific role. Reverts * with an {AccessControlUnauthorizedAccount} error including the required role. */ modifier onlyRole(bytes32 role) { _checkRole(role); _; } function __AccessControl_init() internal onlyInitializing { } function __AccessControl_init_unchained() internal onlyInitializing { } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId); } /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) public view virtual returns (bool) { AccessControlStorage storage $ = _getAccessControlStorage(); return $._roles[role].hasRole[account]; } /** * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()` * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier. */ function _checkRole(bytes32 role) internal view virtual { _checkRole(role, _msgSender()); } /** * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account` * is missing `role`. */ function _checkRole(bytes32 role, address account) internal view virtual { if (!hasRole(role, account)) { revert AccessControlUnauthorizedAccount(account, role); } } /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) { AccessControlStorage storage $ = _getAccessControlStorage(); return $._roles[role].adminRole; } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleGranted} event. */ function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) { _grantRole(role, account); } /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleRevoked} event. */ function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) { _revokeRole(role, account); } /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been revoked `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `callerConfirmation`. * * May emit a {RoleRevoked} event. */ function renounceRole(bytes32 role, address callerConfirmation) public virtual { if (callerConfirmation != _msgSender()) { revert AccessControlBadConfirmation(); } _revokeRole(role, callerConfirmation); } /** * @dev Sets `adminRole` as ``role``'s admin role. * * Emits a {RoleAdminChanged} event. */ function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { AccessControlStorage storage $ = _getAccessControlStorage(); bytes32 previousAdminRole = getRoleAdmin(role); $._roles[role].adminRole = adminRole; emit RoleAdminChanged(role, previousAdminRole, adminRole); } /** * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted. * * Internal function without access restriction. * * May emit a {RoleGranted} event. */ function _grantRole(bytes32 role, address account) internal virtual returns (bool) { AccessControlStorage storage $ = _getAccessControlStorage(); if (!hasRole(role, account)) { $._roles[role].hasRole[account] = true; emit RoleGranted(role, account, _msgSender()); return true; } else { return false; } } /** * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked. * * Internal function without access restriction. * * May emit a {RoleRevoked} event. */ function _revokeRole(bytes32 role, address account) internal virtual returns (bool) { AccessControlStorage storage $ = _getAccessControlStorage(); if (hasRole(role, account)) { $._roles[role].hasRole[account] = false; emit RoleRevoked(role, account, _msgSender()); return true; } else { return false; } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol) pragma solidity ^0.8.20; import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; import {Initializable} from "../../proxy/utils/Initializable.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` */ abstract contract ERC165Upgradeable is Initializable, IERC165 { function __ERC165_init() internal onlyInitializing { } function __ERC165_init_unchained() internal onlyInitializing { } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
{ "remappings": [ "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/", "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/", "@symbiotic/core/=lib/core/src/", "@symbiotic/core-test/=lib/core/test/", "@symbiotic/rewards/=lib/rewards/src/", "@symbiotic/burners/=lib/burners/src/", "@eigenlayer-interfaces/=lib/eigenlayer-contracts/src/contracts/interfaces/", "@eigenlayer-src/=lib/eigenlayer-contracts/src/contracts/", "@openzeppelin-upgrades-v4.9.0/=lib/eigenlayer-contracts/lib/openzeppelin-contracts-upgradeable-v4.9.0/", "@openzeppelin-upgrades/=lib/eigenlayer-contracts/lib/openzeppelin-contracts-upgradeable/", "@openzeppelin-v4.9.0/=lib/eigenlayer-contracts/lib/openzeppelin-contracts-v4.9.0/", "@symbioticfi/core/=lib/burners/lib/core/", "burners/=lib/burners/", "core/=lib/core/", "ds-test/=lib/eigenlayer-contracts/lib/ds-test/src/", "eigenlayer-contracts/=lib/eigenlayer-contracts/", "erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/", "forge-std/=lib/forge-std/src/", "openzeppelin-contracts-upgradeable-v4.9.0/=lib/eigenlayer-contracts/lib/openzeppelin-contracts-upgradeable-v4.9.0/", "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/", "openzeppelin-contracts-v4.9.0/=lib/eigenlayer-contracts/lib/openzeppelin-contracts-v4.9.0/", "openzeppelin-contracts/=lib/openzeppelin-contracts/", "openzeppelin/=lib/eigenlayer-contracts/lib/openzeppelin-contracts-v4.9.0/contracts/", "rewards/=lib/rewards/", "zeus-templates/=lib/eigenlayer-contracts/lib/zeus-templates/src/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "cancun", "viaIR": false, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"symbioticVaultFactory_","type":"address"},{"internalType":"address","name":"strategy_","type":"address"},{"internalType":"address","name":"multiVaultImplementation_","type":"address"},{"internalType":"address","name":"symbioticWithdrawalQueueImplementation_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"multiVault","type":"address"},{"indexed":true,"internalType":"address","name":"symbioticAdapter","type":"address"},{"indexed":true,"internalType":"bytes32","name":"salt","type":"bytes32"},{"components":[{"internalType":"address","name":"admin","type":"address"},{"internalType":"address","name":"proxyAdmin","type":"address"},{"internalType":"address","name":"curator","type":"address"},{"internalType":"address","name":"symbioticVault","type":"address"},{"internalType":"address","name":"depositWrapper","type":"address"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"address","name":"defaultCollateral","type":"address"},{"internalType":"uint256","name":"limit","type":"uint256"},{"internalType":"bool","name":"depositPause","type":"bool"},{"internalType":"bool","name":"withdrawalPause","type":"bool"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint64","name":"minRatioD18","type":"uint64"},{"internalType":"uint64","name":"maxRatioD18","type":"uint64"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"indexed":false,"internalType":"struct MultiVaultDeployScript.DeployParams","name":"deployParams","type":"tuple"}],"name":"Deployed","type":"event"},{"inputs":[{"components":[{"internalType":"address","name":"admin","type":"address"},{"internalType":"address","name":"proxyAdmin","type":"address"},{"internalType":"address","name":"curator","type":"address"},{"internalType":"address","name":"symbioticVault","type":"address"},{"internalType":"address","name":"depositWrapper","type":"address"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"address","name":"defaultCollateral","type":"address"},{"internalType":"uint256","name":"limit","type":"uint256"},{"internalType":"bool","name":"depositPause","type":"bool"},{"internalType":"bool","name":"withdrawalPause","type":"bool"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint64","name":"minRatioD18","type":"uint64"},{"internalType":"uint64","name":"maxRatioD18","type":"uint64"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"internalType":"struct MultiVaultDeployScript.DeployParams","name":"params","type":"tuple"}],"name":"calculateSalt","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"admin","type":"address"},{"internalType":"address","name":"proxyAdmin","type":"address"},{"internalType":"address","name":"curator","type":"address"},{"internalType":"address","name":"symbioticVault","type":"address"},{"internalType":"address","name":"depositWrapper","type":"address"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"address","name":"defaultCollateral","type":"address"},{"internalType":"uint256","name":"limit","type":"uint256"},{"internalType":"bool","name":"depositPause","type":"bool"},{"internalType":"bool","name":"withdrawalPause","type":"bool"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint64","name":"minRatioD18","type":"uint64"},{"internalType":"uint64","name":"maxRatioD18","type":"uint64"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"internalType":"struct MultiVaultDeployScript.DeployParams","name":"params","type":"tuple"}],"name":"deploy","outputs":[{"internalType":"contract MultiVault","name":"multiVault","type":"address"},{"internalType":"address","name":"symbioticAdapter","type":"address"},{"components":[{"internalType":"address","name":"admin","type":"address"},{"internalType":"address","name":"proxyAdmin","type":"address"},{"internalType":"address","name":"curator","type":"address"},{"internalType":"address","name":"symbioticVault","type":"address"},{"internalType":"address","name":"depositWrapper","type":"address"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"address","name":"defaultCollateral","type":"address"},{"internalType":"uint256","name":"limit","type":"uint256"},{"internalType":"bool","name":"depositPause","type":"bool"},{"internalType":"bool","name":"withdrawalPause","type":"bool"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint64","name":"minRatioD18","type":"uint64"},{"internalType":"uint64","name":"maxRatioD18","type":"uint64"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"internalType":"struct MultiVaultDeployScript.DeployParams","name":"","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"deployments","outputs":[{"components":[{"internalType":"address","name":"multiVault","type":"address"},{"internalType":"address","name":"symbioticAdapter","type":"address"},{"components":[{"internalType":"address","name":"admin","type":"address"},{"internalType":"address","name":"proxyAdmin","type":"address"},{"internalType":"address","name":"curator","type":"address"},{"internalType":"address","name":"symbioticVault","type":"address"},{"internalType":"address","name":"depositWrapper","type":"address"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"address","name":"defaultCollateral","type":"address"},{"internalType":"uint256","name":"limit","type":"uint256"},{"internalType":"bool","name":"depositPause","type":"bool"},{"internalType":"bool","name":"withdrawalPause","type":"bool"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint64","name":"minRatioD18","type":"uint64"},{"internalType":"uint64","name":"maxRatioD18","type":"uint64"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"internalType":"struct MultiVaultDeployScript.DeployParams","name":"params","type":"tuple"}],"internalType":"struct MultiVaultDeployScript.Deployment","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"multiVaultImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"strategy","outputs":[{"internalType":"contract RatiosStrategy","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbioticVaultFactory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbioticWithdrawalQueueImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
610100604052348015610010575f80fd5b506040516154d93803806154d983398101604081905261002f9161006c565b6001600160a01b0393841660805291831660a052821660c0521660e0526100bd565b80516001600160a01b0381168114610067575f80fd5b919050565b5f805f806080858703121561007f575f80fd5b61008885610051565b935061009660208601610051565b92506100a460408601610051565b91506100b260608601610051565b905092959194509250565b60805160a05160c05160e0516153b46101255f395f81816083015261047701525f818160c701526103dd01525f81816101780152818161067501528181610cb201528181610dcc015281816110f5015261116c01525f818160ee015261045601526153b45ff3fe608060405234801561000f575f80fd5b506004361061007a575f3560e01c8063374040171161005857806337404017146101105780634238b3af146101305780635dbe8f8b14610152578063a8c62e7614610173575f80fd5b806308e85a781461007e578063187a4ad9146100c257806323ee74fb146100e9575b5f80fd5b6100a57f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b6100a57f000000000000000000000000000000000000000000000000000000000000000081565b6100a57f000000000000000000000000000000000000000000000000000000000000000081565b61012361011e3660046116dd565b61019a565b6040516100b9919061187f565b61014361013e3660046118c1565b6103c4565b6040516100b9939291906118ff565b6101656101603660046118c1565b6115f7565b6040519081526020016100b9565b6100a57f000000000000000000000000000000000000000000000000000000000000000081565b6101a2611626565b5f828152602081815260409182902082516060808201855282546001600160a01b039081168352600184015481168386015285516101e081018752600285018054831682526003860154831696820196909652600485015482168188015260058501548216928101929092526006840154811660808301526007840154811660a083015260088401541660c0820152600983015460e0820152600a83015460ff808216151561010084810191909152909104161515610120820152600b83018054929593949386019391926101408401919061027d90611933565b80601f01602080910402602001604051908101604052809291908181526020018280546102a990611933565b80156102f45780601f106102cb576101008083540402835291602001916102f4565b820191905f5260205f20905b8154815290600101906020018083116102d757829003601f168201915b50505050508152602001600a8201805461030d90611933565b80601f016020809104026020016040519081016040528092919081815260200182805461033990611933565b80156103845780601f1061035b57610100808354040283529160200191610384565b820191905f5260205f20905b81548152906001019060200180831161036757829003601f168201915b5050509183525050600b8201546001600160401b038082166020840152600160401b909104166040820152600c9091015460609091015290525092915050565b5f806103ce611649565b5f6103d8856115f7565b9050807f000000000000000000000000000000000000000000000000000000000000000061040c6040880160208901611986565b604080515f8152602081019182905290610425906116c3565b610431939291906119b3565b8190604051809103905ff590508015801561044e573d5f803e3d5ffd5b5093505f81857f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000006104a660408b0160208c01611986565b6040516104b2906116d0565b6001600160a01b0394851681529284166020840152908316604083015290911660608201526080018190604051809103905ff59050801580156104f7573d5f803e3d5ffd5b509050818161050c6040890160208a01611986565b604080515f8152602081019182905290610525906116c3565b610531939291906119b3565b8190604051809103905ff590508015801561054e573d5f803e3d5ffd5b50604080516101e08101825230815260e089013560208201529195505f919081016105816101208a016101008b016119ed565b1515815260200161059a6101408a016101208b016119ed565b151581526020015f6105b260a08b0160808c01611986565b6001600160a01b0316141581526020016105d260c08a0160a08b01611986565b6001600160a01b031681526020016105ee6101408a018a611a06565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152505050908252506020016106356101608a018a611a06565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152505050908252506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016602082018190526040820181905260608201526080016106bb60e08a0160c08b01611986565b6001600160a01b03908116825287811660208301525f60408084018290526060909301529051639bfe9e2360e01b8152919250871690639bfe9e2390610705908490600401611a4f565b5f604051808303815f87803b15801561071c575f80fd5b505af115801561072e573d5f803e3d5ffd5b505f925061074591505060a0890160808a01611986565b6001600160a01b0316146108a857604051632f2ff15d60e01b81527f1867ae69910bc7238ccbbb445aa11a0dbdd472b851b7fac0c991101aca0a360d60048201819052306024830152906001600160a01b03881690632f2ff15d906044015f604051808303815f87803b1580156107ba575f80fd5b505af11580156107cc573d5f803e3d5ffd5b5050506001600160a01b038816905063a28614666107f060a08b0160808c01611986565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152600160248201526044015f604051808303815f87803b158015610835575f80fd5b505af1158015610847573d5f803e3d5ffd5b5050604051631b2b455f60e11b8152600481018490523060248201526001600160a01b038a1692506336568abe91506044015f604051808303815f87803b158015610890575f80fd5b505af11580156108a2573d5f803e3d5ffd5b50505050505b856001600160a01b0316632f2ff15d876001600160a01b031663a217fddf6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108f3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109179190611bb9565b61092460208b018b611986565b6040516001600160e01b031960e085901b16815260048101929092526001600160a01b031660248201526044015f604051808303815f87803b158015610968575f80fd5b505af115801561097a573d5f803e3d5ffd5b50505050856001600160a01b0316632f2ff15d876001600160a01b031663c2e9dcd66040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109c9573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109ed9190611bb9565b6109fa60208b018b611986565b6040516001600160e01b031960e085901b16815260048101929092526001600160a01b031660248201526044015f604051808303815f87803b158015610a3e575f80fd5b505af1158015610a50573d5f803e3d5ffd5b50505050856001600160a01b0316632f2ff15d876001600160a01b0316635680e1456040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a9f573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ac39190611bb9565b610ad360608b0160408c01611986565b6040516001600160e01b031960e085901b16815260048101929092526001600160a01b031660248201526044015f604051808303815f87803b158015610b17575f80fd5b505af1158015610b29573d5f803e3d5ffd5b50505050856001600160a01b0316632f2ff15d876001600160a01b0316633a2bbe496040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b78573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b9c9190611bb9565b610bac60608b0160408c01611986565b6040516001600160e01b031960e085901b16815260048101929092526001600160a01b031660248201526044015f604051808303815f87803b158015610bf0575f80fd5b505af1158015610c02573d5f803e3d5ffd5b5050506001600160a01b0387169050632f2ff15d7f6e5811d60b7d57973a97208b6158fed3b8e064ca747403e6a8c81f56a8f9e75f610c4760608b0160408c01611986565b6040516001600160e01b031960e085901b16815260048101929092526001600160a01b031660248201526044015f604051808303815f87803b158015610c8b575f80fd5b505af1158015610c9d573d5f803e3d5ffd5b50505050856001600160a01b0316632f2ff15d7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663cf8dda3b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d0c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d309190611bb9565b610d4060608b0160408c01611986565b6040516001600160e01b031960e085901b16815260048101929092526001600160a01b031660248201526044015f604051808303815f87803b158015610d84575f80fd5b505af1158015610d96573d5f803e3d5ffd5b505f9250610dad9150506080890160608a01611986565b6001600160a01b0316146113c157856001600160a01b0316632f2ff15d7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663cf8dda3b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e26573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e4a9190611bb9565b6040516001600160e01b031960e084901b16815260048101919091523060248201526044015f604051808303815f87803b158015610e86575f80fd5b505af1158015610e98573d5f803e3d5ffd5b50505050856001600160a01b0316632f2ff15d876001600160a01b0316633a2bbe496040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ee7573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f0b9190611bb9565b6040516001600160e01b031960e084901b16815260048101919091523060248201526044015f604051808303815f87803b158015610f47575f80fd5b505af1158015610f59573d5f803e3d5ffd5b5050506001600160a01b0387169050634b6a58fe610f7d60808a0160608b01611986565b5f6040518363ffffffff1660e01b8152600401610f9b929190611bd0565b5f604051808303815f87803b158015610fb2575f80fd5b505af1158015610fc4573d5f803e3d5ffd5b505f925060019150610fd39050565b604051908082528060200260200182016040528015610ffc578160200160208202803683370190505b50905061100f6080890160608a01611986565b815f8151811061102157611021611c09565b6001600160a01b0392909216602092830291909101909101526040805160018082528183019092525f91816020015b604080518082019091525f808252602082015281526020019060019003908161105057505060408051808201909152909150806110956101a08c016101808d01611c33565b6001600160401b031681526020016110b56101c08c016101a08d01611c33565b6001600160401b0316815250815f815181106110d3576110d3611c09565b6020908102919091010152604051637166956d60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690637166956d9061112e908b9086908690600401611c4c565b5f604051808303815f87803b158015611145575f80fd5b505af1158015611157573d5f803e3d5ffd5b50505050876001600160a01b03166336568abe7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663cf8dda3b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111c6573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111ea9190611bb9565b6040516001600160e01b031960e084901b16815260048101919091523060248201526044015f604051808303815f87803b158015611226575f80fd5b505af1158015611238573d5f803e3d5ffd5b50505050876001600160a01b03166336568abe896001600160a01b0316633a2bbe496040518163ffffffff1660e01b8152600401602060405180830381865afa158015611287573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112ab9190611bb9565b6040516001600160e01b031960e084901b16815260048101919091523060248201526044015f604051808303815f87803b1580156112e7575f80fd5b505af11580156112f9573d5f803e3d5ffd5b50505050876001600160a01b03166336568abe896001600160a01b031663a217fddf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611348573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061136c9190611bb9565b6040516001600160e01b031960e084901b16815260048101919091523060248201526044015f604051808303815f87803b1580156113a8575f80fd5b505af11580156113ba573d5f803e3d5ffd5b5050505050505b82856001600160a01b0316876001600160a01b03167f941c9195b6fb499b0f8e1b227134859845dadb7b8e5f025a9e682118ea8bb34a8a6040516114059190611d65565b60405180910390a46040518060600160405280876001600160a01b03168152602001866001600160a01b031681526020018861144090611fdc565b90525f8481526020818152604091829020835181546001600160a01b03199081166001600160a01b039283161783558584015160018401805483169184169190911790558585015180516002850180548416918516919091178155948101516003850180548416918516919091179055948501516004840180548316918416919091179055606085015160058401805483169184169190911790556080850151600684018054831691841691909117905560a0850151600784018054831691841691909117905560c0850151600884018054909216921691909117905560e0830151600982015561010080840151600a8301805461012087015161ffff1990911692151561ff0019169290921791151590920217905561014083015190929190600b84019061156f908261216b565b50610160820151600a820190611585908261216b565b50610180820151600b820180546101a08501516001600160401b03908116600160401b026fffffffffffffffffffffffffffffffff199092169316929092179190911790556101c090910151600c909101555086905085886115e681611fdc565b929a91995091975095505050505050565b5f816040516020016116099190611d65565b604051602081830303815290604052805190602001209050919050565b604080516060810182525f8082526020820152908101611644611649565b905290565b604080516101e0810182525f8082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e0820183905261010082018390526101208201839052610140820181905261016082015261018081018290526101a081018290526101c081019190915290565b610dbc8061222b83390190565b61239880612fe783390190565b5f602082840312156116ed575f80fd5b5035919050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b80516001600160a01b031682525f6101e0602083015161174d60208601826001600160a01b03169052565b50604083015161176860408601826001600160a01b03169052565b50606083015161178360608601826001600160a01b03169052565b50608083015161179e60808601826001600160a01b03169052565b5060a08301516117b960a08601826001600160a01b03169052565b5060c08301516117d460c08601826001600160a01b03169052565b5060e083015160e0850152610100808401516117f38287018215159052565b5050610120838101511515908501526101408084015181860183905261181b838701826116f4565b92505050610160808401518583038287015261183783826116f4565b9250505061018080840151611856828701826001600160401b03169052565b50506101a0838101516001600160401b0316908501526101c09283015192909301919091525090565b602081525f60018060a01b038084511660208401528060208501511660408401525060408301516060808401526118b96080840182611722565b949350505050565b5f602082840312156118d1575f80fd5b81356001600160401b038111156118e6575f80fd5b82016101e081850312156118f8575f80fd5b9392505050565b6001600160a01b038481168252831660208201526060604082018190525f9061192a90830184611722565b95945050505050565b600181811c9082168061194757607f821691505b60208210810361196557634e487b7160e01b5f52602260045260245ffd5b50919050565b80356001600160a01b0381168114611981575f80fd5b919050565b5f60208284031215611996575f80fd5b6118f88261196b565b634e487b7160e01b5f52604160045260245ffd5b6001600160a01b038481168252831660208201526060604082018190525f9061192a908301846116f4565b80358015158114611981575f80fd5b5f602082840312156119fd575f80fd5b6118f8826119de565b5f808335601e19843603018112611a1b575f80fd5b8301803591506001600160401b03821115611a34575f80fd5b602001915036819003821315611a48575f80fd5b9250929050565b60208152611a696020820183516001600160a01b03169052565b602082015160408201525f6040830151611a87606084018215159052565b506060830151801515608084015250608083015180151560a08401525060a08301516001600160a01b03811660c08401525060c08301516101e08060e0850152611ad56102008501836116f4565b915060e0850151610100601f198685030181870152611af484836116f4565b935080870151915050610120611b14818701836001600160a01b03169052565b8601519050610140611b30868201836001600160a01b03169052565b8601519050610160611b4c868201836001600160a01b03169052565b8601519050610180611b68868201836001600160a01b03169052565b86015190506101a0611b84868201836001600160a01b03169052565b86015190506101c0611ba0868201836001600160a01b03169052565b909501516001600160a01b031693019290925250919050565b5f60208284031215611bc9575f80fd5b5051919050565b6001600160a01b03831681526040810160038310611bfc57634e487b7160e01b5f52602160045260245ffd5b8260208301529392505050565b634e487b7160e01b5f52603260045260245ffd5b80356001600160401b0381168114611981575f80fd5b5f60208284031215611c43575f80fd5b6118f882611c1d565b6001600160a01b0384811682526060602080840182905285519184018290525f92868201929091906080860190855b81811015611c99578551851683529483019491830191600101611c7b565b50506040935085810360408701528092508651808252828201935082880191505f5b81811015611ced57825180516001600160401b0390811687529085015116848601529385019391830191600101611cbb565b50929998505050505050505050565b5f808335601e19843603018112611d11575f80fd5b83016020810192503590506001600160401b03811115611d2f575f80fd5b803603821315611a48575f80fd5b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b60208152611d8660208201611d798461196b565b6001600160a01b03169052565b5f611d936020840161196b565b6001600160a01b038116604084015250611daf6040840161196b565b6001600160a01b038116606084015250611dcb6060840161196b565b6001600160a01b038116608084015250611de76080840161196b565b6001600160a01b03811660a084015250611e0360a0840161196b565b6001600160a01b03811660c084015250611e1f60c0840161196b565b6001600160a01b03811660e08401525061010060e084013581840152611e468185016119de565b9050610120611e588185018315159052565b611e638186016119de565b915050610140611e768185018315159052565b611e8281860186611cfc565b925090506101e06101608181870152611ea061020087018585611d3d565b9350611eae81880188611cfc565b93509050610180601f198786030181880152611ecb858584611d3d565b9450611ed8818901611c1d565b935050506101a0611ef3818701846001600160401b03169052565b611efe818801611c1d565b9250506101c0611f18818701846001600160401b03169052565b9590950135939094019290925250919050565b6040516101e081016001600160401b0381118282101715611f4e57611f4e61199f565b60405290565b5f82601f830112611f63575f80fd5b81356001600160401b0380821115611f7d57611f7d61199f565b604051601f8301601f19908116603f01168101908282118183101715611fa557611fa561199f565b81604052838152866020858801011115611fbd575f80fd5b836020870160208301375f602085830101528094505050505092915050565b5f6101e08236031215611fed575f80fd5b611ff5611f2b565b611ffe8361196b565b815261200c6020840161196b565b602082015261201d6040840161196b565b604082015261202e6060840161196b565b606082015261203f6080840161196b565b608082015261205060a0840161196b565b60a082015261206160c0840161196b565b60c082015260e083013560e082015261010061207e8185016119de565b908201526101206120908482016119de565b90820152610140838101356001600160401b03808211156120af575f80fd5b6120bb36838801611f54565b838501526101609250828601359150808211156120d6575f80fd5b506120e336828701611f54565b8284015250506101806120f7818501611c1d565b908201526101a0612109848201611c1d565b908201526101c092830135928101929092525090565b601f82111561216657805f5260205f20601f840160051c810160208510156121445750805b601f840160051c820191505b81811015612163575f8155600101612150565b50505b505050565b81516001600160401b038111156121845761218461199f565b612198816121928454611933565b8461211f565b602080601f8311600181146121cb575f84156121b45750858301515b5f19600386901b1c1916600185901b178555612222565b5f85815260208120601f198616915b828110156121f9578886015182559484019460019091019084016121da565b508582101561221657878501515f19600388901b60f8161c191681555b505060018460011b0185555b50505050505056fe60a0604052604051610dbc380380610dbc8339810160408190526100229161036a565b828161002e828261008c565b50508160405161003d9061032e565b6001600160a01b039091168152602001604051809103905ff080158015610066573d5f803e3d5ffd5b506001600160a01b031660805261008461007f60805190565b6100ea565b50505061044b565b61009582610157565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a28051156100de576100d982826101d5565b505050565b6100e6610248565b5050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6101295f80516020610d9c833981519152546001600160a01b031690565b604080516001600160a01b03928316815291841660208301520160405180910390a161015481610269565b50565b806001600160a01b03163b5f0361019157604051634c9c8ce360e01b81526001600160a01b03821660048201526024015b60405180910390fd5b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5b80546001600160a01b0319166001600160a01b039290921691909117905550565b60605f80846001600160a01b0316846040516101f19190610435565b5f60405180830381855af49150503d805f8114610229576040519150601f19603f3d011682016040523d82523d5f602084013e61022e565b606091505b50909250905061023f8583836102a6565b95945050505050565b34156102675760405163b398979f60e01b815260040160405180910390fd5b565b6001600160a01b03811661029257604051633173bdd160e11b81525f6004820152602401610188565b805f80516020610d9c8339815191526101b4565b6060826102bb576102b682610305565b6102fe565b81511580156102d257506001600160a01b0384163b155b156102fb57604051639996b31560e01b81526001600160a01b0385166004820152602401610188565b50805b9392505050565b8051156103155780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b6104e7806108b583390190565b80516001600160a01b0381168114610351575f80fd5b919050565b634e487b7160e01b5f52604160045260245ffd5b5f805f6060848603121561037c575f80fd5b6103858461033b565b92506103936020850161033b565b60408501519092506001600160401b03808211156103af575f80fd5b818601915086601f8301126103c2575f80fd5b8151818111156103d4576103d4610356565b604051601f8201601f19908116603f011681019083821181831017156103fc576103fc610356565b81604052828152896020848701011115610414575f80fd5b8260208601602083015e5f6020848301015280955050505050509250925092565b5f82518060208501845e5f920191825250919050565b6080516104536104625f395f601001526104535ff3fe608060405261000c61000e565b005b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316330361007a575f356001600160e01b03191663278f794360e11b14610070576040516334ad5dbb60e21b815260040160405180910390fd5b610078610082565b565b6100786100b0565b5f806100913660048184610303565b81019061009e919061033e565b915091506100ac82826100c0565b5050565b6100786100bb61011a565b610151565b6100c98261016f565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a28051156101125761010d82826101ea565b505050565b6100ac61025c565b5f61014c7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b365f80375f80365f845af43d5f803e80801561016b573d5ff35b3d5ffd5b806001600160a01b03163b5f036101a957604051634c9c8ce360e01b81526001600160a01b03821660048201526024015b60405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b60605f80846001600160a01b0316846040516102069190610407565b5f60405180830381855af49150503d805f811461023e576040519150601f19603f3d011682016040523d82523d5f602084013e610243565b606091505b509150915061025385838361027b565b95945050505050565b34156100785760405163b398979f60e01b815260040160405180910390fd5b6060826102905761028b826102da565b6102d3565b81511580156102a757506001600160a01b0384163b155b156102d057604051639996b31560e01b81526001600160a01b03851660048201526024016101a0565b50805b9392505050565b8051156102ea5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b5f8085851115610311575f80fd5b8386111561031d575f80fd5b5050820193919092039150565b634e487b7160e01b5f52604160045260245ffd5b5f806040838503121561034f575f80fd5b82356001600160a01b0381168114610365575f80fd5b9150602083013567ffffffffffffffff80821115610381575f80fd5b818501915085601f830112610394575f80fd5b8135818111156103a6576103a661032a565b604051601f8201601f19908116603f011681019083821181831017156103ce576103ce61032a565b816040528281528860208487010111156103e6575f80fd5b826020860160208301375f6020848301015280955050505050509250929050565b5f82518060208501845e5f92019182525091905056fea2646970667358221220e6e83e6b94bd1c904c450a0f7d266eefd5304d703d4586030e57945cfc84fa7d64736f6c63430008190033608060405234801561000f575f80fd5b506040516104e73803806104e783398101604081905261002e916100bb565b806001600160a01b03811661005c57604051631e4fbdf760e01b81525f600482015260240160405180910390fd5b6100658161006c565b50506100e8565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b5f602082840312156100cb575f80fd5b81516001600160a01b03811681146100e1575f80fd5b9392505050565b6103f2806100f55f395ff3fe608060405260043610610049575f3560e01c8063715018a61461004d5780638da5cb5b146100635780639623609d1461008e578063ad3cb1cc146100a1578063f2fde38b146100de575b5f80fd5b348015610058575f80fd5b506100616100fd565b005b34801561006e575f80fd5b505f546040516001600160a01b0390911681526020015b60405180910390f35b61006161009c366004610260565b610110565b3480156100ac575f80fd5b506100d1604051806040016040528060058152602001640352e302e360dc1b81525081565b604051610085919061035d565b3480156100e9575f80fd5b506100616100f8366004610376565b61017b565b6101056101bd565b61010e5f6101e9565b565b6101186101bd565b60405163278f794360e11b81526001600160a01b03841690634f1ef2869034906101489086908690600401610391565b5f604051808303818588803b15801561015f575f80fd5b505af1158015610171573d5f803e3d5ffd5b5050505050505050565b6101836101bd565b6001600160a01b0381166101b157604051631e4fbdf760e01b81525f60048201526024015b60405180910390fd5b6101ba816101e9565b50565b5f546001600160a01b0316331461010e5760405163118cdaa760e01b81523360048201526024016101a8565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b03811681146101ba575f80fd5b634e487b7160e01b5f52604160045260245ffd5b5f805f60608486031215610272575f80fd5b833561027d81610238565b9250602084013561028d81610238565b9150604084013567ffffffffffffffff808211156102a9575f80fd5b818601915086601f8301126102bc575f80fd5b8135818111156102ce576102ce61024c565b604051601f8201601f19908116603f011681019083821181831017156102f6576102f661024c565b8160405282815289602084870101111561030e575f80fd5b826020860160208301375f6020848301015280955050505050509250925092565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f61036f602083018461032f565b9392505050565b5f60208284031215610386575f80fd5b813561036f81610238565b6001600160a01b03831681526040602082018190525f906103b49083018461032f565b94935050505056fea2646970667358221220201f933fb8df9921a6b060f6eac1014eaca99e8d26d0affaeed42773b42d620f64736f6c63430008190033b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103610100604052348015610010575f80fd5b5060405161239838038061239883398101604081905261002f9161006c565b6001600160a01b0393841660805291831660a052821660c0521660e0526100bd565b80516001600160a01b0381168114610067575f80fd5b919050565b5f805f806080858703121561007f575f80fd5b61008885610051565b935061009660208601610051565b92506100a460408601610051565b91506100b260608601610051565b905092959194509250565b60805160a05160c05160e05161224d61014b5f395f81816101030152610b5101525f818161018e0152610b2f01525f818161023b01526109f601525f8181610275015281816102a20152818161032401528181610409015281816105ec0152818161071001528181610754015281816107f90152818161094401528181610aff0152610c1b015261224d5ff3fe608060405234801561000f575f80fd5b50600436106100e5575f3560e01c806386fa944211610088578063c28ef59111610063578063c28ef59114610223578063d8a06f7314610236578063ef36bbde1461025d578063fbfa77cf14610270575f80fd5b806386fa9442146101c35780638e6adb03146101eb5780639cdf7ad8146101fe575f80fd5b8063413b4bab116100c3578063413b4bab1461016357806347e7ef2414610176578063563a96e11461018957806371f96211146101b0575f80fd5b806301ee7642146100e95780633e47158c146100fe578063402d267d14610142575b5f80fd5b6100fc6100f7366004611071565b610297565b005b6101257f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b610155610150366004611157565b610386565b604051908152602001610139565b6100fc610171366004611172565b6105e1565b6100fc6101843660046111d6565b610705565b6101257f000000000000000000000000000000000000000000000000000000000000000081565b6101256101be366004611157565b610877565b6101256101d1366004611157565b5f602081905290815260409020546001600160a01b031681565b6100fc6101f9366004611200565b6108de565b61021361020c36600461123f565b5f92915050565b6040519015158152602001610139565b610125610231366004611157565b610938565b6101257f000000000000000000000000000000000000000000000000000000000000000081565b61015561026b366004611157565b610c04565b6101257f000000000000000000000000000000000000000000000000000000000000000081565b306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146102e85760405162461bcd60e51b81526004016102df90611276565b60405180910390fd5b5f818060200190518101906102fd91906112ba565b604051635d0b520560e01b81529091506001600160a01b03821690635d0b520590610352907f0000000000000000000000000000000000000000000000000000000000000000908990899089906004016112d5565b5f604051808303815f87803b158015610369575f80fd5b505af115801561037b573d5f803e3d5ffd5b505050505050505050565b5f80829050806001600160a01b03166348d3b7756040518163ffffffff1660e01b8152600401602060405180830381865afa1580156103c7573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103eb919061131f565b801561047c575060405163794b15b760e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015282169063794b15b790602401602060405180830381865afa158015610456573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061047a919061131f565b155b1561048957505f92915050565b806001600160a01b031663a1b122026040518163ffffffff1660e01b8152600401602060405180830381865afa1580156104c5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104e9919061131f565b6104f657505f1992915050565b5f816001600160a01b031663bd49c35f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610533573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610557919061133e565b90505f826001600160a01b031663ecf708586040518163ffffffff1660e01b8152600401602060405180830381865afa158015610596573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105ba919061133e565b9050818111156105d7576105ce8282611369565b95945050505050565b505f949350505050565b306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146106295760405162461bcd60e51b81526004016102df90611276565b60405163f3fef3a360e01b81526001600160a01b038581166004830152602482018490525f919087169063f3fef3a39060440160408051808303815f875af1158015610677573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061069b919061137c565b60405163c8c01a5560e01b81526001600160a01b03878116600483015260248201839052919350908716915063c8c01a55906044015f604051808303815f87803b1580156106e7575f80fd5b505af11580156106f9573d5f803e3d5ffd5b50505050505050505050565b306001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461074d5760405162461bcd60e51b81526004016102df90611276565b6107e282827f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107ae573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107d291906112ba565b6001600160a01b03169190610c8f565b6040516311f9fbc960e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018390528316906347e7ef249060440160408051808303815f875af115801561084d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610871919061137c565b50505050565b5f816001600160a01b031663d8dfeb456040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108b4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108d891906112ba565b92915050565b602081146108fe5760405162461bcd60e51b81526004016102df9061139e565b5f61090b82840184611157565b90506001600160a01b0381166109335760405162461bcd60e51b81526004016102df9061139e565b505050565b5f336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146109b15760405162461bcd60e51b815260206004820152601c60248201527f53796d62696f746963416461707465723a206f6e6c79207661756c740000000060448201526064016102df565b506001600160a01b038082165f908152602081905260409020541680156109d757919050565b6040516302910f8b60e31b81526001600160a01b0383811660048301527f000000000000000000000000000000000000000000000000000000000000000016906314887c5890602401602060405180830381865afa158015610a3b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a5f919061131f565b610abd5760405162461bcd60e51b815260206004820152602960248201527f53796d62696f746963416461707465723a20696e76616c69642073796d62696f6044820152681d1a58c81d985d5b1d60ba1b60648201526084016102df565b6040516bffffffffffffffffffffffff19606084901b16602082015260340160408051601f198184030181529082905280516020909101206001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116602484015284166044830152907f0000000000000000000000000000000000000000000000000000000000000000907f00000000000000000000000000000000000000000000000000000000000000009060640160408051601f198184030181529181526020820180516001600160e01b031663485cc95560e01b17905251610ba890610ff7565b610bb4939291906113e3565b8190604051809103905ff5905080158015610bd1573d5f803e3d5ffd5b506001600160a01b039283165f90815260208190526040902080546001600160a01b031916938216939093179092555090565b6040516359f769a960e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301525f91908316906359f769a990602401602060405180830381865afa158015610c6b573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108d8919061133e565b604051636eb1769f60e11b81523060048201526001600160a01b0383811660248301525f919085169063dd62ed3e90604401602060405180830381865afa158015610cdc573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d00919061133e565b90506108718484610d118585611432565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b179052610d628482610dc4565b61087157604080516001600160a01b03851660248201525f6044808301919091528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b179052610dba908590610e61565b6108718482610e61565b5f805f846001600160a01b031684604051610ddf9190611445565b5f604051808303815f865af19150503d805f8114610e18576040519150601f19603f3d011682016040523d82523d5f602084013e610e1d565b606091505b5091509150818015610e47575080511580610e47575080806020019051810190610e47919061131f565b80156105ce5750505050506001600160a01b03163b151590565b5f610e756001600160a01b03841683610ec2565b905080515f14158015610e99575080806020019051810190610e97919061131f565b155b1561093357604051635274afe760e01b81526001600160a01b03841660048201526024016102df565b6060610ecf83835f610ed6565b9392505050565b606081471015610efb5760405163cd78605960e01b81523060048201526024016102df565b5f80856001600160a01b03168486604051610f169190611445565b5f6040518083038185875af1925050503d805f8114610f50576040519150601f19603f3d011682016040523d82523d5f602084013e610f55565b606091505b5091509150610f65868383610f6f565b9695505050505050565b606082610f8457610f7f82610fcb565b610ecf565b8151158015610f9b57506001600160a01b0384163b155b15610fc457604051639996b31560e01b81526001600160a01b03851660048201526024016102df565b5080610ecf565b805115610fdb5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b50565b610dbc8061145c83390190565b6001600160a01b0381168114610ff4575f80fd5b5f8083601f840112611028575f80fd5b50813567ffffffffffffffff81111561103f575f80fd5b602083019150836020828501011115611056575f80fd5b9250929050565b634e487b7160e01b5f52604160045260245ffd5b5f805f8060608587031215611084575f80fd5b843561108f81611004565b9350602085013567ffffffffffffffff808211156110ab575f80fd5b6110b788838901611018565b909550935060408701359150808211156110cf575f80fd5b818701915087601f8301126110e2575f80fd5b8135818111156110f4576110f461105d565b604051601f8201601f19908116603f0116810190838211818310171561111c5761111c61105d565b816040528281528a6020848701011115611134575f80fd5b826020860160208301375f60208483010152809550505050505092959194509250565b5f60208284031215611167575f80fd5b8135610ecf81611004565b5f805f805f60a08688031215611186575f80fd5b853561119181611004565b945060208601356111a181611004565b935060408601356111b181611004565b92506060860135915060808601356111c881611004565b809150509295509295909350565b5f80604083850312156111e7575f80fd5b82356111f281611004565b946020939093013593505050565b5f8060208385031215611211575f80fd5b823567ffffffffffffffff811115611227575f80fd5b61123385828601611018565b90969095509350505050565b5f8060408385031215611250575f80fd5b823561125b81611004565b9150602083013561126b81611004565b809150509250929050565b60208082526024908201527f53796d62696f746963416461707465723a2064656c65676174652063616c6c206040820152636f6e6c7960e01b606082015260800190565b5f602082840312156112ca575f80fd5b8151610ecf81611004565b6001600160a01b0385811682528416602082015260606040820181905281018290525f828460808401375f608084840101526080601f19601f850116830101905095945050505050565b5f6020828403121561132f575f80fd5b81518015158114610ecf575f80fd5b5f6020828403121561134e575f80fd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b818103818111156108d8576108d8611355565b5f806040838503121561138d575f80fd5b505080516020909101519092909150565b60208082526025908201527f53796d62696f746963416461707465723a20696e76616c696420726577617264604082015264206461746160d81b606082015260800190565b5f60018060a01b0380861683528085166020840152506060604083015282518060608401528060208501608085015e5f608082850101526080601f19601f830116840101915050949350505050565b808201808211156108d8576108d8611355565b5f82518060208501845e5f92019182525091905056fe60a0604052604051610dbc380380610dbc8339810160408190526100229161036a565b828161002e828261008c565b50508160405161003d9061032e565b6001600160a01b039091168152602001604051809103905ff080158015610066573d5f803e3d5ffd5b506001600160a01b031660805261008461007f60805190565b6100ea565b50505061044b565b61009582610157565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a28051156100de576100d982826101d5565b505050565b6100e6610248565b5050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6101295f80516020610d9c833981519152546001600160a01b031690565b604080516001600160a01b03928316815291841660208301520160405180910390a161015481610269565b50565b806001600160a01b03163b5f0361019157604051634c9c8ce360e01b81526001600160a01b03821660048201526024015b60405180910390fd5b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5b80546001600160a01b0319166001600160a01b039290921691909117905550565b60605f80846001600160a01b0316846040516101f19190610435565b5f60405180830381855af49150503d805f8114610229576040519150601f19603f3d011682016040523d82523d5f602084013e61022e565b606091505b50909250905061023f8583836102a6565b95945050505050565b34156102675760405163b398979f60e01b815260040160405180910390fd5b565b6001600160a01b03811661029257604051633173bdd160e11b81525f6004820152602401610188565b805f80516020610d9c8339815191526101b4565b6060826102bb576102b682610305565b6102fe565b81511580156102d257506001600160a01b0384163b155b156102fb57604051639996b31560e01b81526001600160a01b0385166004820152602401610188565b50805b9392505050565b8051156103155780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b6104e7806108b583390190565b80516001600160a01b0381168114610351575f80fd5b919050565b634e487b7160e01b5f52604160045260245ffd5b5f805f6060848603121561037c575f80fd5b6103858461033b565b92506103936020850161033b565b60408501519092506001600160401b03808211156103af575f80fd5b818601915086601f8301126103c2575f80fd5b8151818111156103d4576103d4610356565b604051601f8201601f19908116603f011681019083821181831017156103fc576103fc610356565b81604052828152896020848701011115610414575f80fd5b8260208601602083015e5f6020848301015280955050505050509250925092565b5f82518060208501845e5f920191825250919050565b6080516104536104625f395f601001526104535ff3fe608060405261000c61000e565b005b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316330361007a575f356001600160e01b03191663278f794360e11b14610070576040516334ad5dbb60e21b815260040160405180910390fd5b610078610082565b565b6100786100b0565b5f806100913660048184610303565b81019061009e919061033e565b915091506100ac82826100c0565b5050565b6100786100bb61011a565b610151565b6100c98261016f565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a28051156101125761010d82826101ea565b505050565b6100ac61025c565b5f61014c7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b365f80375f80365f845af43d5f803e80801561016b573d5ff35b3d5ffd5b806001600160a01b03163b5f036101a957604051634c9c8ce360e01b81526001600160a01b03821660048201526024015b60405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b60605f80846001600160a01b0316846040516102069190610407565b5f60405180830381855af49150503d805f811461023e576040519150601f19603f3d011682016040523d82523d5f602084013e610243565b606091505b509150915061025385838361027b565b95945050505050565b34156100785760405163b398979f60e01b815260040160405180910390fd5b6060826102905761028b826102da565b6102d3565b81511580156102a757506001600160a01b0384163b155b156102d057604051639996b31560e01b81526001600160a01b03851660048201526024016101a0565b50805b9392505050565b8051156102ea5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b5f8085851115610311575f80fd5b8386111561031d575f80fd5b5050820193919092039150565b634e487b7160e01b5f52604160045260245ffd5b5f806040838503121561034f575f80fd5b82356001600160a01b0381168114610365575f80fd5b9150602083013567ffffffffffffffff80821115610381575f80fd5b818501915085601f830112610394575f80fd5b8135818111156103a6576103a661032a565b604051601f8201601f19908116603f011681019083821181831017156103ce576103ce61032a565b816040528281528860208487010111156103e6575f80fd5b826020860160208301375f6020848301015280955050505050509250929050565b5f82518060208501845e5f92019182525091905056fea2646970667358221220e6e83e6b94bd1c904c450a0f7d266eefd5304d703d4586030e57945cfc84fa7d64736f6c63430008190033608060405234801561000f575f80fd5b506040516104e73803806104e783398101604081905261002e916100bb565b806001600160a01b03811661005c57604051631e4fbdf760e01b81525f600482015260240160405180910390fd5b6100658161006c565b50506100e8565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b5f602082840312156100cb575f80fd5b81516001600160a01b03811681146100e1575f80fd5b9392505050565b6103f2806100f55f395ff3fe608060405260043610610049575f3560e01c8063715018a61461004d5780638da5cb5b146100635780639623609d1461008e578063ad3cb1cc146100a1578063f2fde38b146100de575b5f80fd5b348015610058575f80fd5b506100616100fd565b005b34801561006e575f80fd5b505f546040516001600160a01b0390911681526020015b60405180910390f35b61006161009c366004610260565b610110565b3480156100ac575f80fd5b506100d1604051806040016040528060058152602001640352e302e360dc1b81525081565b604051610085919061035d565b3480156100e9575f80fd5b506100616100f8366004610376565b61017b565b6101056101bd565b61010e5f6101e9565b565b6101186101bd565b60405163278f794360e11b81526001600160a01b03841690634f1ef2869034906101489086908690600401610391565b5f604051808303818588803b15801561015f575f80fd5b505af1158015610171573d5f803e3d5ffd5b5050505050505050565b6101836101bd565b6001600160a01b0381166101b157604051631e4fbdf760e01b81525f60048201526024015b60405180910390fd5b6101ba816101e9565b50565b5f546001600160a01b0316331461010e5760405163118cdaa760e01b81523360048201526024016101a8565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b03811681146101ba575f80fd5b634e487b7160e01b5f52604160045260245ffd5b5f805f60608486031215610272575f80fd5b833561027d81610238565b9250602084013561028d81610238565b9150604084013567ffffffffffffffff808211156102a9575f80fd5b818601915086601f8301126102bc575f80fd5b8135818111156102ce576102ce61024c565b604051601f8201601f19908116603f011681019083821181831017156102f6576102f661024c565b8160405282815289602084870101111561030e575f80fd5b826020860160208301375f6020848301015280955050505050509250925092565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f61036f602083018461032f565b9392505050565b5f60208284031215610386575f80fd5b813561036f81610238565b6001600160a01b03831681526040602082018190525f906103b49083018461032f565b94935050505056fea2646970667358221220201f933fb8df9921a6b060f6eac1014eaca99e8d26d0affaeed42773b42d620f64736f6c63430008190033b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103a26469706673582212206e9e76c911f1ae16b5758eb33a466666f70a881317a30d3f2698910ad1c2892664736f6c63430008190033a26469706673582212206f736f99c1e27fa2dfcfdc95eb94ef6b40f7c7e52651f735aeca76f5b071725664736f6c63430008190033000000000000000000000000aeb6bdd95c502390db8f52c8909f703e9af6a3460000000000000000000000007daa2dce460c21ecb049f6da0f6ecc13ae8210fd000000000000000000000000e17544790a5fb91d2f30b46c02a00b1b5f7bb670000000000000000000000000b0531f4bc6d5aa3052b17df225be2c9e79c5a18a
Deployed Bytecode
0x608060405234801561000f575f80fd5b506004361061007a575f3560e01c8063374040171161005857806337404017146101105780634238b3af146101305780635dbe8f8b14610152578063a8c62e7614610173575f80fd5b806308e85a781461007e578063187a4ad9146100c257806323ee74fb146100e9575b5f80fd5b6100a57f000000000000000000000000b0531f4bc6d5aa3052b17df225be2c9e79c5a18a81565b6040516001600160a01b0390911681526020015b60405180910390f35b6100a57f000000000000000000000000e17544790a5fb91d2f30b46c02a00b1b5f7bb67081565b6100a57f000000000000000000000000aeb6bdd95c502390db8f52c8909f703e9af6a34681565b61012361011e3660046116dd565b61019a565b6040516100b9919061187f565b61014361013e3660046118c1565b6103c4565b6040516100b9939291906118ff565b6101656101603660046118c1565b6115f7565b6040519081526020016100b9565b6100a57f0000000000000000000000007daa2dce460c21ecb049f6da0f6ecc13ae8210fd81565b6101a2611626565b5f828152602081815260409182902082516060808201855282546001600160a01b039081168352600184015481168386015285516101e081018752600285018054831682526003860154831696820196909652600485015482168188015260058501548216928101929092526006840154811660808301526007840154811660a083015260088401541660c0820152600983015460e0820152600a83015460ff808216151561010084810191909152909104161515610120820152600b83018054929593949386019391926101408401919061027d90611933565b80601f01602080910402602001604051908101604052809291908181526020018280546102a990611933565b80156102f45780601f106102cb576101008083540402835291602001916102f4565b820191905f5260205f20905b8154815290600101906020018083116102d757829003601f168201915b50505050508152602001600a8201805461030d90611933565b80601f016020809104026020016040519081016040528092919081815260200182805461033990611933565b80156103845780601f1061035b57610100808354040283529160200191610384565b820191905f5260205f20905b81548152906001019060200180831161036757829003601f168201915b5050509183525050600b8201546001600160401b038082166020840152600160401b909104166040820152600c9091015460609091015290525092915050565b5f806103ce611649565b5f6103d8856115f7565b9050807f000000000000000000000000e17544790a5fb91d2f30b46c02a00b1b5f7bb67061040c6040880160208901611986565b604080515f8152602081019182905290610425906116c3565b610431939291906119b3565b8190604051809103905ff590508015801561044e573d5f803e3d5ffd5b5093505f81857f000000000000000000000000aeb6bdd95c502390db8f52c8909f703e9af6a3467f000000000000000000000000b0531f4bc6d5aa3052b17df225be2c9e79c5a18a6104a660408b0160208c01611986565b6040516104b2906116d0565b6001600160a01b0394851681529284166020840152908316604083015290911660608201526080018190604051809103905ff59050801580156104f7573d5f803e3d5ffd5b509050818161050c6040890160208a01611986565b604080515f8152602081019182905290610525906116c3565b610531939291906119b3565b8190604051809103905ff590508015801561054e573d5f803e3d5ffd5b50604080516101e08101825230815260e089013560208201529195505f919081016105816101208a016101008b016119ed565b1515815260200161059a6101408a016101208b016119ed565b151581526020015f6105b260a08b0160808c01611986565b6001600160a01b0316141581526020016105d260c08a0160a08b01611986565b6001600160a01b031681526020016105ee6101408a018a611a06565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152505050908252506020016106356101608a018a611a06565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152505050908252506001600160a01b037f0000000000000000000000007daa2dce460c21ecb049f6da0f6ecc13ae8210fd16602082018190526040820181905260608201526080016106bb60e08a0160c08b01611986565b6001600160a01b03908116825287811660208301525f60408084018290526060909301529051639bfe9e2360e01b8152919250871690639bfe9e2390610705908490600401611a4f565b5f604051808303815f87803b15801561071c575f80fd5b505af115801561072e573d5f803e3d5ffd5b505f925061074591505060a0890160808a01611986565b6001600160a01b0316146108a857604051632f2ff15d60e01b81527f1867ae69910bc7238ccbbb445aa11a0dbdd472b851b7fac0c991101aca0a360d60048201819052306024830152906001600160a01b03881690632f2ff15d906044015f604051808303815f87803b1580156107ba575f80fd5b505af11580156107cc573d5f803e3d5ffd5b5050506001600160a01b038816905063a28614666107f060a08b0160808c01611986565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152600160248201526044015f604051808303815f87803b158015610835575f80fd5b505af1158015610847573d5f803e3d5ffd5b5050604051631b2b455f60e11b8152600481018490523060248201526001600160a01b038a1692506336568abe91506044015f604051808303815f87803b158015610890575f80fd5b505af11580156108a2573d5f803e3d5ffd5b50505050505b856001600160a01b0316632f2ff15d876001600160a01b031663a217fddf6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108f3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109179190611bb9565b61092460208b018b611986565b6040516001600160e01b031960e085901b16815260048101929092526001600160a01b031660248201526044015f604051808303815f87803b158015610968575f80fd5b505af115801561097a573d5f803e3d5ffd5b50505050856001600160a01b0316632f2ff15d876001600160a01b031663c2e9dcd66040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109c9573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109ed9190611bb9565b6109fa60208b018b611986565b6040516001600160e01b031960e085901b16815260048101929092526001600160a01b031660248201526044015f604051808303815f87803b158015610a3e575f80fd5b505af1158015610a50573d5f803e3d5ffd5b50505050856001600160a01b0316632f2ff15d876001600160a01b0316635680e1456040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a9f573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ac39190611bb9565b610ad360608b0160408c01611986565b6040516001600160e01b031960e085901b16815260048101929092526001600160a01b031660248201526044015f604051808303815f87803b158015610b17575f80fd5b505af1158015610b29573d5f803e3d5ffd5b50505050856001600160a01b0316632f2ff15d876001600160a01b0316633a2bbe496040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b78573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b9c9190611bb9565b610bac60608b0160408c01611986565b6040516001600160e01b031960e085901b16815260048101929092526001600160a01b031660248201526044015f604051808303815f87803b158015610bf0575f80fd5b505af1158015610c02573d5f803e3d5ffd5b5050506001600160a01b0387169050632f2ff15d7f6e5811d60b7d57973a97208b6158fed3b8e064ca747403e6a8c81f56a8f9e75f610c4760608b0160408c01611986565b6040516001600160e01b031960e085901b16815260048101929092526001600160a01b031660248201526044015f604051808303815f87803b158015610c8b575f80fd5b505af1158015610c9d573d5f803e3d5ffd5b50505050856001600160a01b0316632f2ff15d7f0000000000000000000000007daa2dce460c21ecb049f6da0f6ecc13ae8210fd6001600160a01b031663cf8dda3b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d0c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d309190611bb9565b610d4060608b0160408c01611986565b6040516001600160e01b031960e085901b16815260048101929092526001600160a01b031660248201526044015f604051808303815f87803b158015610d84575f80fd5b505af1158015610d96573d5f803e3d5ffd5b505f9250610dad9150506080890160608a01611986565b6001600160a01b0316146113c157856001600160a01b0316632f2ff15d7f0000000000000000000000007daa2dce460c21ecb049f6da0f6ecc13ae8210fd6001600160a01b031663cf8dda3b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e26573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e4a9190611bb9565b6040516001600160e01b031960e084901b16815260048101919091523060248201526044015f604051808303815f87803b158015610e86575f80fd5b505af1158015610e98573d5f803e3d5ffd5b50505050856001600160a01b0316632f2ff15d876001600160a01b0316633a2bbe496040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ee7573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f0b9190611bb9565b6040516001600160e01b031960e084901b16815260048101919091523060248201526044015f604051808303815f87803b158015610f47575f80fd5b505af1158015610f59573d5f803e3d5ffd5b5050506001600160a01b0387169050634b6a58fe610f7d60808a0160608b01611986565b5f6040518363ffffffff1660e01b8152600401610f9b929190611bd0565b5f604051808303815f87803b158015610fb2575f80fd5b505af1158015610fc4573d5f803e3d5ffd5b505f925060019150610fd39050565b604051908082528060200260200182016040528015610ffc578160200160208202803683370190505b50905061100f6080890160608a01611986565b815f8151811061102157611021611c09565b6001600160a01b0392909216602092830291909101909101526040805160018082528183019092525f91816020015b604080518082019091525f808252602082015281526020019060019003908161105057505060408051808201909152909150806110956101a08c016101808d01611c33565b6001600160401b031681526020016110b56101c08c016101a08d01611c33565b6001600160401b0316815250815f815181106110d3576110d3611c09565b6020908102919091010152604051637166956d60e01b81526001600160a01b037f0000000000000000000000007daa2dce460c21ecb049f6da0f6ecc13ae8210fd1690637166956d9061112e908b9086908690600401611c4c565b5f604051808303815f87803b158015611145575f80fd5b505af1158015611157573d5f803e3d5ffd5b50505050876001600160a01b03166336568abe7f0000000000000000000000007daa2dce460c21ecb049f6da0f6ecc13ae8210fd6001600160a01b031663cf8dda3b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111c6573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111ea9190611bb9565b6040516001600160e01b031960e084901b16815260048101919091523060248201526044015f604051808303815f87803b158015611226575f80fd5b505af1158015611238573d5f803e3d5ffd5b50505050876001600160a01b03166336568abe896001600160a01b0316633a2bbe496040518163ffffffff1660e01b8152600401602060405180830381865afa158015611287573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112ab9190611bb9565b6040516001600160e01b031960e084901b16815260048101919091523060248201526044015f604051808303815f87803b1580156112e7575f80fd5b505af11580156112f9573d5f803e3d5ffd5b50505050876001600160a01b03166336568abe896001600160a01b031663a217fddf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611348573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061136c9190611bb9565b6040516001600160e01b031960e084901b16815260048101919091523060248201526044015f604051808303815f87803b1580156113a8575f80fd5b505af11580156113ba573d5f803e3d5ffd5b5050505050505b82856001600160a01b0316876001600160a01b03167f941c9195b6fb499b0f8e1b227134859845dadb7b8e5f025a9e682118ea8bb34a8a6040516114059190611d65565b60405180910390a46040518060600160405280876001600160a01b03168152602001866001600160a01b031681526020018861144090611fdc565b90525f8481526020818152604091829020835181546001600160a01b03199081166001600160a01b039283161783558584015160018401805483169184169190911790558585015180516002850180548416918516919091178155948101516003850180548416918516919091179055948501516004840180548316918416919091179055606085015160058401805483169184169190911790556080850151600684018054831691841691909117905560a0850151600784018054831691841691909117905560c0850151600884018054909216921691909117905560e0830151600982015561010080840151600a8301805461012087015161ffff1990911692151561ff0019169290921791151590920217905561014083015190929190600b84019061156f908261216b565b50610160820151600a820190611585908261216b565b50610180820151600b820180546101a08501516001600160401b03908116600160401b026fffffffffffffffffffffffffffffffff199092169316929092179190911790556101c090910151600c909101555086905085886115e681611fdc565b929a91995091975095505050505050565b5f816040516020016116099190611d65565b604051602081830303815290604052805190602001209050919050565b604080516060810182525f8082526020820152908101611644611649565b905290565b604080516101e0810182525f8082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e0820183905261010082018390526101208201839052610140820181905261016082015261018081018290526101a081018290526101c081019190915290565b610dbc8061222b83390190565b61239880612fe783390190565b5f602082840312156116ed575f80fd5b5035919050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b80516001600160a01b031682525f6101e0602083015161174d60208601826001600160a01b03169052565b50604083015161176860408601826001600160a01b03169052565b50606083015161178360608601826001600160a01b03169052565b50608083015161179e60808601826001600160a01b03169052565b5060a08301516117b960a08601826001600160a01b03169052565b5060c08301516117d460c08601826001600160a01b03169052565b5060e083015160e0850152610100808401516117f38287018215159052565b5050610120838101511515908501526101408084015181860183905261181b838701826116f4565b92505050610160808401518583038287015261183783826116f4565b9250505061018080840151611856828701826001600160401b03169052565b50506101a0838101516001600160401b0316908501526101c09283015192909301919091525090565b602081525f60018060a01b038084511660208401528060208501511660408401525060408301516060808401526118b96080840182611722565b949350505050565b5f602082840312156118d1575f80fd5b81356001600160401b038111156118e6575f80fd5b82016101e081850312156118f8575f80fd5b9392505050565b6001600160a01b038481168252831660208201526060604082018190525f9061192a90830184611722565b95945050505050565b600181811c9082168061194757607f821691505b60208210810361196557634e487b7160e01b5f52602260045260245ffd5b50919050565b80356001600160a01b0381168114611981575f80fd5b919050565b5f60208284031215611996575f80fd5b6118f88261196b565b634e487b7160e01b5f52604160045260245ffd5b6001600160a01b038481168252831660208201526060604082018190525f9061192a908301846116f4565b80358015158114611981575f80fd5b5f602082840312156119fd575f80fd5b6118f8826119de565b5f808335601e19843603018112611a1b575f80fd5b8301803591506001600160401b03821115611a34575f80fd5b602001915036819003821315611a48575f80fd5b9250929050565b60208152611a696020820183516001600160a01b03169052565b602082015160408201525f6040830151611a87606084018215159052565b506060830151801515608084015250608083015180151560a08401525060a08301516001600160a01b03811660c08401525060c08301516101e08060e0850152611ad56102008501836116f4565b915060e0850151610100601f198685030181870152611af484836116f4565b935080870151915050610120611b14818701836001600160a01b03169052565b8601519050610140611b30868201836001600160a01b03169052565b8601519050610160611b4c868201836001600160a01b03169052565b8601519050610180611b68868201836001600160a01b03169052565b86015190506101a0611b84868201836001600160a01b03169052565b86015190506101c0611ba0868201836001600160a01b03169052565b909501516001600160a01b031693019290925250919050565b5f60208284031215611bc9575f80fd5b5051919050565b6001600160a01b03831681526040810160038310611bfc57634e487b7160e01b5f52602160045260245ffd5b8260208301529392505050565b634e487b7160e01b5f52603260045260245ffd5b80356001600160401b0381168114611981575f80fd5b5f60208284031215611c43575f80fd5b6118f882611c1d565b6001600160a01b0384811682526060602080840182905285519184018290525f92868201929091906080860190855b81811015611c99578551851683529483019491830191600101611c7b565b50506040935085810360408701528092508651808252828201935082880191505f5b81811015611ced57825180516001600160401b0390811687529085015116848601529385019391830191600101611cbb565b50929998505050505050505050565b5f808335601e19843603018112611d11575f80fd5b83016020810192503590506001600160401b03811115611d2f575f80fd5b803603821315611a48575f80fd5b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b60208152611d8660208201611d798461196b565b6001600160a01b03169052565b5f611d936020840161196b565b6001600160a01b038116604084015250611daf6040840161196b565b6001600160a01b038116606084015250611dcb6060840161196b565b6001600160a01b038116608084015250611de76080840161196b565b6001600160a01b03811660a084015250611e0360a0840161196b565b6001600160a01b03811660c084015250611e1f60c0840161196b565b6001600160a01b03811660e08401525061010060e084013581840152611e468185016119de565b9050610120611e588185018315159052565b611e638186016119de565b915050610140611e768185018315159052565b611e8281860186611cfc565b925090506101e06101608181870152611ea061020087018585611d3d565b9350611eae81880188611cfc565b93509050610180601f198786030181880152611ecb858584611d3d565b9450611ed8818901611c1d565b935050506101a0611ef3818701846001600160401b03169052565b611efe818801611c1d565b9250506101c0611f18818701846001600160401b03169052565b9590950135939094019290925250919050565b6040516101e081016001600160401b0381118282101715611f4e57611f4e61199f565b60405290565b5f82601f830112611f63575f80fd5b81356001600160401b0380821115611f7d57611f7d61199f565b604051601f8301601f19908116603f01168101908282118183101715611fa557611fa561199f565b81604052838152866020858801011115611fbd575f80fd5b836020870160208301375f602085830101528094505050505092915050565b5f6101e08236031215611fed575f80fd5b611ff5611f2b565b611ffe8361196b565b815261200c6020840161196b565b602082015261201d6040840161196b565b604082015261202e6060840161196b565b606082015261203f6080840161196b565b608082015261205060a0840161196b565b60a082015261206160c0840161196b565b60c082015260e083013560e082015261010061207e8185016119de565b908201526101206120908482016119de565b90820152610140838101356001600160401b03808211156120af575f80fd5b6120bb36838801611f54565b838501526101609250828601359150808211156120d6575f80fd5b506120e336828701611f54565b8284015250506101806120f7818501611c1d565b908201526101a0612109848201611c1d565b908201526101c092830135928101929092525090565b601f82111561216657805f5260205f20601f840160051c810160208510156121445750805b601f840160051c820191505b81811015612163575f8155600101612150565b50505b505050565b81516001600160401b038111156121845761218461199f565b612198816121928454611933565b8461211f565b602080601f8311600181146121cb575f84156121b45750858301515b5f19600386901b1c1916600185901b178555612222565b5f85815260208120601f198616915b828110156121f9578886015182559484019460019091019084016121da565b508582101561221657878501515f19600388901b60f8161c191681555b505060018460011b0185555b50505050505056fe60a0604052604051610dbc380380610dbc8339810160408190526100229161036a565b828161002e828261008c565b50508160405161003d9061032e565b6001600160a01b039091168152602001604051809103905ff080158015610066573d5f803e3d5ffd5b506001600160a01b031660805261008461007f60805190565b6100ea565b50505061044b565b61009582610157565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a28051156100de576100d982826101d5565b505050565b6100e6610248565b5050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6101295f80516020610d9c833981519152546001600160a01b031690565b604080516001600160a01b03928316815291841660208301520160405180910390a161015481610269565b50565b806001600160a01b03163b5f0361019157604051634c9c8ce360e01b81526001600160a01b03821660048201526024015b60405180910390fd5b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5b80546001600160a01b0319166001600160a01b039290921691909117905550565b60605f80846001600160a01b0316846040516101f19190610435565b5f60405180830381855af49150503d805f8114610229576040519150601f19603f3d011682016040523d82523d5f602084013e61022e565b606091505b50909250905061023f8583836102a6565b95945050505050565b34156102675760405163b398979f60e01b815260040160405180910390fd5b565b6001600160a01b03811661029257604051633173bdd160e11b81525f6004820152602401610188565b805f80516020610d9c8339815191526101b4565b6060826102bb576102b682610305565b6102fe565b81511580156102d257506001600160a01b0384163b155b156102fb57604051639996b31560e01b81526001600160a01b0385166004820152602401610188565b50805b9392505050565b8051156103155780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b6104e7806108b583390190565b80516001600160a01b0381168114610351575f80fd5b919050565b634e487b7160e01b5f52604160045260245ffd5b5f805f6060848603121561037c575f80fd5b6103858461033b565b92506103936020850161033b565b60408501519092506001600160401b03808211156103af575f80fd5b818601915086601f8301126103c2575f80fd5b8151818111156103d4576103d4610356565b604051601f8201601f19908116603f011681019083821181831017156103fc576103fc610356565b81604052828152896020848701011115610414575f80fd5b8260208601602083015e5f6020848301015280955050505050509250925092565b5f82518060208501845e5f920191825250919050565b6080516104536104625f395f601001526104535ff3fe608060405261000c61000e565b005b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316330361007a575f356001600160e01b03191663278f794360e11b14610070576040516334ad5dbb60e21b815260040160405180910390fd5b610078610082565b565b6100786100b0565b5f806100913660048184610303565b81019061009e919061033e565b915091506100ac82826100c0565b5050565b6100786100bb61011a565b610151565b6100c98261016f565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a28051156101125761010d82826101ea565b505050565b6100ac61025c565b5f61014c7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b365f80375f80365f845af43d5f803e80801561016b573d5ff35b3d5ffd5b806001600160a01b03163b5f036101a957604051634c9c8ce360e01b81526001600160a01b03821660048201526024015b60405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b60605f80846001600160a01b0316846040516102069190610407565b5f60405180830381855af49150503d805f811461023e576040519150601f19603f3d011682016040523d82523d5f602084013e610243565b606091505b509150915061025385838361027b565b95945050505050565b34156100785760405163b398979f60e01b815260040160405180910390fd5b6060826102905761028b826102da565b6102d3565b81511580156102a757506001600160a01b0384163b155b156102d057604051639996b31560e01b81526001600160a01b03851660048201526024016101a0565b50805b9392505050565b8051156102ea5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b5f8085851115610311575f80fd5b8386111561031d575f80fd5b5050820193919092039150565b634e487b7160e01b5f52604160045260245ffd5b5f806040838503121561034f575f80fd5b82356001600160a01b0381168114610365575f80fd5b9150602083013567ffffffffffffffff80821115610381575f80fd5b818501915085601f830112610394575f80fd5b8135818111156103a6576103a661032a565b604051601f8201601f19908116603f011681019083821181831017156103ce576103ce61032a565b816040528281528860208487010111156103e6575f80fd5b826020860160208301375f6020848301015280955050505050509250929050565b5f82518060208501845e5f92019182525091905056fea2646970667358221220e6e83e6b94bd1c904c450a0f7d266eefd5304d703d4586030e57945cfc84fa7d64736f6c63430008190033608060405234801561000f575f80fd5b506040516104e73803806104e783398101604081905261002e916100bb565b806001600160a01b03811661005c57604051631e4fbdf760e01b81525f600482015260240160405180910390fd5b6100658161006c565b50506100e8565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b5f602082840312156100cb575f80fd5b81516001600160a01b03811681146100e1575f80fd5b9392505050565b6103f2806100f55f395ff3fe608060405260043610610049575f3560e01c8063715018a61461004d5780638da5cb5b146100635780639623609d1461008e578063ad3cb1cc146100a1578063f2fde38b146100de575b5f80fd5b348015610058575f80fd5b506100616100fd565b005b34801561006e575f80fd5b505f546040516001600160a01b0390911681526020015b60405180910390f35b61006161009c366004610260565b610110565b3480156100ac575f80fd5b506100d1604051806040016040528060058152602001640352e302e360dc1b81525081565b604051610085919061035d565b3480156100e9575f80fd5b506100616100f8366004610376565b61017b565b6101056101bd565b61010e5f6101e9565b565b6101186101bd565b60405163278f794360e11b81526001600160a01b03841690634f1ef2869034906101489086908690600401610391565b5f604051808303818588803b15801561015f575f80fd5b505af1158015610171573d5f803e3d5ffd5b5050505050505050565b6101836101bd565b6001600160a01b0381166101b157604051631e4fbdf760e01b81525f60048201526024015b60405180910390fd5b6101ba816101e9565b50565b5f546001600160a01b0316331461010e5760405163118cdaa760e01b81523360048201526024016101a8565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b03811681146101ba575f80fd5b634e487b7160e01b5f52604160045260245ffd5b5f805f60608486031215610272575f80fd5b833561027d81610238565b9250602084013561028d81610238565b9150604084013567ffffffffffffffff808211156102a9575f80fd5b818601915086601f8301126102bc575f80fd5b8135818111156102ce576102ce61024c565b604051601f8201601f19908116603f011681019083821181831017156102f6576102f661024c565b8160405282815289602084870101111561030e575f80fd5b826020860160208301375f6020848301015280955050505050509250925092565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f61036f602083018461032f565b9392505050565b5f60208284031215610386575f80fd5b813561036f81610238565b6001600160a01b03831681526040602082018190525f906103b49083018461032f565b94935050505056fea2646970667358221220201f933fb8df9921a6b060f6eac1014eaca99e8d26d0affaeed42773b42d620f64736f6c63430008190033b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103610100604052348015610010575f80fd5b5060405161239838038061239883398101604081905261002f9161006c565b6001600160a01b0393841660805291831660a052821660c0521660e0526100bd565b80516001600160a01b0381168114610067575f80fd5b919050565b5f805f806080858703121561007f575f80fd5b61008885610051565b935061009660208601610051565b92506100a460408601610051565b91506100b260608601610051565b905092959194509250565b60805160a05160c05160e05161224d61014b5f395f81816101030152610b5101525f818161018e0152610b2f01525f818161023b01526109f601525f8181610275015281816102a20152818161032401528181610409015281816105ec0152818161071001528181610754015281816107f90152818161094401528181610aff0152610c1b015261224d5ff3fe608060405234801561000f575f80fd5b50600436106100e5575f3560e01c806386fa944211610088578063c28ef59111610063578063c28ef59114610223578063d8a06f7314610236578063ef36bbde1461025d578063fbfa77cf14610270575f80fd5b806386fa9442146101c35780638e6adb03146101eb5780639cdf7ad8146101fe575f80fd5b8063413b4bab116100c3578063413b4bab1461016357806347e7ef2414610176578063563a96e11461018957806371f96211146101b0575f80fd5b806301ee7642146100e95780633e47158c146100fe578063402d267d14610142575b5f80fd5b6100fc6100f7366004611071565b610297565b005b6101257f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b610155610150366004611157565b610386565b604051908152602001610139565b6100fc610171366004611172565b6105e1565b6100fc6101843660046111d6565b610705565b6101257f000000000000000000000000000000000000000000000000000000000000000081565b6101256101be366004611157565b610877565b6101256101d1366004611157565b5f602081905290815260409020546001600160a01b031681565b6100fc6101f9366004611200565b6108de565b61021361020c36600461123f565b5f92915050565b6040519015158152602001610139565b610125610231366004611157565b610938565b6101257f000000000000000000000000000000000000000000000000000000000000000081565b61015561026b366004611157565b610c04565b6101257f000000000000000000000000000000000000000000000000000000000000000081565b306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146102e85760405162461bcd60e51b81526004016102df90611276565b60405180910390fd5b5f818060200190518101906102fd91906112ba565b604051635d0b520560e01b81529091506001600160a01b03821690635d0b520590610352907f0000000000000000000000000000000000000000000000000000000000000000908990899089906004016112d5565b5f604051808303815f87803b158015610369575f80fd5b505af115801561037b573d5f803e3d5ffd5b505050505050505050565b5f80829050806001600160a01b03166348d3b7756040518163ffffffff1660e01b8152600401602060405180830381865afa1580156103c7573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103eb919061131f565b801561047c575060405163794b15b760e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015282169063794b15b790602401602060405180830381865afa158015610456573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061047a919061131f565b155b1561048957505f92915050565b806001600160a01b031663a1b122026040518163ffffffff1660e01b8152600401602060405180830381865afa1580156104c5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104e9919061131f565b6104f657505f1992915050565b5f816001600160a01b031663bd49c35f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610533573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610557919061133e565b90505f826001600160a01b031663ecf708586040518163ffffffff1660e01b8152600401602060405180830381865afa158015610596573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105ba919061133e565b9050818111156105d7576105ce8282611369565b95945050505050565b505f949350505050565b306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146106295760405162461bcd60e51b81526004016102df90611276565b60405163f3fef3a360e01b81526001600160a01b038581166004830152602482018490525f919087169063f3fef3a39060440160408051808303815f875af1158015610677573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061069b919061137c565b60405163c8c01a5560e01b81526001600160a01b03878116600483015260248201839052919350908716915063c8c01a55906044015f604051808303815f87803b1580156106e7575f80fd5b505af11580156106f9573d5f803e3d5ffd5b50505050505050505050565b306001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461074d5760405162461bcd60e51b81526004016102df90611276565b6107e282827f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107ae573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107d291906112ba565b6001600160a01b03169190610c8f565b6040516311f9fbc960e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018390528316906347e7ef249060440160408051808303815f875af115801561084d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610871919061137c565b50505050565b5f816001600160a01b031663d8dfeb456040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108b4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108d891906112ba565b92915050565b602081146108fe5760405162461bcd60e51b81526004016102df9061139e565b5f61090b82840184611157565b90506001600160a01b0381166109335760405162461bcd60e51b81526004016102df9061139e565b505050565b5f336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146109b15760405162461bcd60e51b815260206004820152601c60248201527f53796d62696f746963416461707465723a206f6e6c79207661756c740000000060448201526064016102df565b506001600160a01b038082165f908152602081905260409020541680156109d757919050565b6040516302910f8b60e31b81526001600160a01b0383811660048301527f000000000000000000000000000000000000000000000000000000000000000016906314887c5890602401602060405180830381865afa158015610a3b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a5f919061131f565b610abd5760405162461bcd60e51b815260206004820152602960248201527f53796d62696f746963416461707465723a20696e76616c69642073796d62696f6044820152681d1a58c81d985d5b1d60ba1b60648201526084016102df565b6040516bffffffffffffffffffffffff19606084901b16602082015260340160408051601f198184030181529082905280516020909101206001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116602484015284166044830152907f0000000000000000000000000000000000000000000000000000000000000000907f00000000000000000000000000000000000000000000000000000000000000009060640160408051601f198184030181529181526020820180516001600160e01b031663485cc95560e01b17905251610ba890610ff7565b610bb4939291906113e3565b8190604051809103905ff5905080158015610bd1573d5f803e3d5ffd5b506001600160a01b039283165f90815260208190526040902080546001600160a01b031916938216939093179092555090565b6040516359f769a960e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301525f91908316906359f769a990602401602060405180830381865afa158015610c6b573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108d8919061133e565b604051636eb1769f60e11b81523060048201526001600160a01b0383811660248301525f919085169063dd62ed3e90604401602060405180830381865afa158015610cdc573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d00919061133e565b90506108718484610d118585611432565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b179052610d628482610dc4565b61087157604080516001600160a01b03851660248201525f6044808301919091528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b179052610dba908590610e61565b6108718482610e61565b5f805f846001600160a01b031684604051610ddf9190611445565b5f604051808303815f865af19150503d805f8114610e18576040519150601f19603f3d011682016040523d82523d5f602084013e610e1d565b606091505b5091509150818015610e47575080511580610e47575080806020019051810190610e47919061131f565b80156105ce5750505050506001600160a01b03163b151590565b5f610e756001600160a01b03841683610ec2565b905080515f14158015610e99575080806020019051810190610e97919061131f565b155b1561093357604051635274afe760e01b81526001600160a01b03841660048201526024016102df565b6060610ecf83835f610ed6565b9392505050565b606081471015610efb5760405163cd78605960e01b81523060048201526024016102df565b5f80856001600160a01b03168486604051610f169190611445565b5f6040518083038185875af1925050503d805f8114610f50576040519150601f19603f3d011682016040523d82523d5f602084013e610f55565b606091505b5091509150610f65868383610f6f565b9695505050505050565b606082610f8457610f7f82610fcb565b610ecf565b8151158015610f9b57506001600160a01b0384163b155b15610fc457604051639996b31560e01b81526001600160a01b03851660048201526024016102df565b5080610ecf565b805115610fdb5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b50565b610dbc8061145c83390190565b6001600160a01b0381168114610ff4575f80fd5b5f8083601f840112611028575f80fd5b50813567ffffffffffffffff81111561103f575f80fd5b602083019150836020828501011115611056575f80fd5b9250929050565b634e487b7160e01b5f52604160045260245ffd5b5f805f8060608587031215611084575f80fd5b843561108f81611004565b9350602085013567ffffffffffffffff808211156110ab575f80fd5b6110b788838901611018565b909550935060408701359150808211156110cf575f80fd5b818701915087601f8301126110e2575f80fd5b8135818111156110f4576110f461105d565b604051601f8201601f19908116603f0116810190838211818310171561111c5761111c61105d565b816040528281528a6020848701011115611134575f80fd5b826020860160208301375f60208483010152809550505050505092959194509250565b5f60208284031215611167575f80fd5b8135610ecf81611004565b5f805f805f60a08688031215611186575f80fd5b853561119181611004565b945060208601356111a181611004565b935060408601356111b181611004565b92506060860135915060808601356111c881611004565b809150509295509295909350565b5f80604083850312156111e7575f80fd5b82356111f281611004565b946020939093013593505050565b5f8060208385031215611211575f80fd5b823567ffffffffffffffff811115611227575f80fd5b61123385828601611018565b90969095509350505050565b5f8060408385031215611250575f80fd5b823561125b81611004565b9150602083013561126b81611004565b809150509250929050565b60208082526024908201527f53796d62696f746963416461707465723a2064656c65676174652063616c6c206040820152636f6e6c7960e01b606082015260800190565b5f602082840312156112ca575f80fd5b8151610ecf81611004565b6001600160a01b0385811682528416602082015260606040820181905281018290525f828460808401375f608084840101526080601f19601f850116830101905095945050505050565b5f6020828403121561132f575f80fd5b81518015158114610ecf575f80fd5b5f6020828403121561134e575f80fd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b818103818111156108d8576108d8611355565b5f806040838503121561138d575f80fd5b505080516020909101519092909150565b60208082526025908201527f53796d62696f746963416461707465723a20696e76616c696420726577617264604082015264206461746160d81b606082015260800190565b5f60018060a01b0380861683528085166020840152506060604083015282518060608401528060208501608085015e5f608082850101526080601f19601f830116840101915050949350505050565b808201808211156108d8576108d8611355565b5f82518060208501845e5f92019182525091905056fe60a0604052604051610dbc380380610dbc8339810160408190526100229161036a565b828161002e828261008c565b50508160405161003d9061032e565b6001600160a01b039091168152602001604051809103905ff080158015610066573d5f803e3d5ffd5b506001600160a01b031660805261008461007f60805190565b6100ea565b50505061044b565b61009582610157565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a28051156100de576100d982826101d5565b505050565b6100e6610248565b5050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6101295f80516020610d9c833981519152546001600160a01b031690565b604080516001600160a01b03928316815291841660208301520160405180910390a161015481610269565b50565b806001600160a01b03163b5f0361019157604051634c9c8ce360e01b81526001600160a01b03821660048201526024015b60405180910390fd5b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5b80546001600160a01b0319166001600160a01b039290921691909117905550565b60605f80846001600160a01b0316846040516101f19190610435565b5f60405180830381855af49150503d805f8114610229576040519150601f19603f3d011682016040523d82523d5f602084013e61022e565b606091505b50909250905061023f8583836102a6565b95945050505050565b34156102675760405163b398979f60e01b815260040160405180910390fd5b565b6001600160a01b03811661029257604051633173bdd160e11b81525f6004820152602401610188565b805f80516020610d9c8339815191526101b4565b6060826102bb576102b682610305565b6102fe565b81511580156102d257506001600160a01b0384163b155b156102fb57604051639996b31560e01b81526001600160a01b0385166004820152602401610188565b50805b9392505050565b8051156103155780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b6104e7806108b583390190565b80516001600160a01b0381168114610351575f80fd5b919050565b634e487b7160e01b5f52604160045260245ffd5b5f805f6060848603121561037c575f80fd5b6103858461033b565b92506103936020850161033b565b60408501519092506001600160401b03808211156103af575f80fd5b818601915086601f8301126103c2575f80fd5b8151818111156103d4576103d4610356565b604051601f8201601f19908116603f011681019083821181831017156103fc576103fc610356565b81604052828152896020848701011115610414575f80fd5b8260208601602083015e5f6020848301015280955050505050509250925092565b5f82518060208501845e5f920191825250919050565b6080516104536104625f395f601001526104535ff3fe608060405261000c61000e565b005b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316330361007a575f356001600160e01b03191663278f794360e11b14610070576040516334ad5dbb60e21b815260040160405180910390fd5b610078610082565b565b6100786100b0565b5f806100913660048184610303565b81019061009e919061033e565b915091506100ac82826100c0565b5050565b6100786100bb61011a565b610151565b6100c98261016f565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a28051156101125761010d82826101ea565b505050565b6100ac61025c565b5f61014c7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b365f80375f80365f845af43d5f803e80801561016b573d5ff35b3d5ffd5b806001600160a01b03163b5f036101a957604051634c9c8ce360e01b81526001600160a01b03821660048201526024015b60405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b60605f80846001600160a01b0316846040516102069190610407565b5f60405180830381855af49150503d805f811461023e576040519150601f19603f3d011682016040523d82523d5f602084013e610243565b606091505b509150915061025385838361027b565b95945050505050565b34156100785760405163b398979f60e01b815260040160405180910390fd5b6060826102905761028b826102da565b6102d3565b81511580156102a757506001600160a01b0384163b155b156102d057604051639996b31560e01b81526001600160a01b03851660048201526024016101a0565b50805b9392505050565b8051156102ea5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b5f8085851115610311575f80fd5b8386111561031d575f80fd5b5050820193919092039150565b634e487b7160e01b5f52604160045260245ffd5b5f806040838503121561034f575f80fd5b82356001600160a01b0381168114610365575f80fd5b9150602083013567ffffffffffffffff80821115610381575f80fd5b818501915085601f830112610394575f80fd5b8135818111156103a6576103a661032a565b604051601f8201601f19908116603f011681019083821181831017156103ce576103ce61032a565b816040528281528860208487010111156103e6575f80fd5b826020860160208301375f6020848301015280955050505050509250929050565b5f82518060208501845e5f92019182525091905056fea2646970667358221220e6e83e6b94bd1c904c450a0f7d266eefd5304d703d4586030e57945cfc84fa7d64736f6c63430008190033608060405234801561000f575f80fd5b506040516104e73803806104e783398101604081905261002e916100bb565b806001600160a01b03811661005c57604051631e4fbdf760e01b81525f600482015260240160405180910390fd5b6100658161006c565b50506100e8565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b5f602082840312156100cb575f80fd5b81516001600160a01b03811681146100e1575f80fd5b9392505050565b6103f2806100f55f395ff3fe608060405260043610610049575f3560e01c8063715018a61461004d5780638da5cb5b146100635780639623609d1461008e578063ad3cb1cc146100a1578063f2fde38b146100de575b5f80fd5b348015610058575f80fd5b506100616100fd565b005b34801561006e575f80fd5b505f546040516001600160a01b0390911681526020015b60405180910390f35b61006161009c366004610260565b610110565b3480156100ac575f80fd5b506100d1604051806040016040528060058152602001640352e302e360dc1b81525081565b604051610085919061035d565b3480156100e9575f80fd5b506100616100f8366004610376565b61017b565b6101056101bd565b61010e5f6101e9565b565b6101186101bd565b60405163278f794360e11b81526001600160a01b03841690634f1ef2869034906101489086908690600401610391565b5f604051808303818588803b15801561015f575f80fd5b505af1158015610171573d5f803e3d5ffd5b5050505050505050565b6101836101bd565b6001600160a01b0381166101b157604051631e4fbdf760e01b81525f60048201526024015b60405180910390fd5b6101ba816101e9565b50565b5f546001600160a01b0316331461010e5760405163118cdaa760e01b81523360048201526024016101a8565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b03811681146101ba575f80fd5b634e487b7160e01b5f52604160045260245ffd5b5f805f60608486031215610272575f80fd5b833561027d81610238565b9250602084013561028d81610238565b9150604084013567ffffffffffffffff808211156102a9575f80fd5b818601915086601f8301126102bc575f80fd5b8135818111156102ce576102ce61024c565b604051601f8201601f19908116603f011681019083821181831017156102f6576102f661024c565b8160405282815289602084870101111561030e575f80fd5b826020860160208301375f6020848301015280955050505050509250925092565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f61036f602083018461032f565b9392505050565b5f60208284031215610386575f80fd5b813561036f81610238565b6001600160a01b03831681526040602082018190525f906103b49083018461032f565b94935050505056fea2646970667358221220201f933fb8df9921a6b060f6eac1014eaca99e8d26d0affaeed42773b42d620f64736f6c63430008190033b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103a26469706673582212206e9e76c911f1ae16b5758eb33a466666f70a881317a30d3f2698910ad1c2892664736f6c63430008190033a26469706673582212206f736f99c1e27fa2dfcfdc95eb94ef6b40f7c7e52651f735aeca76f5b071725664736f6c63430008190033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000aeb6bdd95c502390db8f52c8909f703e9af6a3460000000000000000000000007daa2dce460c21ecb049f6da0f6ecc13ae8210fd000000000000000000000000e17544790a5fb91d2f30b46c02a00b1b5f7bb670000000000000000000000000b0531f4bc6d5aa3052b17df225be2c9e79c5a18a
-----Decoded View---------------
Arg [0] : symbioticVaultFactory_ (address): 0xAEb6bdd95c502390db8f52c8909F703E9Af6a346
Arg [1] : strategy_ (address): 0x7dAA2Dce460C21eCB049f6DA0f6EcC13ae8210fd
Arg [2] : multiVaultImplementation_ (address): 0xE17544790a5FB91D2f30b46C02A00b1b5F7Bb670
Arg [3] : symbioticWithdrawalQueueImplementation_ (address): 0xb0531F4bC6d5aa3052B17DF225be2c9E79C5a18a
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 000000000000000000000000aeb6bdd95c502390db8f52c8909f703e9af6a346
Arg [1] : 0000000000000000000000007daa2dce460c21ecb049f6da0f6ecc13ae8210fd
Arg [2] : 000000000000000000000000e17544790a5fb91d2f30b46c02a00b1b5f7bb670
Arg [3] : 000000000000000000000000b0531f4bc6d5aa3052b17df225be2c9e79c5a18a
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 31 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.