diff --git a/contracts/contracts/interfaces/IDripper.sol b/contracts/contracts/interfaces/IDripper.sol new file mode 100644 index 0000000000..ff1b52cae7 --- /dev/null +++ b/contracts/contracts/interfaces/IDripper.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface IDripper { + /// @notice How much funds have dripped out already and are currently + // available to be sent to the vault. + /// @return The amount that would be sent if a collect was called + function availableFunds() external view returns (uint256); + + /// @notice Collect all dripped funds and send to vault. + /// Recalculate new drip rate. + function collect() external; + + /// @notice Collect all dripped funds, send to vault, recalculate new drip + /// rate, and rebase mToken. + function collectAndRebase() external; + + /// @notice Change the drip duration. Governor only. + /// @param _durationSeconds the number of seconds to drip out the entire + /// balance over if no collects were called during that time. + function setDripDuration(uint256 _durationSeconds) external; + + /// @dev Transfer out ERC20 tokens held by the contract. Governor only. + /// @param _asset ERC20 token address + /// @param _amount amount to transfer + function transferToken(address _asset, uint256 _amount) external; +} diff --git a/contracts/contracts/interfaces/IVault.sol b/contracts/contracts/interfaces/IVault.sol index de354f2a48..da7aca411b 100644 --- a/contracts/contracts/interfaces/IVault.sol +++ b/contracts/contracts/interfaces/IVault.sol @@ -34,6 +34,19 @@ interface IVault { uint256 _fromAssetAmount, uint256 _toAssetAmount ); + event DripperChanged(address indexed _dripper); + event WithdrawalRequested( + address indexed _withdrawer, + uint256 indexed _requestId, + uint256 _amount, + uint256 _queued + ); + event WithdrawalClaimed( + address indexed _withdrawer, + uint256 indexed _requestId, + uint256 _amount + ); + event WithdrawalClaimable(uint256 _claimable, uint256 _newClaimable); // Governable.sol function transferGovernance(address _newGovernor) external; @@ -199,6 +212,8 @@ interface IVault { function netOusdMintedForStrategy() external view returns (int256); + function setDripper(address _dripper) external; + function weth() external view returns (address); function cacheWETHAssetIndex() external; @@ -210,4 +225,29 @@ interface IVault { function setAdminImpl(address) external; function removeAsset(address _asset) external; + + // These are OETH specific functions + function addWithdrawalQueueLiquidity() external; + + function requestWithdrawal(uint256 _amount) + external + returns (uint256 requestId, uint256 queued); + + function claimWithdrawal(uint256 requestId) + external + returns (uint256 amount); + + function claimWithdrawals(uint256[] memory requestIds) + external + returns (uint256[] memory amounts, uint256 totalAmount); + + function withdrawalQueueMetadata() + external + view + returns (VaultStorage.WithdrawalQueueMetadata memory); + + function withdrawalRequests(uint256 requestId) + external + view + returns (VaultStorage.WithdrawalRequest memory); } diff --git a/contracts/contracts/mocks/MockStrategy.sol b/contracts/contracts/mocks/MockStrategy.sol index 6e068944d0..fe74686a0e 100644 --- a/contracts/contracts/mocks/MockStrategy.sol +++ b/contracts/contracts/mocks/MockStrategy.sol @@ -6,6 +6,9 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; contract MockStrategy { address[] public assets; + address public withdrawAllAsset; + address public withdrawAllRecipient; + constructor() {} function deposit(address asset, uint256 amount) external {} @@ -21,7 +24,10 @@ contract MockStrategy { } function withdrawAll() external { - require(false, "Not implemented"); + IERC20(withdrawAllAsset).transfer( + withdrawAllRecipient, + IERC20(withdrawAllAsset).balanceOf(address(this)) + ); } function checkBalance(address asset) @@ -45,4 +51,9 @@ contract MockStrategy { { return new address[](0); } + + function setWithdrawAll(address asset, address recipient) external { + withdrawAllAsset = asset; + withdrawAllRecipient = recipient; + } } diff --git a/contracts/contracts/vault/OETHVaultAdmin.sol b/contracts/contracts/vault/OETHVaultAdmin.sol index aa16a98d79..9365400003 100644 --- a/contracts/contracts/vault/OETHVaultAdmin.sol +++ b/contracts/contracts/vault/OETHVaultAdmin.sol @@ -1,6 +1,11 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; +import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +import { IStrategy } from "../interfaces/IStrategy.sol"; +import { IVault } from "../interfaces/IVault.sol"; import { VaultAdmin } from "./VaultAdmin.sol"; /** @@ -8,5 +13,101 @@ import { VaultAdmin } from "./VaultAdmin.sol"; * @author Origin Protocol Inc */ contract OETHVaultAdmin is VaultAdmin { + using SafeERC20 for IERC20; + + address public immutable weth; + + constructor(address _weth) { + weth = _weth; + } + + /// @dev Simplified version of the deposit function as WETH is the only supported asset. + function _depositToStrategy( + address _strategyToAddress, + address[] calldata _assets, + uint256[] calldata _amounts + ) internal override { + require( + strategies[_strategyToAddress].isSupported, + "Invalid to Strategy" + ); + require( + _assets.length == 1 && _amounts.length == 1 && _assets[0] == weth, + "Only WETH is supported" + ); + + // Check the there is enough WETH to transfer once the WETH reserved for the withdrawal queue is accounted for + require(_amounts[0] <= _wethAvailable(), "Not enough WETH available"); + + // Send required amount of funds to the strategy + IERC20(weth).safeTransfer(_strategyToAddress, _amounts[0]); + + // Deposit all the funds that have been sent to the strategy + IStrategy(_strategyToAddress).depositAll(); + } + + function _withdrawFromStrategy( + address _recipient, + address _strategyFromAddress, + address[] calldata _assets, + uint256[] calldata _amounts + ) internal override { + super._withdrawFromStrategy( + _recipient, + _strategyFromAddress, + _assets, + _amounts + ); + + IVault(address(this)).addWithdrawalQueueLiquidity(); + } + + function _withdrawAllFromStrategy(address _strategyAddr) internal override { + super._withdrawAllFromStrategy(_strategyAddr); + + IVault(address(this)).addWithdrawalQueueLiquidity(); + } + + function _withdrawAllFromStrategies() internal override { + super._withdrawAllFromStrategies(); + + IVault(address(this)).addWithdrawalQueueLiquidity(); + } + + /// @dev Calculates the amount of WETH in the Vault that is not reserved for the withdrawal queue. + function _wethAvailable() internal view returns (uint256 wethAvailable) { + WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata; + + // The amount of WETH that is still to be claimed in the withdrawal queue + uint256 outstandingWithdrawals = queue.queued - queue.claimed; + + // The amount of sitting in WETH in the vault + uint256 wethBalance = IERC20(weth).balanceOf(address(this)); + + // If there is more WETH in the vault than the outstanding withdrawals + if (wethBalance > outstandingWithdrawals) { + wethAvailable = wethBalance - outstandingWithdrawals; + } + } + + function _swapCollateral( + address _fromAsset, + address _toAsset, + uint256 _fromAssetAmount, + uint256 _minToAssetAmount, + bytes calldata _data + ) internal override returns (uint256 toAssetAmount) { + require(_fromAsset != weth, "Swap from WETH not supported"); + require(_toAsset == weth, "Only swap to WETH"); + toAssetAmount = super._swapCollateral( + _fromAsset, + _toAsset, + _fromAssetAmount, + _minToAssetAmount, + _data + ); + // Add any new WETH to the withdrawal queue first + IVault(address(this)).addWithdrawalQueueLiquidity(); + } } diff --git a/contracts/contracts/vault/OETHVaultCore.sol b/contracts/contracts/vault/OETHVaultCore.sol index 01cb3e1c9e..fe38a39e5e 100644 --- a/contracts/contracts/vault/OETHVaultCore.sol +++ b/contracts/contracts/vault/OETHVaultCore.sol @@ -1,12 +1,14 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import { StableMath } from "../utils/StableMath.sol"; -import { VaultCore } from "./VaultCore.sol"; - import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol"; + +import { StableMath } from "../utils/StableMath.sol"; +import { VaultCore } from "./VaultCore.sol"; import { IStrategy } from "../interfaces/IStrategy.sol"; +import { IDripper } from "../interfaces/IDripper.sol"; /** * @title OETH VaultCore Contract @@ -16,6 +18,7 @@ contract OETHVaultCore is VaultCore { using SafeERC20 for IERC20; using StableMath for uint256; + uint256 public constant CLAIM_DELAY = 10 minutes; address public immutable weth; uint256 public wethAssetIndex; @@ -43,6 +46,7 @@ contract OETHVaultCore is VaultCore { } // @inheritdoc VaultCore + // slither-disable-start reentrancy-no-eth function _mint( address _asset, uint256 _amount, @@ -59,6 +63,9 @@ contract OETHVaultCore is VaultCore { // Rebase must happen before any transfers occur. if (!rebasePaused && _amount >= rebaseThreshold) { + // Stream any harvested rewards (WETH) that are available to the Vault + IDripper(dripper).collect(); + _rebase(); } @@ -68,12 +75,17 @@ contract OETHVaultCore is VaultCore { // Transfer the deposited coins to the vault IERC20(_asset).safeTransferFrom(msg.sender, address(this), _amount); + // Give priority to the withdrawal queue for the new WETH liquidity + _addWithdrawalQueueLiquidity(); + // Auto-allocate if necessary if (_amount >= autoAllocateThreshold) { _allocate(); } } + // slither-disable-end reentrancy-no-eth + // @inheritdoc VaultCore function _calculateRedeemOutputs(uint256 _amount) internal @@ -128,24 +140,346 @@ contract OETHVaultCore is VaultCore { "Redeem amount lower than minimum" ); - if (IERC20(weth).balanceOf(address(this)) >= amountMinusFee) { - // Use Vault funds first if sufficient - IERC20(weth).safeTransfer(msg.sender, amountMinusFee); - } else { - address strategyAddr = assetDefaultStrategies[weth]; - if (strategyAddr != address(0)) { - // Nothing in Vault, but something in Strategy, send from there - IStrategy strategy = IStrategy(strategyAddr); - strategy.withdraw(msg.sender, weth, amountMinusFee); - } else { - // Cant find funds anywhere - revert("Liquidity error"); - } - } + // Is there enough WETH in the Vault available after accounting for the withdrawal queue + require(_wethAvailable() >= amountMinusFee, "Liquidity error"); + + // Transfer WETH minus the fee to the redeemer + IERC20(weth).safeTransfer(msg.sender, amountMinusFee); // Burn OETH from user (including fees) oUSD.burn(msg.sender, _amount); + // Prevent insolvency _postRedeem(_amount); } + + /** + * @notice Request an asynchronous withdrawal of WETH in exchange for OETH. + * The OETH is burned on request and the WETH is transferred to the withdrawer on claim. + * This request can be claimed once the withdrawal queue's `claimable` amount + * is greater than or equal this request's `queued` amount. + * There is no minimum time or block number before a request can be claimed. It just needs + * enough WETH liquidity in the Vault to satisfy all the outstanding requests to that point in the queue. + * OETH is converted to WETH at 1:1. + * @param _amount Amount of OETH to burn. + * @param requestId Unique ID for the withdrawal request + * @param queued Cumulative total of all WETH queued including already claimed requests. + */ + function requestWithdrawal(uint256 _amount) + external + whenNotCapitalPaused + nonReentrant + returns (uint256 requestId, uint256 queued) + { + // The check that the requester has enough OETH is done in to later burn call + + requestId = withdrawalQueueMetadata.nextWithdrawalIndex; + queued = withdrawalQueueMetadata.queued + _amount; + + // Store the next withdrawal request + withdrawalQueueMetadata.nextWithdrawalIndex = SafeCast.toUint128( + requestId + 1 + ); + // Store the updated queued amount which reserves WETH in the withdrawal queue + // and reduces the vault's total assets + withdrawalQueueMetadata.queued = SafeCast.toUint128(queued); + // Store the user's withdrawal request + withdrawalRequests[requestId] = WithdrawalRequest({ + withdrawer: msg.sender, + claimed: false, + timestamp: uint40(block.timestamp), + amount: SafeCast.toUint128(_amount), + queued: SafeCast.toUint128(queued) + }); + + // Burn the user's OETH + oUSD.burn(msg.sender, _amount); + + // Prevent withdrawal if the vault is solvent by more than the the allowed percentage + _postRedeem(_amount); + + emit WithdrawalRequested(msg.sender, requestId, _amount, queued); + } + + // slither-disable-start reentrancy-no-eth + /** + * @notice Claim a previously requested withdrawal once it is claimable. + * This request can be claimed once the withdrawal queue's `claimable` amount + * is greater than or equal this request's `queued` amount and 10 minutes has passed. + * If the requests is not claimable, the transaction will revert with `Queue pending liquidity`. + * If the request is not older than 10 minutes, the transaction will revert with `Claim delay not met`. + * OETH is converted to WETH at 1:1. + * @param _requestId Unique ID for the withdrawal request + * @return amount Amount of WETH transferred to the withdrawer + */ + function claimWithdrawal(uint256 _requestId) + external + whenNotCapitalPaused + nonReentrant + returns (uint256 amount) + { + // Try and get more liquidity if there is not enough available + if ( + withdrawalRequests[_requestId].queued > + withdrawalQueueMetadata.claimable + ) { + // Stream any harvested rewards (WETH) that are available to the Vault + IDripper(dripper).collect(); + + // Add any WETH from the Dripper to the withdrawal queue + _addWithdrawalQueueLiquidity(); + } + + amount = _claimWithdrawal(_requestId); + + // transfer WETH from the vault to the withdrawer + IERC20(weth).safeTransfer(msg.sender, amount); + + // Prevent insolvency + _postRedeem(amount); + } + + // slither-disable-end reentrancy-no-eth + + /** + * @notice Claim a previously requested withdrawals once they are claimable. + * This requests can be claimed once the withdrawal queue's `claimable` amount + * is greater than or equal each request's `queued` amount and 10 minutes has passed. + * If one of the requests is not claimable, the whole transaction will revert with `Queue pending liquidity`. + * If one of the requests is not older than 10 minutes, + * the whole transaction will revert with `Claim delay not met`. + * @param _requestIds Unique ID of each withdrawal request + * @return amounts Amount of WETH received for each request + * @return totalAmount Total amount of WETH transferred to the withdrawer + */ + function claimWithdrawals(uint256[] memory _requestIds) + external + whenNotCapitalPaused + nonReentrant + returns (uint256[] memory amounts, uint256 totalAmount) + { + // Just call the Dripper instead of looping through _requestIds to find the highest id + // and checking it's queued amount is > the queue's claimable amount. + + // Stream any harvested rewards (WETH) that are available to the Vault + IDripper(dripper).collect(); + + // Add any WETH from the Dripper to the withdrawal queue + _addWithdrawalQueueLiquidity(); + + amounts = new uint256[](_requestIds.length); + for (uint256 i = 0; i < _requestIds.length; ++i) { + amounts[i] = _claimWithdrawal(_requestIds[i]); + totalAmount += amounts[i]; + } + + // transfer all the claimed WETH from the vault to the withdrawer + IERC20(weth).safeTransfer(msg.sender, totalAmount); + + // Prevent insolvency + _postRedeem(totalAmount); + } + + function _claimWithdrawal(uint256 requestId) + internal + returns (uint256 amount) + { + // Load the structs from storage into memory + WithdrawalRequest memory request = withdrawalRequests[requestId]; + WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata; + + require( + request.timestamp + CLAIM_DELAY <= block.timestamp, + "Claim delay not met" + ); + // If there isn't enough reserved liquidity in the queue to claim + require(request.queued <= queue.claimable, "Queue pending liquidity"); + require(request.withdrawer == msg.sender, "Not requester"); + require(request.claimed == false, "Already claimed"); + + // Store the request as claimed + withdrawalRequests[requestId].claimed = true; + // Store the updated claimed amount + withdrawalQueueMetadata.claimed = queue.claimed + request.amount; + + emit WithdrawalClaimed(msg.sender, requestId, request.amount); + + return request.amount; + } + + /// @notice Collects harvested rewards from the Dripper as WETH then + /// adds WETH to the withdrawal queue if there is a funding shortfall. + /// @dev is called from the Native Staking strategy when validator withdrawals are processed. + /// It also called before any WETH is allocated to a strategy. + function addWithdrawalQueueLiquidity() external { + // Stream any harvested rewards (WETH) that are available to the Vault + IDripper(dripper).collect(); + + _addWithdrawalQueueLiquidity(); + } + + /// @dev Adds WETH to the withdrawal queue if there is a funding shortfall. + /// This assumes 1 WETH equal 1 OETH. + function _addWithdrawalQueueLiquidity() + internal + returns (uint256 addedClaimable) + { + WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata; + + // Check if the claimable WETH is less than the queued amount + uint256 queueShortfall = queue.queued - queue.claimable; + + // No need to do anything is the withdrawal queue is full funded + if (queueShortfall == 0) { + return 0; + } + + uint256 wethBalance = IERC20(weth).balanceOf(address(this)); + + // Of the claimable withdrawal requests, how much is unclaimed? + // That is, the amount of WETH that is currently allocated for the withdrawal queue + uint256 allocatedWeth = queue.claimable - queue.claimed; + + // If there is no unallocated WETH then there is nothing to add to the queue + if (wethBalance <= allocatedWeth) { + return 0; + } + + uint256 unallocatedWeth = wethBalance - allocatedWeth; + + // the new claimable amount is the smaller of the queue shortfall or unallocated weth + addedClaimable = queueShortfall < unallocatedWeth + ? queueShortfall + : unallocatedWeth; + uint256 newClaimable = queue.claimable + addedClaimable; + + // Store the new claimable amount back to storage + withdrawalQueueMetadata.claimable = SafeCast.toUint128(newClaimable); + + // emit a WithdrawalClaimable event + emit WithdrawalClaimable(newClaimable, addedClaimable); + } + + /*************************************** + View Functions + ****************************************/ + + /// @dev Calculate how much WETH in the vault is not reserved for the withdrawal queue. + // That is, it is available to be redeemed or deposited into a strategy. + function _wethAvailable() internal view returns (uint256 wethAvailable) { + WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata; + + // The amount of WETH that is still to be claimed in the withdrawal queue + uint256 outstandingWithdrawals = queue.queued - queue.claimed; + + // The amount of sitting in WETH in the vault + uint256 wethBalance = IERC20(weth).balanceOf(address(this)); + + // If there is not enough WETH in the vault to cover the outstanding withdrawals + if (wethBalance <= outstandingWithdrawals) { + return 0; + } + + return wethBalance - outstandingWithdrawals; + } + + /// @dev Get the balance of an asset held in Vault and all strategies + /// less any WETH that is reserved for the withdrawal queue. + /// This will only return a non-zero balance for WETH. + /// All other assets will return 0 even if there is some dust amounts left in the Vault. + /// For example, there is 1 wei left of stETH in the OETH Vault but will return 0 in this function. + /// + /// If there is not enough WETH in the vault and all strategies to cover all outstanding + /// withdrawal requests then return a WETH balance of 0 + function _checkBalance(address _asset) + internal + view + override + returns (uint256 balance) + { + if (_asset != weth) { + return 0; + } + + // Get the WETH balance in the vault and all strategies less any WETH reserved for the withdrawal queue + return _totalValue(); + } + + /** + * @notice Allocate unallocated funds on Vault to strategies. + **/ + function allocate() external override whenNotCapitalPaused nonReentrant { + // Add any unallocated WETH to the withdrawal queue first + _addWithdrawalQueueLiquidity(); + + _allocate(); + } + + /// @dev Allocate WETH to the default WETH strategy if there is excess to the Vault buffer. + /// This is called from either `mint` or `allocate` and assumes `_addWithdrawalQueueLiquidity` + /// has been called before this function. + function _allocate() internal override { + // No need to do anything if no default strategy for WETH + address depositStrategyAddr = assetDefaultStrategies[weth]; + if (depositStrategyAddr == address(0)) return; + + uint256 wethAvailableInVault = _wethAvailable(); + // No need to do anything if there isn't any WETH in the vault to allocate + if (wethAvailableInVault == 0) return; + + // Calculate the target buffer for the vault using the total supply + uint256 totalSupply = oUSD.totalSupply(); + uint256 targetBuffer = totalSupply.mulTruncate(vaultBuffer); + + // If available WETH in the Vault is below or equal the target buffer then there's nothing to allocate + if (wethAvailableInVault <= targetBuffer) return; + + // The amount of assets to allocate to the default strategy + uint256 allocateAmount = wethAvailableInVault - targetBuffer; + + IStrategy strategy = IStrategy(depositStrategyAddr); + // Transfer WETH to the strategy and call the strategy's deposit function + IERC20(weth).safeTransfer(address(strategy), allocateAmount); + strategy.deposit(weth, allocateAmount); + + emit AssetAllocated(weth, depositStrategyAddr, allocateAmount); + } + + /// @dev The total value of all assets held by the vault and all its strategies + /// less any WETH that is reserved for the withdrawal queue. + /// For OETH, this is just WETH in the vault and strategies. + /// + // If there is not enough WETH in the vault and all strategies to cover all outstanding + // withdrawal requests then return a total value of 0. + function _totalValue() internal view override returns (uint256 value) { + value = _totalValueInVault() + _totalValueInStrategies(); + + // Need to remove WETH that is reserved for the withdrawal queue. + WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata; + // reserved for the withdrawal queue = cumulative queued total - total claimed + uint256 reservedForQueue = queue.queued - queue.claimed; + + if (value < reservedForQueue) { + // This can happen if the vault becomes insolvent enough that the + // total value in the vault and all strategies is less than the outstanding withdrawals. + // For example, there was a mass slashing event and most users request a withdrawal. + return 0; + } + + // Adjust the total value by the amount reserved for the withdrawal queue + return value - reservedForQueue; + } + + /// @dev Only WETH is supported in the OETH Vault so return the WETH balance only + /// Any ETH balances in the Vault will be ignored. + /// Amounts from previously supported vault assets will also be ignored. + /// For example, there is 1 wei left of stETH in the OETH Vault but is will be ignored. + function _totalValueInVault() + internal + view + override + returns (uint256 value) + { + value = IERC20(weth).balanceOf(address(this)); + } } diff --git a/contracts/contracts/vault/VaultAdmin.sol b/contracts/contracts/vault/VaultAdmin.sol index 88065e4b04..0bc783a766 100644 --- a/contracts/contracts/vault/VaultAdmin.sol +++ b/contracts/contracts/vault/VaultAdmin.sol @@ -154,6 +154,15 @@ contract VaultAdmin is VaultStorage { emit NetOusdMintForStrategyThresholdChanged(_threshold); } + /** + * @notice Set the Dripper contract that streams harvested rewards to the vault. + * @param _dripper Address of the Dripper contract. + */ + function setDripper(address _dripper) external onlyGovernor { + dripper = _dripper; + emit DripperChanged(_dripper); + } + /*************************************** Swaps ****************************************/ @@ -179,6 +188,22 @@ contract VaultAdmin is VaultStorage { onlyGovernorOrStrategist returns (uint256 toAssetAmount) { + toAssetAmount = _swapCollateral( + _fromAsset, + _toAsset, + _fromAssetAmount, + _minToAssetAmount, + _data + ); + } + + function _swapCollateral( + address _fromAsset, + address _toAsset, + uint256 _fromAssetAmount, + uint256 _minToAssetAmount, + bytes calldata _data + ) internal virtual returns (uint256 toAssetAmount) { // Check fromAsset and toAsset are valid Asset memory fromAssetConfig = assets[address(_fromAsset)]; Asset memory toAssetConfig = assets[_toAsset]; @@ -470,7 +495,7 @@ contract VaultAdmin is VaultStorage { address _strategyToAddress, address[] calldata _assets, uint256[] calldata _amounts - ) internal { + ) internal virtual { require( strategies[_strategyToAddress].isSupported, "Invalid to Strategy" @@ -519,7 +544,7 @@ contract VaultAdmin is VaultStorage { address _strategyFromAddress, address[] calldata _assets, uint256[] calldata _amounts - ) internal { + ) internal virtual { require( strategies[_strategyFromAddress].isSupported, "Invalid from Strategy" @@ -643,6 +668,10 @@ contract VaultAdmin is VaultStorage { external onlyGovernorOrStrategist { + _withdrawAllFromStrategy(_strategyAddr); + } + + function _withdrawAllFromStrategy(address _strategyAddr) internal virtual { require( strategies[_strategyAddr].isSupported, "Strategy is not supported" @@ -655,6 +684,10 @@ contract VaultAdmin is VaultStorage { * @notice Withdraws all assets from all the strategies and sends assets to the Vault. */ function withdrawAllFromStrategies() external onlyGovernorOrStrategist { + _withdrawAllFromStrategies(); + } + + function _withdrawAllFromStrategies() internal virtual { uint256 stratCount = allStrategies.length; for (uint256 i = 0; i < stratCount; ++i) { IStrategy(allStrategies[i]).withdrawAll(); diff --git a/contracts/contracts/vault/VaultCore.sol b/contracts/contracts/vault/VaultCore.sol index 814dcda9e5..fa3568ab2e 100644 --- a/contracts/contracts/vault/VaultCore.sol +++ b/contracts/contracts/vault/VaultCore.sol @@ -16,6 +16,7 @@ import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.s import { StableMath } from "../utils/StableMath.sol"; import { IOracle } from "../interfaces/IOracle.sol"; import { IGetExchangeRateToken } from "../interfaces/IGetExchangeRateToken.sol"; +import { IDripper } from "../interfaces/IDripper.sol"; import "./VaultInitializer.sol"; @@ -89,6 +90,10 @@ contract VaultCore is VaultInitializer { // Rebase must happen before any transfers occur. if (priceAdjustedDeposit >= rebaseThreshold && !rebasePaused) { + if (dripper != address(0)) { + // Stream any harvested rewards that are available + IDripper(dripper).collect(); + } _rebase(); } @@ -220,6 +225,11 @@ contract VaultCore is VaultInitializer { // Check that the OTokens are backed by enough assets if (maxSupplyDiff > 0) { + // If there are more outstanding withdrawal requests than assets in the vault and strategies + // then the available assets will be negative and totalUnits will be rounded up to zero. + // As we don't know the exact shortfall amount, we will reject all redeem and withdrawals + require(totalUnits > 0, "Too many outstanding requests"); + // Allow a max difference of maxSupplyDiff% between // backing assets value and OUSD total supply uint256 diff = oUSD.totalSupply().divPrecisely(totalUnits); @@ -279,14 +289,14 @@ contract VaultCore is VaultInitializer { /** * @notice Allocate unallocated funds on Vault to strategies. **/ - function allocate() external whenNotCapitalPaused nonReentrant { + function allocate() external virtual whenNotCapitalPaused nonReentrant { _allocate(); } /** * @dev Allocate unallocated funds on Vault to strategies. **/ - function _allocate() internal { + function _allocate() internal virtual { uint256 vaultValue = _totalValueInVault(); // Nothing in vault to allocate if (vaultValue == 0) return; @@ -414,7 +424,12 @@ contract VaultCore is VaultInitializer { * @dev Internal to calculate total value of all assets held in Vault. * @return value Total value in USD/ETH (1e18) */ - function _totalValueInVault() internal view returns (uint256 value) { + function _totalValueInVault() + internal + view + virtual + returns (uint256 value) + { uint256 assetCount = allAssets.length; for (uint256 y = 0; y < assetCount; ++y) { address assetAddr = allAssets[y]; diff --git a/contracts/contracts/vault/VaultStorage.sol b/contracts/contracts/vault/VaultStorage.sol index ebadbcb0ac..e93ca9a548 100644 --- a/contracts/contracts/vault/VaultStorage.sol +++ b/contracts/contracts/vault/VaultStorage.sol @@ -53,6 +53,19 @@ contract VaultStorage is Initializable, Governable { uint256 _fromAssetAmount, uint256 _toAssetAmount ); + event DripperChanged(address indexed _dripper); + event WithdrawalRequested( + address indexed _withdrawer, + uint256 indexed _requestId, + uint256 _amount, + uint256 _queued + ); + event WithdrawalClaimed( + address indexed _withdrawer, + uint256 indexed _requestId, + uint256 _amount + ); + event WithdrawalClaimable(uint256 _claimable, uint256 _newClaimable); // Assets supported by the Vault, i.e. Stablecoins enum UnitConversion { @@ -83,7 +96,7 @@ contract VaultStorage is Initializable, Governable { bool isSupported; uint256 _deprecated; // Deprecated storage slot } - /// @dev mapping of strategy contracts to their configiration + /// @dev mapping of strategy contracts to their configuration mapping(address => Strategy) internal strategies; /// @dev list of all vault strategies address[] internal allStrategies; @@ -166,8 +179,50 @@ contract VaultStorage is Initializable, Governable { } SwapConfig internal swapConfig = SwapConfig(address(0), 0); + /// @notice Address of the Dripper contract that streams harvested rewards to the Vault + /// @dev The vault is proxied so needs to be set with setDripper against the proxy contract. + // slither-disable-start constable-states + // slither-disable-next-line uninitialized-state + address public dripper; + // slither-disable-end constable-states + + /// Withdrawal Queue Storage ///// + + struct WithdrawalQueueMetadata { + // cumulative total of all withdrawal requests included the ones that have already been claimed + uint128 queued; + // cumulative total of all the requests that can be claimed including the ones that have already been claimed + uint128 claimable; + // total of all the requests that have been claimed + uint128 claimed; + // index of the next withdrawal request starting at 0 + uint128 nextWithdrawalIndex; + } + + /// @notice Global metadata for the withdrawal queue including: + /// queued - cumulative total of all withdrawal requests included the ones that have already been claimed + /// claimable - cumulative total of all the requests that can be claimed including the ones already claimed + /// claimed - total of all the requests that have been claimed + /// nextWithdrawalIndex - index of the next withdrawal request starting at 0 + // slither-disable-next-line uninitialized-state + WithdrawalQueueMetadata public withdrawalQueueMetadata; + + struct WithdrawalRequest { + address withdrawer; + bool claimed; + uint40 timestamp; // timestamp of the withdrawal request + // Amount of oTokens to redeem. eg OETH + uint128 amount; + // cumulative total of all withdrawal requests including this one. + // this request can be claimed when this queued amount is less than or equal to the queue's claimable amount. + uint128 queued; + } + + /// @notice Mapping of withdrawal request indices to the user withdrawal request data + mapping(uint256 => WithdrawalRequest) public withdrawalRequests; + // For future use - uint256[50] private __gap; + uint256[46] private __gap; /** * @notice set the implementation for the admin, this needs to be in a base class else we cannot set it diff --git a/contracts/deploy/deployActions.js b/contracts/deploy/deployActions.js index 2892193eb5..28c226354d 100644 --- a/contracts/deploy/deployActions.js +++ b/contracts/deploy/deployActions.js @@ -710,6 +710,7 @@ const deployOUSDDripper = async () => { const assetAddresses = await getAssetAddresses(deployments); const cVaultProxy = await ethers.getContract("VaultProxy"); + const cVault = await ethers.getContractAt("IVault", cVaultProxy.address); // Deploy Dripper Impl const dDripper = await deployWithConfirmation("Dripper", [ @@ -726,8 +727,21 @@ const deployOUSDDripper = async () => { [] ) ); + const cDripper = await ethers.getContractAt( + "OETHDripper", + cDripperProxy.address + ); + + const sGovernor = await ethers.provider.getSigner(governorAddr); + // duration of 14 days + await withConfirmation( + cDripper.connect(sGovernor).setDripDuration(14 * 24 * 60 * 60) + ); + await withConfirmation( + cVault.connect(sGovernor).setDripper(cDripperProxy.address) + ); - return cDripperProxy; + return cDripper; }; const deployOETHDripper = async () => { @@ -735,6 +749,7 @@ const deployOETHDripper = async () => { const assetAddresses = await getAssetAddresses(deployments); const cVaultProxy = await ethers.getContract("OETHVaultProxy"); + const cVault = await ethers.getContractAt("IVault", cVaultProxy.address); // Deploy Dripper Impl const dDripper = await deployWithConfirmation("OETHDripper", [ @@ -752,8 +767,23 @@ const deployOETHDripper = async () => { [] ) ); + const cDripper = await ethers.getContractAt( + "OETHDripper", + cDripperProxy.address + ); - return cDripperProxy; + const sGovernor = await ethers.provider.getSigner(governorAddr); + + // duration of 14 days + await withConfirmation( + cDripper.connect(sGovernor).setDripDuration(14 * 24 * 60 * 60) + ); + + await withConfirmation( + cVault.connect(sGovernor).setDripper(cDripperProxy.address) + ); + + return cDripper; }; const deployDrippers = async () => { @@ -1066,7 +1096,9 @@ const deployOETHCore = async () => { const dOETHVaultCore = await deployWithConfirmation("OETHVaultCore", [ assetAddresses.WETH, ]); - const dOETHVaultAdmin = await deployWithConfirmation("OETHVaultAdmin"); + const dOETHVaultAdmin = await deployWithConfirmation("OETHVaultAdmin", [ + assetAddresses.WETH, + ]); // Get contract instances const cOETHProxy = await ethers.getContract("OETHProxy"); diff --git a/contracts/deploy/holesky/015_oeth_withdrawal_queue.js b/contracts/deploy/holesky/015_oeth_withdrawal_queue.js new file mode 100644 index 0000000000..eb8af1c8d1 --- /dev/null +++ b/contracts/deploy/holesky/015_oeth_withdrawal_queue.js @@ -0,0 +1,58 @@ +const { + deployWithConfirmation, + withConfirmation, +} = require("../../utils/deploy"); + +const addresses = require("../../utils/addresses"); + +const mainExport = async () => { + console.log("Running 015 deployment on Holesky..."); + + const { governorAddr } = await getNamedAccounts(); + const sGovernor = await ethers.provider.getSigner(governorAddr); + + // 1. Deploy new OETH Vault Core and Admin implementations + // Need to override the storage safety check as we are repacking the + // internal assets mapping to just use 1 storage slot + const dVaultCore = await deployWithConfirmation( + "OETHVaultCore", + [addresses.holesky.WETH], + null, + true + ); + console.log(`OETHVaultCore deployed to ${dVaultCore.address}`); + + const dVaultAdmin = await deployWithConfirmation( + "OETHVaultAdmin", + [addresses.holesky.WETH], + null, + true + ); + console.log(`OETHVaultAdmin deployed to ${dVaultAdmin.address}`); + + // 2. Connect to the OETH Vault as its governor via the proxy + const cVaultProxy = await ethers.getContract("OETHVaultProxy"); + const cVault = await ethers.getContractAt("OETHVault", cVaultProxy.address); + const cDripperProxy = await ethers.getContract("OETHDripperProxy"); + + // 3. Execute the Governance actions + await withConfirmation( + cVaultProxy.connect(sGovernor).upgradeTo(dVaultCore.address) + ); + await withConfirmation( + cVault.connect(sGovernor).setAdminImpl(dVaultAdmin.address) + ); + await withConfirmation( + cVault.connect(sGovernor).setDripper(cDripperProxy.address) + ); + + console.log("Running 015 deployment done"); + return true; +}; + +mainExport.id = "015_oeth_withdrawal_queue"; +mainExport.tags = []; +mainExport.dependencies = []; +mainExport.skip = () => false; + +module.exports = mainExport; diff --git a/contracts/deploy/holesky/015_upgrade_strategy.js b/contracts/deploy/holesky/016_upgrade_strategy.js similarity index 66% rename from contracts/deploy/holesky/015_upgrade_strategy.js rename to contracts/deploy/holesky/016_upgrade_strategy.js index 6169c2605c..2c8e1118f2 100644 --- a/contracts/deploy/holesky/015_upgrade_strategy.js +++ b/contracts/deploy/holesky/016_upgrade_strategy.js @@ -1,15 +1,15 @@ const { upgradeNativeStakingSSVStrategy } = require("../deployActions"); const mainExport = async () => { - console.log("Running 015 deployment on Holesky..."); + console.log("Running 016 deployment on Holesky..."); await upgradeNativeStakingSSVStrategy(); - console.log("Running 015 deployment done"); + console.log("Running 016 deployment done"); return true; }; -mainExport.id = "015_upgrade_strategy"; +mainExport.id = "016_upgrade_strategy"; mainExport.tags = []; mainExport.dependencies = []; mainExport.skip = () => false; diff --git a/contracts/deploy/mainnet/103_oeth_withdraw_queue.js b/contracts/deploy/mainnet/103_oeth_withdraw_queue.js new file mode 100644 index 0000000000..44eaba2246 --- /dev/null +++ b/contracts/deploy/mainnet/103_oeth_withdraw_queue.js @@ -0,0 +1,135 @@ +const { formatUnits, parseEther } = require("ethers/lib/utils"); + +const addresses = require("../../utils/addresses"); +const { deploymentWithGovernanceProposal } = require("../../utils/deploy"); + +module.exports = deploymentWithGovernanceProposal( + { + deployName: "103_oeth_withdraw_queue", + forceDeploy: false, + //forceSkip: true, + reduceQueueTime: true, + deployerIsProposer: false, + // proposalId: + }, + async ({ deployWithConfirmation }) => { + // Deployer Actions + // ---------------- + + // 1. Deploy new OETH Vault Core and Admin implementations + // Need to override the storage safety check as we are repacking the + // internal assets mapping to just use 1 storage slot + const dVaultCore = await deployWithConfirmation( + "OETHVaultCore", + [addresses.mainnet.WETH], + null, + true + ); + const dVaultAdmin = await deployWithConfirmation( + "OETHVaultAdmin", + [addresses.mainnet.WETH], + null, + true + ); + + // 2. Connect to the OETH Vault as its governor via the proxy + const cVaultProxy = await ethers.getContract("OETHVaultProxy"); + const cVault = await ethers.getContractAt("IVault", cVaultProxy.address); + const cDripperProxy = await ethers.getContract("OETHDripperProxy"); + + const cLidoWithdrawStrategyProxy = await ethers.getContract( + "LidoWithdrawalStrategyProxy" + ); + const cOETHMorphoAaveStrategyProxy = await ethers.getContract( + "OETHMorphoAaveStrategyProxy" + ); + + const stETH = await ethers.getContractAt("IERC20", addresses.mainnet.stETH); + const stEthInVault = await stETH.balanceOf(cVault.address); + console.log( + `There is ${formatUnits(stEthInVault)} stETH in the OETH Vault` + ); + + const rETH = await ethers.getContractAt("IERC20", addresses.mainnet.rETH); + const rEthInVault = await rETH.balanceOf(cVault.address); + console.log(`There is ${formatUnits(rEthInVault)} rETH in the OETH Vault`); + + const cNativeStakingStrategy2Proxy = await ethers.getContract( + "NativeStakingSSVStrategy2Proxy" + ); + + // Governance Actions + // ---------------- + return { + name: "Upgrade OETH Vault to support queued withdrawals", + actions: [ + // 1. Remove the Lido Withdraw Strategy + { + contract: cVault, + signature: "removeStrategy(address)", + args: [cLidoWithdrawStrategyProxy.address], + }, + // 2. Remove the Morpho Strategy + { + contract: cVault, + signature: "removeStrategy(address)", + args: [cOETHMorphoAaveStrategyProxy.address], + }, + // 3. Remove stETH from the OETH Vault + { + contract: cVault, + signature: "removeAsset(address)", + args: [stETH.address], + }, + // 4. Remove rETH from the OETH Vault + { + contract: cVault, + signature: "removeAsset(address)", + args: [rETH.address], + }, + // 5. Cache WETH asset index now stETH has been removed + // the WETH index should go from 1 to 0 + { + contract: cVault, + signature: "cacheWETHAssetIndex()", + args: [], + }, + // 6. Upgrade the OETH Vault proxy to the new core vault implementation + { + contract: cVaultProxy, + signature: "upgradeTo(address)", + args: [dVaultCore.address], + }, + // 7. set OETH Vault proxy to the new admin vault implementation + { + contract: cVault, + signature: "setAdminImpl(address)", + args: [dVaultAdmin.address], + }, + // 8. Set the Dripper contract + { + contract: cVault, + signature: "setDripper(address)", + args: [cDripperProxy.address], + }, + // 9. Set the second Native Staking Strategy as the default for WETH + { + contract: cVault, + signature: "setAssetDefaultStrategy(address,address)", + args: [addresses.mainnet.WETH, cNativeStakingStrategy2Proxy.address], + }, + // 10. Set Vault buffer to 0.2% + { + contract: cVault, + signature: "setVaultBuffer(uint256)", + args: [parseEther("0.002")], + }, + // 11. Allocate WETH to the second Native Staking Strategy + { + contract: cVault, + signature: "allocate()", + }, + ], + }; + } +); diff --git a/contracts/deployments/holesky/.migrations.json b/contracts/deployments/holesky/.migrations.json index 3a973797ad..c73f5e4cd0 100644 --- a/contracts/deployments/holesky/.migrations.json +++ b/contracts/deployments/holesky/.migrations.json @@ -13,5 +13,6 @@ "012_upgrade_strategy": 1717477122, "013_upgrade_strategy": 1717803989, "014_upgrade_strategy": 1717806940, - "015_upgrade_strategy": 1721109545 -} \ No newline at end of file + "015_oeth_withdrawal_queue": 1720063996, + "016_upgrade_strategy": 1721109545 +} diff --git a/contracts/deployments/holesky/OETHVaultAdmin.json b/contracts/deployments/holesky/OETHVaultAdmin.json index c58d7d080f..4828a22e3d 100644 --- a/contracts/deployments/holesky/OETHVaultAdmin.json +++ b/contracts/deployments/holesky/OETHVaultAdmin.json @@ -1,6 +1,17 @@ { - "address": "0xa94c4aab0Cf9f6E79bB064DB145fBe2506b9Fa75", + "address": "0x8AAcc620050a399F5829422bD0c45Db1Af90ea37", "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "_weth", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, { "anonymous": false, "inputs": [ @@ -58,6 +69,19 @@ "name": "AssetDefaultStrategyUpdated", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_asset", + "type": "address" + } + ], + "name": "AssetRemoved", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -83,6 +107,19 @@ "name": "CapitalUnpaused", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_dripper", + "type": "address" + } + ], + "name": "DripperChanged", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -403,6 +440,81 @@ "name": "VaultBufferUpdated", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_claimable", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_newClaimable", + "type": "uint256" + } + ], + "name": "WithdrawalClaimable", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_withdrawer", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "_requestId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "WithdrawalClaimed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_withdrawer", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "_requestId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_queued", + "type": "uint256" + } + ], + "name": "WithdrawalRequested", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -542,6 +654,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "dripper", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "governor", @@ -686,6 +811,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "_asset", + "type": "address" + } + ], + "name": "removeAsset", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -743,6 +881,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "_dripper", + "type": "address" + } + ], + "name": "setDripper", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -1084,6 +1235,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "weth", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "withdrawAllFromStrategies", @@ -1126,45 +1290,109 @@ "outputs": [], "stateMutability": "nonpayable", "type": "function" + }, + { + "inputs": [], + "name": "withdrawalQueueMetadata", + "outputs": [ + { + "internalType": "uint128", + "name": "queued", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "claimable", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "claimed", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "nextWithdrawalIndex", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "withdrawalRequests", + "outputs": [ + { + "internalType": "address", + "name": "withdrawer", + "type": "address" + }, + { + "internalType": "bool", + "name": "claimed", + "type": "bool" + }, + { + "internalType": "uint128", + "name": "amount", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "queued", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" } ], - "transactionHash": "0xe29b0302a257a781d787f590e9502246b3ac3fe2f2d3c39d37d3ac9e856057eb", + "transactionHash": "0xcbe9723c967f2ca8cd45fd0b0d7060699b801811bf5e4d5a07eb76f72e60bc54", "receipt": { "to": null, "from": "0x1b94CA50D3Ad9f8368851F8526132272d1a5028C", - "contractAddress": "0xa94c4aab0Cf9f6E79bB064DB145fBe2506b9Fa75", - "transactionIndex": 39, - "gasUsed": "3146556", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000040000010000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000004000000000000002000000000000000000040000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000010000000000010000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0x50619ec9fad9061d57a94456471009c7fa5c0cf4d68201956bf36a07a219f708", - "transactionHash": "0xe29b0302a257a781d787f590e9502246b3ac3fe2f2d3c39d37d3ac9e856057eb", + "contractAddress": "0x8AAcc620050a399F5829422bD0c45Db1Af90ea37", + "transactionIndex": 20, + "gasUsed": "3664700", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000008040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000004000000000000002000000002000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000010000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0xb489f8e204ab36549d803d7e70f4b001e6285d7b51066908f22d01af75b10d1e", + "transactionHash": "0xcbe9723c967f2ca8cd45fd0b0d7060699b801811bf5e4d5a07eb76f72e60bc54", "logs": [ { - "transactionIndex": 39, - "blockNumber": 1405067, - "transactionHash": "0xe29b0302a257a781d787f590e9502246b3ac3fe2f2d3c39d37d3ac9e856057eb", - "address": "0xa94c4aab0Cf9f6E79bB064DB145fBe2506b9Fa75", + "transactionIndex": 20, + "blockNumber": 1860261, + "transactionHash": "0xcbe9723c967f2ca8cd45fd0b0d7060699b801811bf5e4d5a07eb76f72e60bc54", + "address": "0x8AAcc620050a399F5829422bD0c45Db1Af90ea37", "topics": [ "0xc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000001b94ca50d3ad9f8368851f8526132272d1a5028c" ], "data": "0x", - "logIndex": 121, - "blockHash": "0x50619ec9fad9061d57a94456471009c7fa5c0cf4d68201956bf36a07a219f708" + "logIndex": 20, + "blockHash": "0xb489f8e204ab36549d803d7e70f4b001e6285d7b51066908f22d01af75b10d1e" } ], - "blockNumber": 1405067, - "cumulativeGasUsed": "6442389", + "blockNumber": 1860261, + "cumulativeGasUsed": "6071664", "status": 1, "byzantium": true }, - "args": [], - "numDeployments": 1, - "solcInputHash": "da4c2bc4af0be4b969e54f8b43895033", - "metadata": "{\"compiler\":{\"version\":\"0.8.7+commit.e28d00a7\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"AllocateThresholdUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_strategy\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"AssetAllocated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_strategy\",\"type\":\"address\"}],\"name\":\"AssetDefaultStrategyUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"AssetSupported\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"CapitalPaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"CapitalUnpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"GovernorshipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"maxSupplyDiff\",\"type\":\"uint256\"}],\"name\":\"MaxSupplyDiffChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"Mint\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"NetOusdMintForStrategyThresholdChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_ousdMetaStrategy\",\"type\":\"address\"}],\"name\":\"OusdMetaStrategyUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"PendingGovernorshipTransfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_priceProvider\",\"type\":\"address\"}],\"name\":\"PriceProviderUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"RebasePaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"RebaseThresholdUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"RebaseUnpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"Redeem\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_redeemFeeBps\",\"type\":\"uint256\"}],\"name\":\"RedeemFeeUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"StrategistUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"StrategyApproved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"StrategyRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_basis\",\"type\":\"uint256\"}],\"name\":\"SwapAllowedUndervalueChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_basis\",\"type\":\"uint256\"}],\"name\":\"SwapSlippageChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_fromAsset\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_toAsset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_fromAssetAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_toAssetAmount\",\"type\":\"uint256\"}],\"name\":\"Swapped\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"SwapperChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"TrusteeAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_basis\",\"type\":\"uint256\"}],\"name\":\"TrusteeFeeBpsChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_vaultBuffer\",\"type\":\"uint256\"}],\"name\":\"VaultBufferUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_yield\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_fee\",\"type\":\"uint256\"}],\"name\":\"YieldDistribution\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"allowedSwapUndervalue\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"approveStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"assetDefaultStrategies\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"autoAllocateThreshold\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"cacheDecimals\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"capitalPaused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategyToAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"_assets\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_amounts\",\"type\":\"uint256[]\"}],\"name\":\"depositToStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"governor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maxSupplyDiff\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"netOusdMintForStrategyThreshold\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"netOusdMintedForStrategy\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"ousdMetaStrategy\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pauseCapital\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pauseRebase\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"priceProvider\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebasePaused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebaseThreshold\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"redeemFeeBps\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"removeStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImpl\",\"type\":\"address\"}],\"name\":\"setAdminImpl\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_strategy\",\"type\":\"address\"}],\"name\":\"setAssetDefaultStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"setAutoAllocateThreshold\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_maxSupplyDiff\",\"type\":\"uint256\"}],\"name\":\"setMaxSupplyDiff\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"setNetOusdMintForStrategyThreshold\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"_allowedOracleSlippageBps\",\"type\":\"uint16\"}],\"name\":\"setOracleSlippage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_ousdMetaStrategy\",\"type\":\"address\"}],\"name\":\"setOusdMetaStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_priceProvider\",\"type\":\"address\"}],\"name\":\"setPriceProvider\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"setRebaseThreshold\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_redeemFeeBps\",\"type\":\"uint256\"}],\"name\":\"setRedeemFeeBps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"setStrategistAddr\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"_basis\",\"type\":\"uint16\"}],\"name\":\"setSwapAllowedUndervalue\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_swapperAddr\",\"type\":\"address\"}],\"name\":\"setSwapper\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"setTrusteeAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_basis\",\"type\":\"uint256\"}],\"name\":\"setTrusteeFeeBps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_vaultBuffer\",\"type\":\"uint256\"}],\"name\":\"setVaultBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"strategistAddr\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"_unitConversion\",\"type\":\"uint8\"}],\"name\":\"supportAsset\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_fromAsset\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_toAsset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_fromAssetAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_minToAssetAmount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"swapCollateral\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"toAssetAmount\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"swapper\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"swapper_\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newGovernor\",\"type\":\"address\"}],\"name\":\"transferGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"transferToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"trusteeAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"trusteeFeeBps\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpauseCapital\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpauseRebase\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"vaultBuffer\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawAllFromStrategies\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategyAddr\",\"type\":\"address\"}],\"name\":\"withdrawAllFromStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategyFromAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"_assets\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_amounts\",\"type\":\"uint256[]\"}],\"name\":\"withdrawFromStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"Origin Protocol Inc\",\"kind\":\"dev\",\"methods\":{\"allowedSwapUndervalue()\":{\"returns\":{\"value\":\"Percentage in basis points.\"}},\"approveStrategy(address)\":{\"params\":{\"_addr\":\"Address of the strategy to add\"}},\"cacheDecimals(address)\":{\"params\":{\"_asset\":\"Address of asset token\"}},\"depositToStrategy(address,address[],uint256[])\":{\"params\":{\"_amounts\":\"Array of amounts of each corresponding asset to deposit.\",\"_assets\":\"Array of asset address that will be deposited into the strategy.\",\"_strategyToAddress\":\"Address of the Strategy to deposit assets into.\"}},\"removeStrategy(address)\":{\"params\":{\"_addr\":\"Address of the strategy to remove\"}},\"setAdminImpl(address)\":{\"params\":{\"newImpl\":\"address of the implementation\"}},\"setAssetDefaultStrategy(address,address)\":{\"params\":{\"_asset\":\"Address of the asset\",\"_strategy\":\"Address of the Strategy\"}},\"setAutoAllocateThreshold(uint256)\":{\"params\":{\"_threshold\":\"OToken amount with 18 fixed decimals.\"}},\"setNetOusdMintForStrategyThreshold(uint256)\":{\"params\":{\"_threshold\":\"OToken amount with 18 fixed decimals.\"}},\"setOracleSlippage(address,uint16)\":{\"params\":{\"_allowedOracleSlippageBps\":\"allowed slippage from Oracle in basis points. eg 20 = 0.2%. Max 10%.\",\"_asset\":\"Address of the asset token.\"}},\"setOusdMetaStrategy(address)\":{\"params\":{\"_ousdMetaStrategy\":\"Address of OToken metapool strategy\"}},\"setPriceProvider(address)\":{\"params\":{\"_priceProvider\":\"Address of price provider\"}},\"setRebaseThreshold(uint256)\":{\"params\":{\"_threshold\":\"OToken amount with 18 fixed decimals.\"}},\"setRedeemFeeBps(uint256)\":{\"params\":{\"_redeemFeeBps\":\"Basis point fee to be charged\"}},\"setStrategistAddr(address)\":{\"params\":{\"_address\":\"Address of Strategist\"}},\"setSwapAllowedUndervalue(uint16)\":{\"params\":{\"_basis\":\"Percentage in basis points. eg 100 == 1%\"}},\"setSwapper(address)\":{\"params\":{\"_swapperAddr\":\"Address of the Swapper contract that implements the ISwapper interface.\"}},\"setVaultBuffer(uint256)\":{\"params\":{\"_vaultBuffer\":\"Percentage using 18 decimals. 100% = 1e18.\"}},\"supportAsset(address,uint8)\":{\"params\":{\"_asset\":\"Address of asset\"}},\"swapCollateral(address,address,uint256,uint256,bytes)\":{\"params\":{\"_data\":\"implementation specific data. eg 1Inch swap data\",\"_fromAsset\":\"The token address of the asset being sold by the vault.\",\"_fromAssetAmount\":\"The amount of assets being sold by the vault.\",\"_minToAssetAmount\":\"The minimum amount of assets to be purchased.\",\"_toAsset\":\"The token address of the asset being purchased by the vault.\"},\"returns\":{\"toAssetAmount\":\"The amount of toAssets that was received from the swap\"}},\"transferGovernance(address)\":{\"params\":{\"_newGovernor\":\"Address of the new Governor\"}},\"transferToken(address,uint256)\":{\"params\":{\"_amount\":\"Amount of the asset to transfer\",\"_asset\":\"Address for the asset\"}},\"withdrawAllFromStrategy(address)\":{\"params\":{\"_strategyAddr\":\"Strategy address.\"}},\"withdrawFromStrategy(address,address[],uint256[])\":{\"params\":{\"_amounts\":\"Array of amounts of each corresponding asset to withdraw.\",\"_assets\":\"Array of asset address that will be withdrawn from the strategy.\",\"_strategyFromAddress\":\"Address of the Strategy to withdraw assets from.\"}}},\"title\":\"OETH VaultAdmin Contract\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"allowedSwapUndervalue()\":{\"notice\":\"Max allowed percentage the vault total value can drop below the OToken total supply in basis points when executing a collateral swap. For example 100 == 1%\"},\"approveStrategy(address)\":{\"notice\":\"Add a strategy to the Vault.\"},\"assetDefaultStrategies(address)\":{\"notice\":\"Mapping of asset address to the Strategy that they should automatically\"},\"autoAllocateThreshold()\":{\"notice\":\"OToken mints over this amount automatically allocate funds. 18 decimals.\"},\"cacheDecimals(address)\":{\"notice\":\"Cache decimals on OracleRouter for a particular asset. This action is required before that asset's price can be accessed.\"},\"capitalPaused()\":{\"notice\":\"pause operations that change the OToken supply. eg mint, redeem, allocate, mint/burn for strategy\"},\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"depositToStrategy(address,address[],uint256[])\":{\"notice\":\"Deposit multiple assets from the vault into the strategy.\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"maxSupplyDiff()\":{\"notice\":\"Max difference between total supply and total value of assets. 18 decimals.\"},\"netOusdMintForStrategyThreshold()\":{\"notice\":\"How much net total OTokens are allowed to be minted by all strategies\"},\"netOusdMintedForStrategy()\":{\"notice\":\"How much OTokens are currently minted by the strategy\"},\"ousdMetaStrategy()\":{\"notice\":\"Metapool strategy that is allowed to mint/burn OTokens without changing collateral\"},\"pauseCapital()\":{\"notice\":\"Set the deposit paused flag to true to prevent capital movement.\"},\"pauseRebase()\":{\"notice\":\"Set the deposit paused flag to true to prevent rebasing.\"},\"priceProvider()\":{\"notice\":\"Address of the Oracle price provider contract\"},\"rebasePaused()\":{\"notice\":\"pause rebasing if true\"},\"rebaseThreshold()\":{\"notice\":\"OToken mints over this amount automatically rebase. 18 decimals.\"},\"redeemFeeBps()\":{\"notice\":\"Redemption fee in basis points. eg 50 = 0.5%\"},\"removeStrategy(address)\":{\"notice\":\"Remove a strategy from the Vault.\"},\"setAdminImpl(address)\":{\"notice\":\"set the implementation for the admin, this needs to be in a base class else we cannot set it\"},\"setAssetDefaultStrategy(address,address)\":{\"notice\":\"Set the default Strategy for an asset, i.e. the one which the asset will be automatically allocated to and withdrawn from\"},\"setAutoAllocateThreshold(uint256)\":{\"notice\":\"Sets the minimum amount of OTokens in a mint to trigger an automatic allocation of funds afterwords.\"},\"setMaxSupplyDiff(uint256)\":{\"notice\":\"Sets the maximum allowable difference between total supply and backing assets' value.\"},\"setNetOusdMintForStrategyThreshold(uint256)\":{\"notice\":\"Set maximum amount of OTokens that can at any point be minted and deployed to strategy (used only by ConvexOUSDMetaStrategy for now).\"},\"setOracleSlippage(address,uint16)\":{\"notice\":\"Set the allowed slippage from the Oracle price for collateral asset swaps.\"},\"setOusdMetaStrategy(address)\":{\"notice\":\"Set OToken Metapool strategy\"},\"setPriceProvider(address)\":{\"notice\":\"Set address of price provider.\"},\"setRebaseThreshold(uint256)\":{\"notice\":\"Set a minimum amount of OTokens in a mint or redeem that triggers a rebase\"},\"setRedeemFeeBps(uint256)\":{\"notice\":\"Set a fee in basis points to be charged for a redeem.\"},\"setStrategistAddr(address)\":{\"notice\":\"Set address of Strategist\"},\"setSwapAllowedUndervalue(uint16)\":{\"notice\":\"Set max allowed percentage the vault total value can drop below the OToken total supply in basis points when executing collateral swaps.\"},\"setSwapper(address)\":{\"notice\":\"Set the contract the performs swaps of collateral assets.\"},\"setTrusteeAddress(address)\":{\"notice\":\"Sets the trusteeAddress that can receive a portion of yield. Setting to the zero address disables this feature.\"},\"setTrusteeFeeBps(uint256)\":{\"notice\":\"Sets the TrusteeFeeBps to the percentage of yield that should be received in basis points.\"},\"setVaultBuffer(uint256)\":{\"notice\":\"Set a buffer of assets to keep in the Vault to handle most redemptions without needing to spend gas unwinding assets from a Strategy.\"},\"strategistAddr()\":{\"notice\":\"Address of the Strategist\"},\"supportAsset(address,uint8)\":{\"notice\":\"Add a supported asset to the contract, i.e. one that can be to mint OTokens.\"},\"swapCollateral(address,address,uint256,uint256,bytes)\":{\"notice\":\"Strategist swaps collateral assets sitting in the vault.\"},\"swapper()\":{\"notice\":\"Contract that swaps the vault's collateral assets\"},\"transferGovernance(address)\":{\"notice\":\"Transfers Governance of the contract to a new account (`newGovernor`). Can only be called by the current Governor. Must be claimed for this to complete\"},\"transferToken(address,uint256)\":{\"notice\":\"Transfer token to governor. Intended for recovering tokens stuck in contract, i.e. mistaken sends.\"},\"trusteeAddress()\":{\"notice\":\"Trustee contract that can collect a percentage of yield\"},\"trusteeFeeBps()\":{\"notice\":\"Amount of yield collected in basis points. eg 2000 = 20%\"},\"unpauseCapital()\":{\"notice\":\"Set the deposit paused flag to false to enable capital movement.\"},\"unpauseRebase()\":{\"notice\":\"Set the deposit paused flag to true to allow rebasing.\"},\"vaultBuffer()\":{\"notice\":\"Percentage of assets to keep in Vault to handle (most) withdrawals. 100% = 1e18.\"},\"withdrawAllFromStrategies()\":{\"notice\":\"Withdraws all assets from all the strategies and sends assets to the Vault.\"},\"withdrawAllFromStrategy(address)\":{\"notice\":\"Withdraws all assets from the strategy and sends assets to the Vault.\"},\"withdrawFromStrategy(address,address[],uint256[])\":{\"notice\":\"Withdraw multiple assets from the strategy to the vault.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/vault/OETHVaultAdmin.sol\":\"OETHVaultAdmin\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address recipient, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address sender,\\n address recipient,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0x61437cb513a887a1bbad006e7b1c8b414478427d33de47c5600af3c748f108da\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Address.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize, which returns 0 for contracts in\\n // construction, since the code is only stored at the end of the\\n // constructor execution.\\n\\n uint256 size;\\n assembly {\\n size := extcodesize(account)\\n }\\n return size > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x51b758a8815ecc9596c66c37d56b1d33883a444631a3f916b9fe65cb863ef7c4\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/math/SafeMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\\n\\npragma solidity ^0.8.0;\\n\\n// CAUTION\\n// This version of SafeMath should only be used with Solidity 0.8 or later,\\n// because it relies on the compiler's built in overflow checks.\\n\\n/**\\n * @dev Wrappers over Solidity's arithmetic operations.\\n *\\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\\n * now has built in overflow checking.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n uint256 c = a + b;\\n if (c < a) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b > a) return (false, 0);\\n return (true, a - b);\\n }\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) return (true, 0);\\n uint256 c = a * b;\\n if (c / a != b) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a / b);\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a % b);\\n }\\n }\\n\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n *\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a + b;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n *\\n * - Subtraction cannot overflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a - b;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n *\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a * b;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator.\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a / b;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a % b;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\\n * overflow (when the result is negative).\\n *\\n * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {trySub}.\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n *\\n * - Subtraction cannot overflow.\\n */\\n function sub(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b <= a, errorMessage);\\n return a - b;\\n }\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function div(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a / b;\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting with custom message when dividing by zero.\\n *\\n * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {tryMod}.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function mod(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a % b;\\n }\\n }\\n}\\n\",\"keccak256\":\"0xa2f576be637946f767aa56601c26d717f48a0aff44f82e46f13807eea1009a21\",\"license\":\"MIT\"},\"contracts/governance/Governable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Base for contracts that are managed by the Origin Protocol's Governor.\\n * @dev Copy of the openzeppelin Ownable.sol contract with nomenclature change\\n * from owner to governor and renounce methods removed. Does not use\\n * Context.sol like Ownable.sol does for simplification.\\n * @author Origin Protocol Inc\\n */\\ncontract Governable {\\n // Storage position of the owner and pendingOwner of the contract\\n // keccak256(\\\"OUSD.governor\\\");\\n bytes32 private constant governorPosition =\\n 0x7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a;\\n\\n // keccak256(\\\"OUSD.pending.governor\\\");\\n bytes32 private constant pendingGovernorPosition =\\n 0x44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db;\\n\\n // keccak256(\\\"OUSD.reentry.status\\\");\\n bytes32 private constant reentryStatusPosition =\\n 0x53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac4535;\\n\\n // See OpenZeppelin ReentrancyGuard implementation\\n uint256 constant _NOT_ENTERED = 1;\\n uint256 constant _ENTERED = 2;\\n\\n event PendingGovernorshipTransfer(\\n address indexed previousGovernor,\\n address indexed newGovernor\\n );\\n\\n event GovernorshipTransferred(\\n address indexed previousGovernor,\\n address indexed newGovernor\\n );\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial Governor.\\n */\\n constructor() {\\n _setGovernor(msg.sender);\\n emit GovernorshipTransferred(address(0), _governor());\\n }\\n\\n /**\\n * @notice Returns the address of the current Governor.\\n */\\n function governor() public view returns (address) {\\n return _governor();\\n }\\n\\n /**\\n * @dev Returns the address of the current Governor.\\n */\\n function _governor() internal view returns (address governorOut) {\\n bytes32 position = governorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n governorOut := sload(position)\\n }\\n }\\n\\n /**\\n * @dev Returns the address of the pending Governor.\\n */\\n function _pendingGovernor()\\n internal\\n view\\n returns (address pendingGovernor)\\n {\\n bytes32 position = pendingGovernorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n pendingGovernor := sload(position)\\n }\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the Governor.\\n */\\n modifier onlyGovernor() {\\n require(isGovernor(), \\\"Caller is not the Governor\\\");\\n _;\\n }\\n\\n /**\\n * @notice Returns true if the caller is the current Governor.\\n */\\n function isGovernor() public view returns (bool) {\\n return msg.sender == _governor();\\n }\\n\\n function _setGovernor(address newGovernor) internal {\\n bytes32 position = governorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, newGovernor)\\n }\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a `nonReentrant` function from another `nonReentrant`\\n * function is not supported. It is possible to prevent this from happening\\n * by making the `nonReentrant` function external, and make it call a\\n * `private` function that does the actual work.\\n */\\n modifier nonReentrant() {\\n bytes32 position = reentryStatusPosition;\\n uint256 _reentry_status;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n _reentry_status := sload(position)\\n }\\n\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_reentry_status != _ENTERED, \\\"Reentrant call\\\");\\n\\n // Any calls to nonReentrant after this point will fail\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, _ENTERED)\\n }\\n\\n _;\\n\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, _NOT_ENTERED)\\n }\\n }\\n\\n function _setPendingGovernor(address newGovernor) internal {\\n bytes32 position = pendingGovernorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, newGovernor)\\n }\\n }\\n\\n /**\\n * @notice Transfers Governance of the contract to a new account (`newGovernor`).\\n * Can only be called by the current Governor. Must be claimed for this to complete\\n * @param _newGovernor Address of the new Governor\\n */\\n function transferGovernance(address _newGovernor) external onlyGovernor {\\n _setPendingGovernor(_newGovernor);\\n emit PendingGovernorshipTransfer(_governor(), _newGovernor);\\n }\\n\\n /**\\n * @notice Claim Governance of the contract to a new account (`newGovernor`).\\n * Can only be called by the new Governor.\\n */\\n function claimGovernance() external {\\n require(\\n msg.sender == _pendingGovernor(),\\n \\\"Only the pending Governor can complete the claim\\\"\\n );\\n _changeGovernor(msg.sender);\\n }\\n\\n /**\\n * @dev Change Governance of the contract to a new account (`newGovernor`).\\n * @param _newGovernor Address of the new Governor\\n */\\n function _changeGovernor(address _newGovernor) internal {\\n require(_newGovernor != address(0), \\\"New Governor is address(0)\\\");\\n emit GovernorshipTransferred(_governor(), _newGovernor);\\n _setGovernor(_newGovernor);\\n }\\n}\\n\",\"keccak256\":\"0xb7133d6ce7a9e673ff79fcedb3fd41ae6e58e251f94915bb65731abe524270b4\",\"license\":\"MIT\"},\"contracts/interfaces/IBasicToken.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IBasicToken {\\n function symbol() external view returns (string memory);\\n\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0xa562062698aa12572123b36dfd2072f1a39e44fed2031cc19c2c9fd522f96ec2\",\"license\":\"MIT\"},\"contracts/interfaces/IOracle.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IOracle {\\n /**\\n * @dev returns the asset price in USD, in 8 decimal digits.\\n *\\n * The version of priceProvider deployed for OETH has 18 decimal digits\\n */\\n function price(address asset) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0x9eabf152389f145c9c23ed71972af73fb1708cbc4b26e524a9ba29a557b7cfe5\",\"license\":\"MIT\"},\"contracts/interfaces/IStrategy.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Platform interface to integrate with lending platform like Compound, AAVE etc.\\n */\\ninterface IStrategy {\\n /**\\n * @dev Deposit the given asset to platform\\n * @param _asset asset address\\n * @param _amount Amount to deposit\\n */\\n function deposit(address _asset, uint256 _amount) external;\\n\\n /**\\n * @dev Deposit the entire balance of all supported assets in the Strategy\\n * to the platform\\n */\\n function depositAll() external;\\n\\n /**\\n * @dev Withdraw given asset from Lending platform\\n */\\n function withdraw(\\n address _recipient,\\n address _asset,\\n uint256 _amount\\n ) external;\\n\\n /**\\n * @dev Liquidate all assets in strategy and return them to Vault.\\n */\\n function withdrawAll() external;\\n\\n /**\\n * @dev Returns the current balance of the given asset.\\n */\\n function checkBalance(address _asset)\\n external\\n view\\n returns (uint256 balance);\\n\\n /**\\n * @dev Returns bool indicating whether strategy supports asset.\\n */\\n function supportsAsset(address _asset) external view returns (bool);\\n\\n /**\\n * @dev Collect reward tokens from the Strategy.\\n */\\n function collectRewardTokens() external;\\n\\n /**\\n * @dev The address array of the reward tokens for the Strategy.\\n */\\n function getRewardTokenAddresses() external view returns (address[] memory);\\n}\\n\",\"keccak256\":\"0xb291e409a9b95527f9ed19cd6bff8eeb9921a21c1f5194a48c0bb9ce6613959a\",\"license\":\"MIT\"},\"contracts/interfaces/ISwapper.sol\":{\"content\":\"pragma solidity ^0.8.0;\\n\\ninterface ISwapper {\\n /**\\n * @param fromAsset The token address of the asset being sold.\\n * @param toAsset The token address of the asset being purchased.\\n * @param fromAssetAmount The amount of assets being sold.\\n * @param minToAssetAmmount The minimum amount of assets to be purchased.\\n * @param data tx.data returned from 1Inch's /v5.0/1/swap API\\n */\\n function swap(\\n address fromAsset,\\n address toAsset,\\n uint256 fromAssetAmount,\\n uint256 minToAssetAmmount,\\n bytes calldata data\\n ) external returns (uint256 toAssetAmount);\\n}\\n\",\"keccak256\":\"0xf6452c70d5dbfde99e6e82cd6b49d8cbec8efb48da77e28603bea981b8b0759e\"},\"contracts/interfaces/IVault.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { VaultStorage } from \\\"../vault/VaultStorage.sol\\\";\\n\\ninterface IVault {\\n event AssetSupported(address _asset);\\n event AssetDefaultStrategyUpdated(address _asset, address _strategy);\\n event AssetAllocated(address _asset, address _strategy, uint256 _amount);\\n event StrategyApproved(address _addr);\\n event StrategyRemoved(address _addr);\\n event Mint(address _addr, uint256 _value);\\n event Redeem(address _addr, uint256 _value);\\n event CapitalPaused();\\n event CapitalUnpaused();\\n event RebasePaused();\\n event RebaseUnpaused();\\n event VaultBufferUpdated(uint256 _vaultBuffer);\\n event RedeemFeeUpdated(uint256 _redeemFeeBps);\\n event PriceProviderUpdated(address _priceProvider);\\n event AllocateThresholdUpdated(uint256 _threshold);\\n event RebaseThresholdUpdated(uint256 _threshold);\\n event StrategistUpdated(address _address);\\n event MaxSupplyDiffChanged(uint256 maxSupplyDiff);\\n event YieldDistribution(address _to, uint256 _yield, uint256 _fee);\\n event TrusteeFeeBpsChanged(uint256 _basis);\\n event TrusteeAddressChanged(address _address);\\n event SwapperChanged(address _address);\\n event SwapAllowedUndervalueChanged(uint256 _basis);\\n event SwapSlippageChanged(address _asset, uint256 _basis);\\n event Swapped(\\n address indexed _fromAsset,\\n address indexed _toAsset,\\n uint256 _fromAssetAmount,\\n uint256 _toAssetAmount\\n );\\n\\n // Governable.sol\\n function transferGovernance(address _newGovernor) external;\\n\\n function claimGovernance() external;\\n\\n function governor() external view returns (address);\\n\\n // VaultAdmin.sol\\n function setPriceProvider(address _priceProvider) external;\\n\\n function priceProvider() external view returns (address);\\n\\n function setRedeemFeeBps(uint256 _redeemFeeBps) external;\\n\\n function redeemFeeBps() external view returns (uint256);\\n\\n function setVaultBuffer(uint256 _vaultBuffer) external;\\n\\n function vaultBuffer() external view returns (uint256);\\n\\n function setAutoAllocateThreshold(uint256 _threshold) external;\\n\\n function autoAllocateThreshold() external view returns (uint256);\\n\\n function setRebaseThreshold(uint256 _threshold) external;\\n\\n function rebaseThreshold() external view returns (uint256);\\n\\n function setStrategistAddr(address _address) external;\\n\\n function strategistAddr() external view returns (address);\\n\\n function setMaxSupplyDiff(uint256 _maxSupplyDiff) external;\\n\\n function maxSupplyDiff() external view returns (uint256);\\n\\n function setTrusteeAddress(address _address) external;\\n\\n function trusteeAddress() external view returns (address);\\n\\n function setTrusteeFeeBps(uint256 _basis) external;\\n\\n function trusteeFeeBps() external view returns (uint256);\\n\\n function ousdMetaStrategy() external view returns (address);\\n\\n function setSwapper(address _swapperAddr) external;\\n\\n function setSwapAllowedUndervalue(uint16 _percentageBps) external;\\n\\n function setOracleSlippage(address _asset, uint16 _allowedOracleSlippageBps)\\n external;\\n\\n function supportAsset(address _asset, uint8 _supportsAsset) external;\\n\\n function approveStrategy(address _addr) external;\\n\\n function removeStrategy(address _addr) external;\\n\\n function setAssetDefaultStrategy(address _asset, address _strategy)\\n external;\\n\\n function assetDefaultStrategies(address _asset)\\n external\\n view\\n returns (address);\\n\\n function pauseRebase() external;\\n\\n function unpauseRebase() external;\\n\\n function rebasePaused() external view returns (bool);\\n\\n function pauseCapital() external;\\n\\n function unpauseCapital() external;\\n\\n function capitalPaused() external view returns (bool);\\n\\n function transferToken(address _asset, uint256 _amount) external;\\n\\n function priceUnitMint(address asset) external view returns (uint256);\\n\\n function priceUnitRedeem(address asset) external view returns (uint256);\\n\\n function withdrawAllFromStrategy(address _strategyAddr) external;\\n\\n function withdrawAllFromStrategies() external;\\n\\n function withdrawFromStrategy(\\n address _strategyFromAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) external;\\n\\n function depositToStrategy(\\n address _strategyToAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) external;\\n\\n // VaultCore.sol\\n function mint(\\n address _asset,\\n uint256 _amount,\\n uint256 _minimumOusdAmount\\n ) external;\\n\\n function mintForStrategy(uint256 _amount) external;\\n\\n function redeem(uint256 _amount, uint256 _minimumUnitAmount) external;\\n\\n function burnForStrategy(uint256 _amount) external;\\n\\n function redeemAll(uint256 _minimumUnitAmount) external;\\n\\n function allocate() external;\\n\\n function rebase() external;\\n\\n function swapCollateral(\\n address fromAsset,\\n address toAsset,\\n uint256 fromAssetAmount,\\n uint256 minToAssetAmount,\\n bytes calldata data\\n ) external returns (uint256 toAssetAmount);\\n\\n function totalValue() external view returns (uint256 value);\\n\\n function checkBalance(address _asset) external view returns (uint256);\\n\\n function calculateRedeemOutputs(uint256 _amount)\\n external\\n view\\n returns (uint256[] memory);\\n\\n function getAssetCount() external view returns (uint256);\\n\\n function getAssetConfig(address _asset)\\n external\\n view\\n returns (VaultStorage.Asset memory config);\\n\\n function getAllAssets() external view returns (address[] memory);\\n\\n function getStrategyCount() external view returns (uint256);\\n\\n function swapper() external view returns (address);\\n\\n function allowedSwapUndervalue() external view returns (uint256);\\n\\n function getAllStrategies() external view returns (address[] memory);\\n\\n function isSupportedAsset(address _asset) external view returns (bool);\\n\\n function netOusdMintForStrategyThreshold() external view returns (uint256);\\n\\n function setOusdMetaStrategy(address _ousdMetaStrategy) external;\\n\\n function setNetOusdMintForStrategyThreshold(uint256 _threshold) external;\\n\\n function netOusdMintedForStrategy() external view returns (int256);\\n\\n function weth() external view returns (address);\\n\\n function cacheWETHAssetIndex() external;\\n\\n function wethAssetIndex() external view returns (uint256);\\n\\n function initialize(address, address) external;\\n\\n function setAdminImpl(address) external;\\n}\\n\",\"keccak256\":\"0xe8ab2f09127dc86bda14d2ad7f58d4f5ef214959101742f0dd977be3599f9d5f\",\"license\":\"MIT\"},\"contracts/token/OUSD.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OUSD Token Contract\\n * @dev ERC20 compatible contract for OUSD\\n * @dev Implements an elastic supply\\n * @author Origin Protocol Inc\\n */\\nimport { SafeMath } from \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\nimport { Address } from \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport { Initializable } from \\\"../utils/Initializable.sol\\\";\\nimport { InitializableERC20Detailed } from \\\"../utils/InitializableERC20Detailed.sol\\\";\\nimport { StableMath } from \\\"../utils/StableMath.sol\\\";\\nimport { Governable } from \\\"../governance/Governable.sol\\\";\\n\\n/**\\n * NOTE that this is an ERC20 token but the invariant that the sum of\\n * balanceOf(x) for all x is not >= totalSupply(). This is a consequence of the\\n * rebasing design. Any integrations with OUSD should be aware.\\n */\\n\\ncontract OUSD is Initializable, InitializableERC20Detailed, Governable {\\n using SafeMath for uint256;\\n using StableMath for uint256;\\n\\n event TotalSupplyUpdatedHighres(\\n uint256 totalSupply,\\n uint256 rebasingCredits,\\n uint256 rebasingCreditsPerToken\\n );\\n event AccountRebasingEnabled(address account);\\n event AccountRebasingDisabled(address account);\\n\\n enum RebaseOptions {\\n NotSet,\\n OptOut,\\n OptIn\\n }\\n\\n uint256 private constant MAX_SUPPLY = ~uint128(0); // (2^128) - 1\\n uint256 public _totalSupply;\\n mapping(address => mapping(address => uint256)) private _allowances;\\n address public vaultAddress = address(0);\\n mapping(address => uint256) private _creditBalances;\\n uint256 private _rebasingCredits;\\n uint256 private _rebasingCreditsPerToken;\\n // Frozen address/credits are non rebasing (value is held in contracts which\\n // do not receive yield unless they explicitly opt in)\\n uint256 public nonRebasingSupply;\\n mapping(address => uint256) public nonRebasingCreditsPerToken;\\n mapping(address => RebaseOptions) public rebaseState;\\n mapping(address => uint256) public isUpgraded;\\n\\n uint256 private constant RESOLUTION_INCREASE = 1e9;\\n\\n function initialize(\\n string calldata _nameArg,\\n string calldata _symbolArg,\\n address _vaultAddress,\\n uint256 _initialCreditsPerToken\\n ) external onlyGovernor initializer {\\n InitializableERC20Detailed._initialize(_nameArg, _symbolArg, 18);\\n _rebasingCreditsPerToken = _initialCreditsPerToken;\\n vaultAddress = _vaultAddress;\\n }\\n\\n /**\\n * @dev Verifies that the caller is the Vault contract\\n */\\n modifier onlyVault() {\\n require(vaultAddress == msg.sender, \\\"Caller is not the Vault\\\");\\n _;\\n }\\n\\n /**\\n * @return The total supply of OUSD.\\n */\\n function totalSupply() public view override returns (uint256) {\\n return _totalSupply;\\n }\\n\\n /**\\n * @return Low resolution rebasingCreditsPerToken\\n */\\n function rebasingCreditsPerToken() public view returns (uint256) {\\n return _rebasingCreditsPerToken / RESOLUTION_INCREASE;\\n }\\n\\n /**\\n * @return Low resolution total number of rebasing credits\\n */\\n function rebasingCredits() public view returns (uint256) {\\n return _rebasingCredits / RESOLUTION_INCREASE;\\n }\\n\\n /**\\n * @return High resolution rebasingCreditsPerToken\\n */\\n function rebasingCreditsPerTokenHighres() public view returns (uint256) {\\n return _rebasingCreditsPerToken;\\n }\\n\\n /**\\n * @return High resolution total number of rebasing credits\\n */\\n function rebasingCreditsHighres() public view returns (uint256) {\\n return _rebasingCredits;\\n }\\n\\n /**\\n * @dev Gets the balance of the specified address.\\n * @param _account Address to query the balance of.\\n * @return A uint256 representing the amount of base units owned by the\\n * specified address.\\n */\\n function balanceOf(address _account)\\n public\\n view\\n override\\n returns (uint256)\\n {\\n if (_creditBalances[_account] == 0) return 0;\\n return\\n _creditBalances[_account].divPrecisely(_creditsPerToken(_account));\\n }\\n\\n /**\\n * @dev Gets the credits balance of the specified address.\\n * @dev Backwards compatible with old low res credits per token.\\n * @param _account The address to query the balance of.\\n * @return (uint256, uint256) Credit balance and credits per token of the\\n * address\\n */\\n function creditsBalanceOf(address _account)\\n public\\n view\\n returns (uint256, uint256)\\n {\\n uint256 cpt = _creditsPerToken(_account);\\n if (cpt == 1e27) {\\n // For a period before the resolution upgrade, we created all new\\n // contract accounts at high resolution. Since they are not changing\\n // as a result of this upgrade, we will return their true values\\n return (_creditBalances[_account], cpt);\\n } else {\\n return (\\n _creditBalances[_account] / RESOLUTION_INCREASE,\\n cpt / RESOLUTION_INCREASE\\n );\\n }\\n }\\n\\n /**\\n * @dev Gets the credits balance of the specified address.\\n * @param _account The address to query the balance of.\\n * @return (uint256, uint256, bool) Credit balance, credits per token of the\\n * address, and isUpgraded\\n */\\n function creditsBalanceOfHighres(address _account)\\n public\\n view\\n returns (\\n uint256,\\n uint256,\\n bool\\n )\\n {\\n return (\\n _creditBalances[_account],\\n _creditsPerToken(_account),\\n isUpgraded[_account] == 1\\n );\\n }\\n\\n /**\\n * @dev Transfer tokens to a specified address.\\n * @param _to the address to transfer to.\\n * @param _value the amount to be transferred.\\n * @return true on success.\\n */\\n function transfer(address _to, uint256 _value)\\n public\\n override\\n returns (bool)\\n {\\n require(_to != address(0), \\\"Transfer to zero address\\\");\\n require(\\n _value <= balanceOf(msg.sender),\\n \\\"Transfer greater than balance\\\"\\n );\\n\\n _executeTransfer(msg.sender, _to, _value);\\n\\n emit Transfer(msg.sender, _to, _value);\\n\\n return true;\\n }\\n\\n /**\\n * @dev Transfer tokens from one address to another.\\n * @param _from The address you want to send tokens from.\\n * @param _to The address you want to transfer to.\\n * @param _value The amount of tokens to be transferred.\\n */\\n function transferFrom(\\n address _from,\\n address _to,\\n uint256 _value\\n ) public override returns (bool) {\\n require(_to != address(0), \\\"Transfer to zero address\\\");\\n require(_value <= balanceOf(_from), \\\"Transfer greater than balance\\\");\\n\\n _allowances[_from][msg.sender] = _allowances[_from][msg.sender].sub(\\n _value\\n );\\n\\n _executeTransfer(_from, _to, _value);\\n\\n emit Transfer(_from, _to, _value);\\n\\n return true;\\n }\\n\\n /**\\n * @dev Update the count of non rebasing credits in response to a transfer\\n * @param _from The address you want to send tokens from.\\n * @param _to The address you want to transfer to.\\n * @param _value Amount of OUSD to transfer\\n */\\n function _executeTransfer(\\n address _from,\\n address _to,\\n uint256 _value\\n ) internal {\\n bool isNonRebasingTo = _isNonRebasingAccount(_to);\\n bool isNonRebasingFrom = _isNonRebasingAccount(_from);\\n\\n // Credits deducted and credited might be different due to the\\n // differing creditsPerToken used by each account\\n uint256 creditsCredited = _value.mulTruncate(_creditsPerToken(_to));\\n uint256 creditsDeducted = _value.mulTruncate(_creditsPerToken(_from));\\n\\n _creditBalances[_from] = _creditBalances[_from].sub(\\n creditsDeducted,\\n \\\"Transfer amount exceeds balance\\\"\\n );\\n _creditBalances[_to] = _creditBalances[_to].add(creditsCredited);\\n\\n if (isNonRebasingTo && !isNonRebasingFrom) {\\n // Transfer to non-rebasing account from rebasing account, credits\\n // are removed from the non rebasing tally\\n nonRebasingSupply = nonRebasingSupply.add(_value);\\n // Update rebasingCredits by subtracting the deducted amount\\n _rebasingCredits = _rebasingCredits.sub(creditsDeducted);\\n } else if (!isNonRebasingTo && isNonRebasingFrom) {\\n // Transfer to rebasing account from non-rebasing account\\n // Decreasing non-rebasing credits by the amount that was sent\\n nonRebasingSupply = nonRebasingSupply.sub(_value);\\n // Update rebasingCredits by adding the credited amount\\n _rebasingCredits = _rebasingCredits.add(creditsCredited);\\n }\\n }\\n\\n /**\\n * @dev Function to check the amount of tokens that _owner has allowed to\\n * `_spender`.\\n * @param _owner The address which owns the funds.\\n * @param _spender The address which will spend the funds.\\n * @return The number of tokens still available for the _spender.\\n */\\n function allowance(address _owner, address _spender)\\n public\\n view\\n override\\n returns (uint256)\\n {\\n return _allowances[_owner][_spender];\\n }\\n\\n /**\\n * @dev Approve the passed address to spend the specified amount of tokens\\n * on behalf of msg.sender. This method is included for ERC20\\n * compatibility. `increaseAllowance` and `decreaseAllowance` should be\\n * used instead.\\n *\\n * Changing an allowance with this method brings the risk that someone\\n * may transfer both the old and the new allowance - if they are both\\n * greater than zero - if a transfer transaction is mined before the\\n * later approve() call is mined.\\n * @param _spender The address which will spend the funds.\\n * @param _value The amount of tokens to be spent.\\n */\\n function approve(address _spender, uint256 _value)\\n public\\n override\\n returns (bool)\\n {\\n _allowances[msg.sender][_spender] = _value;\\n emit Approval(msg.sender, _spender, _value);\\n return true;\\n }\\n\\n /**\\n * @dev Increase the amount of tokens that an owner has allowed to\\n * `_spender`.\\n * This method should be used instead of approve() to avoid the double\\n * approval vulnerability described above.\\n * @param _spender The address which will spend the funds.\\n * @param _addedValue The amount of tokens to increase the allowance by.\\n */\\n function increaseAllowance(address _spender, uint256 _addedValue)\\n public\\n returns (bool)\\n {\\n _allowances[msg.sender][_spender] = _allowances[msg.sender][_spender]\\n .add(_addedValue);\\n emit Approval(msg.sender, _spender, _allowances[msg.sender][_spender]);\\n return true;\\n }\\n\\n /**\\n * @dev Decrease the amount of tokens that an owner has allowed to\\n `_spender`.\\n * @param _spender The address which will spend the funds.\\n * @param _subtractedValue The amount of tokens to decrease the allowance\\n * by.\\n */\\n function decreaseAllowance(address _spender, uint256 _subtractedValue)\\n public\\n returns (bool)\\n {\\n uint256 oldValue = _allowances[msg.sender][_spender];\\n if (_subtractedValue >= oldValue) {\\n _allowances[msg.sender][_spender] = 0;\\n } else {\\n _allowances[msg.sender][_spender] = oldValue.sub(_subtractedValue);\\n }\\n emit Approval(msg.sender, _spender, _allowances[msg.sender][_spender]);\\n return true;\\n }\\n\\n /**\\n * @dev Mints new tokens, increasing totalSupply.\\n */\\n function mint(address _account, uint256 _amount) external onlyVault {\\n _mint(_account, _amount);\\n }\\n\\n /**\\n * @dev Creates `_amount` tokens and assigns them to `_account`, increasing\\n * the total supply.\\n *\\n * Emits a {Transfer} event with `from` set to the zero address.\\n *\\n * Requirements\\n *\\n * - `to` cannot be the zero address.\\n */\\n function _mint(address _account, uint256 _amount) internal nonReentrant {\\n require(_account != address(0), \\\"Mint to the zero address\\\");\\n\\n bool isNonRebasingAccount = _isNonRebasingAccount(_account);\\n\\n uint256 creditAmount = _amount.mulTruncate(_creditsPerToken(_account));\\n _creditBalances[_account] = _creditBalances[_account].add(creditAmount);\\n\\n // If the account is non rebasing and doesn't have a set creditsPerToken\\n // then set it i.e. this is a mint from a fresh contract\\n if (isNonRebasingAccount) {\\n nonRebasingSupply = nonRebasingSupply.add(_amount);\\n } else {\\n _rebasingCredits = _rebasingCredits.add(creditAmount);\\n }\\n\\n _totalSupply = _totalSupply.add(_amount);\\n\\n require(_totalSupply < MAX_SUPPLY, \\\"Max supply\\\");\\n\\n emit Transfer(address(0), _account, _amount);\\n }\\n\\n /**\\n * @dev Burns tokens, decreasing totalSupply.\\n */\\n function burn(address account, uint256 amount) external onlyVault {\\n _burn(account, amount);\\n }\\n\\n /**\\n * @dev Destroys `_amount` tokens from `_account`, reducing the\\n * total supply.\\n *\\n * Emits a {Transfer} event with `to` set to the zero address.\\n *\\n * Requirements\\n *\\n * - `_account` cannot be the zero address.\\n * - `_account` must have at least `_amount` tokens.\\n */\\n function _burn(address _account, uint256 _amount) internal nonReentrant {\\n require(_account != address(0), \\\"Burn from the zero address\\\");\\n if (_amount == 0) {\\n return;\\n }\\n\\n bool isNonRebasingAccount = _isNonRebasingAccount(_account);\\n uint256 creditAmount = _amount.mulTruncate(_creditsPerToken(_account));\\n uint256 currentCredits = _creditBalances[_account];\\n\\n // Remove the credits, burning rounding errors\\n if (\\n currentCredits == creditAmount || currentCredits - 1 == creditAmount\\n ) {\\n // Handle dust from rounding\\n _creditBalances[_account] = 0;\\n } else if (currentCredits > creditAmount) {\\n _creditBalances[_account] = _creditBalances[_account].sub(\\n creditAmount\\n );\\n } else {\\n revert(\\\"Remove exceeds balance\\\");\\n }\\n\\n // Remove from the credit tallies and non-rebasing supply\\n if (isNonRebasingAccount) {\\n nonRebasingSupply = nonRebasingSupply.sub(_amount);\\n } else {\\n _rebasingCredits = _rebasingCredits.sub(creditAmount);\\n }\\n\\n _totalSupply = _totalSupply.sub(_amount);\\n\\n emit Transfer(_account, address(0), _amount);\\n }\\n\\n /**\\n * @dev Get the credits per token for an account. Returns a fixed amount\\n * if the account is non-rebasing.\\n * @param _account Address of the account.\\n */\\n function _creditsPerToken(address _account)\\n internal\\n view\\n returns (uint256)\\n {\\n if (nonRebasingCreditsPerToken[_account] != 0) {\\n return nonRebasingCreditsPerToken[_account];\\n } else {\\n return _rebasingCreditsPerToken;\\n }\\n }\\n\\n /**\\n * @dev Is an account using rebasing accounting or non-rebasing accounting?\\n * Also, ensure contracts are non-rebasing if they have not opted in.\\n * @param _account Address of the account.\\n */\\n function _isNonRebasingAccount(address _account) internal returns (bool) {\\n bool isContract = Address.isContract(_account);\\n if (isContract && rebaseState[_account] == RebaseOptions.NotSet) {\\n _ensureRebasingMigration(_account);\\n }\\n return nonRebasingCreditsPerToken[_account] > 0;\\n }\\n\\n /**\\n * @dev Ensures internal account for rebasing and non-rebasing credits and\\n * supply is updated following deployment of frozen yield change.\\n */\\n function _ensureRebasingMigration(address _account) internal {\\n if (nonRebasingCreditsPerToken[_account] == 0) {\\n emit AccountRebasingDisabled(_account);\\n if (_creditBalances[_account] == 0) {\\n // Since there is no existing balance, we can directly set to\\n // high resolution, and do not have to do any other bookkeeping\\n nonRebasingCreditsPerToken[_account] = 1e27;\\n } else {\\n // Migrate an existing account:\\n\\n // Set fixed credits per token for this account\\n nonRebasingCreditsPerToken[_account] = _rebasingCreditsPerToken;\\n // Update non rebasing supply\\n nonRebasingSupply = nonRebasingSupply.add(balanceOf(_account));\\n // Update credit tallies\\n _rebasingCredits = _rebasingCredits.sub(\\n _creditBalances[_account]\\n );\\n }\\n }\\n }\\n\\n /**\\n * @notice Enable rebasing for an account.\\n * @dev Add a contract address to the non-rebasing exception list. The\\n * address's balance will be part of rebases and the account will be exposed\\n * to upside and downside.\\n * @param _account Address of the account.\\n */\\n function governanceRebaseOptIn(address _account)\\n public\\n nonReentrant\\n onlyGovernor\\n {\\n _rebaseOptIn(_account);\\n }\\n\\n /**\\n * @dev Add a contract address to the non-rebasing exception list. The\\n * address's balance will be part of rebases and the account will be exposed\\n * to upside and downside.\\n */\\n function rebaseOptIn() public nonReentrant {\\n _rebaseOptIn(msg.sender);\\n }\\n\\n function _rebaseOptIn(address _account) internal {\\n require(_isNonRebasingAccount(_account), \\\"Account has not opted out\\\");\\n\\n // Convert balance into the same amount at the current exchange rate\\n uint256 newCreditBalance = _creditBalances[_account]\\n .mul(_rebasingCreditsPerToken)\\n .div(_creditsPerToken(_account));\\n\\n // Decreasing non rebasing supply\\n nonRebasingSupply = nonRebasingSupply.sub(balanceOf(_account));\\n\\n _creditBalances[_account] = newCreditBalance;\\n\\n // Increase rebasing credits, totalSupply remains unchanged so no\\n // adjustment necessary\\n _rebasingCredits = _rebasingCredits.add(_creditBalances[_account]);\\n\\n rebaseState[_account] = RebaseOptions.OptIn;\\n\\n // Delete any fixed credits per token\\n delete nonRebasingCreditsPerToken[_account];\\n emit AccountRebasingEnabled(_account);\\n }\\n\\n /**\\n * @dev Explicitly mark that an address is non-rebasing.\\n */\\n function rebaseOptOut() public nonReentrant {\\n require(!_isNonRebasingAccount(msg.sender), \\\"Account has not opted in\\\");\\n\\n // Increase non rebasing supply\\n nonRebasingSupply = nonRebasingSupply.add(balanceOf(msg.sender));\\n // Set fixed credits per token\\n nonRebasingCreditsPerToken[msg.sender] = _rebasingCreditsPerToken;\\n\\n // Decrease rebasing credits, total supply remains unchanged so no\\n // adjustment necessary\\n _rebasingCredits = _rebasingCredits.sub(_creditBalances[msg.sender]);\\n\\n // Mark explicitly opted out of rebasing\\n rebaseState[msg.sender] = RebaseOptions.OptOut;\\n emit AccountRebasingDisabled(msg.sender);\\n }\\n\\n /**\\n * @dev Modify the supply without minting new tokens. This uses a change in\\n * the exchange rate between \\\"credits\\\" and OUSD tokens to change balances.\\n * @param _newTotalSupply New total supply of OUSD.\\n */\\n function changeSupply(uint256 _newTotalSupply)\\n external\\n onlyVault\\n nonReentrant\\n {\\n require(_totalSupply > 0, \\\"Cannot increase 0 supply\\\");\\n\\n if (_totalSupply == _newTotalSupply) {\\n emit TotalSupplyUpdatedHighres(\\n _totalSupply,\\n _rebasingCredits,\\n _rebasingCreditsPerToken\\n );\\n return;\\n }\\n\\n _totalSupply = _newTotalSupply > MAX_SUPPLY\\n ? MAX_SUPPLY\\n : _newTotalSupply;\\n\\n _rebasingCreditsPerToken = _rebasingCredits.divPrecisely(\\n _totalSupply.sub(nonRebasingSupply)\\n );\\n\\n require(_rebasingCreditsPerToken > 0, \\\"Invalid change in supply\\\");\\n\\n _totalSupply = _rebasingCredits\\n .divPrecisely(_rebasingCreditsPerToken)\\n .add(nonRebasingSupply);\\n\\n emit TotalSupplyUpdatedHighres(\\n _totalSupply,\\n _rebasingCredits,\\n _rebasingCreditsPerToken\\n );\\n }\\n}\\n\",\"keccak256\":\"0x2dc66b1ba02716d64eb47dd9117fda62650d8b57669e6c351437e0ad29ad5f19\",\"license\":\"MIT\"},\"contracts/utils/Helpers.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { IBasicToken } from \\\"../interfaces/IBasicToken.sol\\\";\\n\\nlibrary Helpers {\\n /**\\n * @notice Fetch the `symbol()` from an ERC20 token\\n * @dev Grabs the `symbol()` from a contract\\n * @param _token Address of the ERC20 token\\n * @return string Symbol of the ERC20 token\\n */\\n function getSymbol(address _token) internal view returns (string memory) {\\n string memory symbol = IBasicToken(_token).symbol();\\n return symbol;\\n }\\n\\n /**\\n * @notice Fetch the `decimals()` from an ERC20 token\\n * @dev Grabs the `decimals()` from a contract and fails if\\n * the decimal value does not live within a certain range\\n * @param _token Address of the ERC20 token\\n * @return uint256 Decimals of the ERC20 token\\n */\\n function getDecimals(address _token) internal view returns (uint256) {\\n uint256 decimals = IBasicToken(_token).decimals();\\n require(\\n decimals >= 4 && decimals <= 18,\\n \\\"Token must have sufficient decimal places\\\"\\n );\\n\\n return decimals;\\n }\\n}\\n\",\"keccak256\":\"0x108b7a69e0140da0072ca18f90a03a3340574400f81aa6076cd2cccdf13699c2\",\"license\":\"MIT\"},\"contracts/utils/Initializable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Base contract any contracts that need to initialize state after deployment.\\n * @author Origin Protocol Inc\\n */\\nabstract contract Initializable {\\n /**\\n * @dev Indicates that the contract has been initialized.\\n */\\n bool private initialized;\\n\\n /**\\n * @dev Indicates that the contract is in the process of being initialized.\\n */\\n bool private initializing;\\n\\n /**\\n * @dev Modifier to protect an initializer function from being invoked twice.\\n */\\n modifier initializer() {\\n require(\\n initializing || !initialized,\\n \\\"Initializable: contract is already initialized\\\"\\n );\\n\\n bool isTopLevelCall = !initializing;\\n if (isTopLevelCall) {\\n initializing = true;\\n initialized = true;\\n }\\n\\n _;\\n\\n if (isTopLevelCall) {\\n initializing = false;\\n }\\n }\\n\\n uint256[50] private ______gap;\\n}\\n\",\"keccak256\":\"0xaadbcc138114afed4af4f353c2ced2916e6ee14be91434789187f192caf0d786\",\"license\":\"MIT\"},\"contracts/utils/InitializableERC20Detailed.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { IERC20 } from \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @dev Optional functions from the ERC20 standard.\\n * Converted from openzeppelin/contracts/token/ERC20/ERC20Detailed.sol\\n * @author Origin Protocol Inc\\n */\\nabstract contract InitializableERC20Detailed is IERC20 {\\n // Storage gap to skip storage from prior to OUSD reset\\n uint256[100] private _____gap;\\n\\n string private _name;\\n string private _symbol;\\n uint8 private _decimals;\\n\\n /**\\n * @dev Sets the values for `name`, `symbol`, and `decimals`. All three of\\n * these values are immutable: they can only be set once during\\n * construction.\\n * @notice To avoid variable shadowing appended `Arg` after arguments name.\\n */\\n function _initialize(\\n string memory nameArg,\\n string memory symbolArg,\\n uint8 decimalsArg\\n ) internal {\\n _name = nameArg;\\n _symbol = symbolArg;\\n _decimals = decimalsArg;\\n }\\n\\n /**\\n * @notice Returns the name of the token.\\n */\\n function name() public view returns (string memory) {\\n return _name;\\n }\\n\\n /**\\n * @notice Returns the symbol of the token, usually a shorter version of the\\n * name.\\n */\\n function symbol() public view returns (string memory) {\\n return _symbol;\\n }\\n\\n /**\\n * @notice Returns the number of decimals used to get its user representation.\\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\\n * be displayed to a user as `5,05` (`505 / 10 ** 2`).\\n *\\n * Tokens usually opt for a value of 18, imitating the relationship between\\n * Ether and Wei.\\n *\\n * NOTE: This information is only used for _display_ purposes: it in\\n * no way affects any of the arithmetic of the contract, including\\n * {IERC20-balanceOf} and {IERC20-transfer}.\\n */\\n function decimals() public view returns (uint8) {\\n return _decimals;\\n }\\n}\\n\",\"keccak256\":\"0xe35ac2d813a30d845a3b52bba72588d7e936c2b3f3373d15568c14db46aeed60\",\"license\":\"MIT\"},\"contracts/utils/StableMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { SafeMath } from \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\n\\n// Based on StableMath from Stability Labs Pty. Ltd.\\n// https://github.com/mstable/mStable-contracts/blob/master/contracts/shared/StableMath.sol\\n\\nlibrary StableMath {\\n using SafeMath for uint256;\\n\\n /**\\n * @dev Scaling unit for use in specific calculations,\\n * where 1 * 10**18, or 1e18 represents a unit '1'\\n */\\n uint256 private constant FULL_SCALE = 1e18;\\n\\n /***************************************\\n Helpers\\n ****************************************/\\n\\n /**\\n * @dev Adjust the scale of an integer\\n * @param to Decimals to scale to\\n * @param from Decimals to scale from\\n */\\n function scaleBy(\\n uint256 x,\\n uint256 to,\\n uint256 from\\n ) internal pure returns (uint256) {\\n if (to > from) {\\n x = x.mul(10**(to - from));\\n } else if (to < from) {\\n // slither-disable-next-line divide-before-multiply\\n x = x.div(10**(from - to));\\n }\\n return x;\\n }\\n\\n /***************************************\\n Precise Arithmetic\\n ****************************************/\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the full scale\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit\\n */\\n function mulTruncate(uint256 x, uint256 y) internal pure returns (uint256) {\\n return mulTruncateScale(x, y, FULL_SCALE);\\n }\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the given scale. For example,\\n * when calculating 90% of 10e18, (10e18 * 9e17) / 1e18 = (9e36) / 1e18 = 9e18\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @param scale Scale unit\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit\\n */\\n function mulTruncateScale(\\n uint256 x,\\n uint256 y,\\n uint256 scale\\n ) internal pure returns (uint256) {\\n // e.g. assume scale = fullScale\\n // z = 10e18 * 9e17 = 9e36\\n uint256 z = x.mul(y);\\n // return 9e36 / 1e18 = 9e18\\n return z.div(scale);\\n }\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the full scale, rounding up the result\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit, rounded up to the closest base unit.\\n */\\n function mulTruncateCeil(uint256 x, uint256 y)\\n internal\\n pure\\n returns (uint256)\\n {\\n // e.g. 8e17 * 17268172638 = 138145381104e17\\n uint256 scaled = x.mul(y);\\n // e.g. 138145381104e17 + 9.99...e17 = 138145381113.99...e17\\n uint256 ceil = scaled.add(FULL_SCALE.sub(1));\\n // e.g. 13814538111.399...e18 / 1e18 = 13814538111\\n return ceil.div(FULL_SCALE);\\n }\\n\\n /**\\n * @dev Precisely divides two units, by first scaling the left hand operand. Useful\\n * for finding percentage weightings, i.e. 8e18/10e18 = 80% (or 8e17)\\n * @param x Left hand input to division\\n * @param y Right hand input to division\\n * @return Result after multiplying the left operand by the scale, and\\n * executing the division on the right hand input.\\n */\\n function divPrecisely(uint256 x, uint256 y)\\n internal\\n pure\\n returns (uint256)\\n {\\n // e.g. 8e18 * 1e18 = 8e36\\n uint256 z = x.mul(FULL_SCALE);\\n // e.g. 8e36 / 10e18 = 8e17\\n return z.div(y);\\n }\\n}\\n\",\"keccak256\":\"0x1eb49f6f79045d9e0a8e1dced8e01d9e559e5fac554dcbb53e43140b601b04e7\",\"license\":\"MIT\"},\"contracts/vault/OETHVaultAdmin.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { VaultAdmin } from \\\"./VaultAdmin.sol\\\";\\n\\n/**\\n * @title OETH VaultAdmin Contract\\n * @author Origin Protocol Inc\\n */\\ncontract OETHVaultAdmin is VaultAdmin {\\n\\n}\\n\",\"keccak256\":\"0xe6aa33bc5fb6bf1e3b7d3f8f3786ee4991f9a511cdcb858da867f7c81eb6a46a\",\"license\":\"MIT\"},\"contracts/vault/VaultAdmin.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OToken VaultAdmin contract\\n * @notice The VaultAdmin contract makes configuration and admin calls on the vault.\\n * @author Origin Protocol Inc\\n */\\n\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\nimport { IOracle } from \\\"../interfaces/IOracle.sol\\\";\\nimport { ISwapper } from \\\"../interfaces/ISwapper.sol\\\";\\nimport { IVault } from \\\"../interfaces/IVault.sol\\\";\\nimport { StableMath } from \\\"../utils/StableMath.sol\\\";\\n\\nimport \\\"./VaultStorage.sol\\\";\\n\\ncontract VaultAdmin is VaultStorage {\\n using SafeERC20 for IERC20;\\n using StableMath for uint256;\\n\\n /**\\n * @dev Verifies that the caller is the Governor or Strategist.\\n */\\n modifier onlyGovernorOrStrategist() {\\n require(\\n msg.sender == strategistAddr || isGovernor(),\\n \\\"Caller is not the Strategist or Governor\\\"\\n );\\n _;\\n }\\n\\n /***************************************\\n Configuration\\n ****************************************/\\n\\n /**\\n * @notice Set address of price provider.\\n * @param _priceProvider Address of price provider\\n */\\n function setPriceProvider(address _priceProvider) external onlyGovernor {\\n priceProvider = _priceProvider;\\n emit PriceProviderUpdated(_priceProvider);\\n }\\n\\n /**\\n * @notice Set a fee in basis points to be charged for a redeem.\\n * @param _redeemFeeBps Basis point fee to be charged\\n */\\n function setRedeemFeeBps(uint256 _redeemFeeBps) external onlyGovernor {\\n require(_redeemFeeBps <= 1000, \\\"Redeem fee should not be over 10%\\\");\\n redeemFeeBps = _redeemFeeBps;\\n emit RedeemFeeUpdated(_redeemFeeBps);\\n }\\n\\n /**\\n * @notice Set a buffer of assets to keep in the Vault to handle most\\n * redemptions without needing to spend gas unwinding assets from a Strategy.\\n * @param _vaultBuffer Percentage using 18 decimals. 100% = 1e18.\\n */\\n function setVaultBuffer(uint256 _vaultBuffer)\\n external\\n onlyGovernorOrStrategist\\n {\\n require(_vaultBuffer <= 1e18, \\\"Invalid value\\\");\\n vaultBuffer = _vaultBuffer;\\n emit VaultBufferUpdated(_vaultBuffer);\\n }\\n\\n /**\\n * @notice Sets the minimum amount of OTokens in a mint to trigger an\\n * automatic allocation of funds afterwords.\\n * @param _threshold OToken amount with 18 fixed decimals.\\n */\\n function setAutoAllocateThreshold(uint256 _threshold)\\n external\\n onlyGovernor\\n {\\n autoAllocateThreshold = _threshold;\\n emit AllocateThresholdUpdated(_threshold);\\n }\\n\\n /**\\n * @notice Set a minimum amount of OTokens in a mint or redeem that triggers a\\n * rebase\\n * @param _threshold OToken amount with 18 fixed decimals.\\n */\\n function setRebaseThreshold(uint256 _threshold) external onlyGovernor {\\n rebaseThreshold = _threshold;\\n emit RebaseThresholdUpdated(_threshold);\\n }\\n\\n /**\\n * @notice Set address of Strategist\\n * @param _address Address of Strategist\\n */\\n function setStrategistAddr(address _address) external onlyGovernor {\\n strategistAddr = _address;\\n emit StrategistUpdated(_address);\\n }\\n\\n /**\\n * @notice Set the default Strategy for an asset, i.e. the one which the asset\\n will be automatically allocated to and withdrawn from\\n * @param _asset Address of the asset\\n * @param _strategy Address of the Strategy\\n */\\n function setAssetDefaultStrategy(address _asset, address _strategy)\\n external\\n onlyGovernorOrStrategist\\n {\\n emit AssetDefaultStrategyUpdated(_asset, _strategy);\\n // If its a zero address being passed for the strategy we are removing\\n // the default strategy\\n if (_strategy != address(0)) {\\n // Make sure the strategy meets some criteria\\n require(strategies[_strategy].isSupported, \\\"Strategy not approved\\\");\\n IStrategy strategy = IStrategy(_strategy);\\n require(assets[_asset].isSupported, \\\"Asset is not supported\\\");\\n require(\\n strategy.supportsAsset(_asset),\\n \\\"Asset not supported by Strategy\\\"\\n );\\n }\\n assetDefaultStrategies[_asset] = _strategy;\\n }\\n\\n /**\\n * @notice Set maximum amount of OTokens that can at any point be minted and deployed\\n * to strategy (used only by ConvexOUSDMetaStrategy for now).\\n * @param _threshold OToken amount with 18 fixed decimals.\\n */\\n function setNetOusdMintForStrategyThreshold(uint256 _threshold)\\n external\\n onlyGovernor\\n {\\n /**\\n * Because `netOusdMintedForStrategy` check in vault core works both ways\\n * (positive and negative) the actual impact of the amount of OToken minted\\n * could be double the threshold. E.g.:\\n * - contract has threshold set to 100\\n * - state of netOusdMinted is -90\\n * - in effect it can mint 190 OToken and still be within limits\\n *\\n * We are somewhat mitigating this behaviour by resetting the netOusdMinted\\n * counter whenever new threshold is set. So it can only move one threshold\\n * amount in each direction. This also enables us to reduce the threshold\\n * amount and not have problems with current netOusdMinted being near\\n * limits on either side.\\n */\\n netOusdMintedForStrategy = 0;\\n netOusdMintForStrategyThreshold = _threshold;\\n emit NetOusdMintForStrategyThresholdChanged(_threshold);\\n }\\n\\n /***************************************\\n Swaps\\n ****************************************/\\n\\n /**\\n * @notice Strategist swaps collateral assets sitting in the vault.\\n * @param _fromAsset The token address of the asset being sold by the vault.\\n * @param _toAsset The token address of the asset being purchased by the vault.\\n * @param _fromAssetAmount The amount of assets being sold by the vault.\\n * @param _minToAssetAmount The minimum amount of assets to be purchased.\\n * @param _data implementation specific data. eg 1Inch swap data\\n * @return toAssetAmount The amount of toAssets that was received from the swap\\n */\\n function swapCollateral(\\n address _fromAsset,\\n address _toAsset,\\n uint256 _fromAssetAmount,\\n uint256 _minToAssetAmount,\\n bytes calldata _data\\n )\\n external\\n nonReentrant\\n onlyGovernorOrStrategist\\n returns (uint256 toAssetAmount)\\n {\\n // Check fromAsset and toAsset are valid\\n Asset memory fromAssetConfig = assets[address(_fromAsset)];\\n Asset memory toAssetConfig = assets[_toAsset];\\n require(fromAssetConfig.isSupported, \\\"From asset is not supported\\\");\\n require(toAssetConfig.isSupported, \\\"To asset is not supported\\\");\\n\\n // Load swap config into memory to avoid separate SLOADs\\n SwapConfig memory config = swapConfig;\\n\\n // Scope a new block to remove toAssetBalBefore from the scope of swapCollateral.\\n // This avoids a stack too deep error.\\n {\\n uint256 toAssetBalBefore = IERC20(_toAsset).balanceOf(\\n address(this)\\n );\\n\\n // Transfer from assets to the swapper contract\\n IERC20(_fromAsset).safeTransfer(config.swapper, _fromAssetAmount);\\n\\n // Call to the Swapper contract to do the actual swap\\n // The -1 is required for stETH which sometimes transfers 1 wei less than what was specified.\\n // slither-disable-next-line unused-return\\n ISwapper(config.swapper).swap(\\n _fromAsset,\\n _toAsset,\\n _fromAssetAmount - 1,\\n _minToAssetAmount,\\n _data\\n );\\n\\n // Compute the change in asset balance held by the Vault\\n toAssetAmount =\\n IERC20(_toAsset).balanceOf(address(this)) -\\n toAssetBalBefore;\\n }\\n\\n // Check the to assets returned is above slippage amount specified by the strategist\\n require(\\n toAssetAmount >= _minToAssetAmount,\\n \\\"Strategist slippage limit\\\"\\n );\\n\\n // Scope a new block to remove minOracleToAssetAmount from the scope of swapCollateral.\\n // This avoids a stack too deep error.\\n {\\n // Check the slippage against the Oracle in case the strategist made a mistake or has become malicious.\\n // to asset amount = from asset amount * from asset price / to asset price\\n uint256 minOracleToAssetAmount = (_fromAssetAmount *\\n (1e4 - fromAssetConfig.allowedOracleSlippageBps) *\\n IOracle(priceProvider).price(_fromAsset)) /\\n (IOracle(priceProvider).price(_toAsset) *\\n (1e4 + toAssetConfig.allowedOracleSlippageBps));\\n\\n // Scale both sides up to 18 decimals to compare\\n require(\\n toAssetAmount.scaleBy(18, toAssetConfig.decimals) >=\\n minOracleToAssetAmount.scaleBy(\\n 18,\\n fromAssetConfig.decimals\\n ),\\n \\\"Oracle slippage limit exceeded\\\"\\n );\\n }\\n\\n // Check the vault's total value hasn't gone below the OToken total supply\\n // by more than the allowed percentage.\\n require(\\n IVault(address(this)).totalValue() >=\\n (oUSD.totalSupply() * ((1e4 - config.allowedUndervalueBps))) /\\n 1e4,\\n \\\"Allowed value < supply\\\"\\n );\\n\\n emit Swapped(_fromAsset, _toAsset, _fromAssetAmount, toAssetAmount);\\n }\\n\\n /***************************************\\n Swap Config\\n ****************************************/\\n\\n /**\\n * @notice Set the contract the performs swaps of collateral assets.\\n * @param _swapperAddr Address of the Swapper contract that implements the ISwapper interface.\\n */\\n function setSwapper(address _swapperAddr) external onlyGovernor {\\n swapConfig.swapper = _swapperAddr;\\n emit SwapperChanged(_swapperAddr);\\n }\\n\\n /// @notice Contract that swaps the vault's collateral assets\\n function swapper() external view returns (address swapper_) {\\n swapper_ = swapConfig.swapper;\\n }\\n\\n /**\\n * @notice Set max allowed percentage the vault total value can drop below the OToken total supply in basis points\\n * when executing collateral swaps.\\n * @param _basis Percentage in basis points. eg 100 == 1%\\n */\\n function setSwapAllowedUndervalue(uint16 _basis) external onlyGovernor {\\n require(_basis < 10001, \\\"Invalid basis points\\\");\\n swapConfig.allowedUndervalueBps = _basis;\\n emit SwapAllowedUndervalueChanged(_basis);\\n }\\n\\n /**\\n * @notice Max allowed percentage the vault total value can drop below the OToken total supply in basis points\\n * when executing a collateral swap.\\n * For example 100 == 1%\\n * @return value Percentage in basis points.\\n */\\n function allowedSwapUndervalue() external view returns (uint256 value) {\\n value = swapConfig.allowedUndervalueBps;\\n }\\n\\n /**\\n * @notice Set the allowed slippage from the Oracle price for collateral asset swaps.\\n * @param _asset Address of the asset token.\\n * @param _allowedOracleSlippageBps allowed slippage from Oracle in basis points. eg 20 = 0.2%. Max 10%.\\n */\\n function setOracleSlippage(address _asset, uint16 _allowedOracleSlippageBps)\\n external\\n onlyGovernor\\n {\\n require(assets[_asset].isSupported, \\\"Asset not supported\\\");\\n require(_allowedOracleSlippageBps < 1000, \\\"Slippage too high\\\");\\n\\n assets[_asset].allowedOracleSlippageBps = _allowedOracleSlippageBps;\\n\\n emit SwapSlippageChanged(_asset, _allowedOracleSlippageBps);\\n }\\n\\n /***************************************\\n Asset Config\\n ****************************************/\\n\\n /**\\n * @notice Add a supported asset to the contract, i.e. one that can be\\n * to mint OTokens.\\n * @param _asset Address of asset\\n */\\n function supportAsset(address _asset, uint8 _unitConversion)\\n external\\n onlyGovernor\\n {\\n require(!assets[_asset].isSupported, \\\"Asset already supported\\\");\\n\\n assets[_asset] = Asset({\\n isSupported: true,\\n unitConversion: UnitConversion(_unitConversion),\\n decimals: 0, // will be overridden in _cacheDecimals\\n allowedOracleSlippageBps: 0 // 0% by default\\n });\\n\\n _cacheDecimals(_asset);\\n allAssets.push(_asset);\\n\\n // Verify that our oracle supports the asset\\n // slither-disable-next-line unused-return\\n IOracle(priceProvider).price(_asset);\\n\\n emit AssetSupported(_asset);\\n }\\n\\n /**\\n * @notice Cache decimals on OracleRouter for a particular asset. This action\\n * is required before that asset's price can be accessed.\\n * @param _asset Address of asset token\\n */\\n function cacheDecimals(address _asset) external onlyGovernor {\\n _cacheDecimals(_asset);\\n }\\n\\n /***************************************\\n Strategy Config\\n ****************************************/\\n\\n /**\\n * @notice Add a strategy to the Vault.\\n * @param _addr Address of the strategy to add\\n */\\n function approveStrategy(address _addr) external onlyGovernor {\\n require(!strategies[_addr].isSupported, \\\"Strategy already approved\\\");\\n strategies[_addr] = Strategy({ isSupported: true, _deprecated: 0 });\\n allStrategies.push(_addr);\\n emit StrategyApproved(_addr);\\n }\\n\\n /**\\n * @notice Remove a strategy from the Vault.\\n * @param _addr Address of the strategy to remove\\n */\\n\\n function removeStrategy(address _addr) external onlyGovernor {\\n require(strategies[_addr].isSupported, \\\"Strategy not approved\\\");\\n\\n uint256 assetCount = allAssets.length;\\n for (uint256 i = 0; i < assetCount; ++i) {\\n require(\\n assetDefaultStrategies[allAssets[i]] != _addr,\\n \\\"Strategy is default for an asset\\\"\\n );\\n }\\n\\n // Initialize strategyIndex with out of bounds result so function will\\n // revert if no valid index found\\n uint256 stratCount = allStrategies.length;\\n uint256 strategyIndex = stratCount;\\n for (uint256 i = 0; i < stratCount; ++i) {\\n if (allStrategies[i] == _addr) {\\n strategyIndex = i;\\n break;\\n }\\n }\\n\\n if (strategyIndex < stratCount) {\\n allStrategies[strategyIndex] = allStrategies[stratCount - 1];\\n allStrategies.pop();\\n\\n // Mark the strategy as not supported\\n strategies[_addr].isSupported = false;\\n\\n // Withdraw all assets\\n IStrategy strategy = IStrategy(_addr);\\n strategy.withdrawAll();\\n\\n emit StrategyRemoved(_addr);\\n }\\n }\\n\\n /***************************************\\n Strategies\\n ****************************************/\\n\\n /**\\n * @notice Deposit multiple assets from the vault into the strategy.\\n * @param _strategyToAddress Address of the Strategy to deposit assets into.\\n * @param _assets Array of asset address that will be deposited into the strategy.\\n * @param _amounts Array of amounts of each corresponding asset to deposit.\\n */\\n function depositToStrategy(\\n address _strategyToAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) external onlyGovernorOrStrategist nonReentrant {\\n _depositToStrategy(_strategyToAddress, _assets, _amounts);\\n }\\n\\n function _depositToStrategy(\\n address _strategyToAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) internal {\\n require(\\n strategies[_strategyToAddress].isSupported,\\n \\\"Invalid to Strategy\\\"\\n );\\n require(_assets.length == _amounts.length, \\\"Parameter length mismatch\\\");\\n\\n uint256 assetCount = _assets.length;\\n for (uint256 i = 0; i < assetCount; ++i) {\\n address assetAddr = _assets[i];\\n require(\\n IStrategy(_strategyToAddress).supportsAsset(assetAddr),\\n \\\"Asset unsupported\\\"\\n );\\n // Send required amount of funds to the strategy\\n IERC20(assetAddr).safeTransfer(_strategyToAddress, _amounts[i]);\\n }\\n\\n // Deposit all the funds that have been sent to the strategy\\n IStrategy(_strategyToAddress).depositAll();\\n }\\n\\n /**\\n * @notice Withdraw multiple assets from the strategy to the vault.\\n * @param _strategyFromAddress Address of the Strategy to withdraw assets from.\\n * @param _assets Array of asset address that will be withdrawn from the strategy.\\n * @param _amounts Array of amounts of each corresponding asset to withdraw.\\n */\\n function withdrawFromStrategy(\\n address _strategyFromAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) external onlyGovernorOrStrategist nonReentrant {\\n _withdrawFromStrategy(\\n address(this),\\n _strategyFromAddress,\\n _assets,\\n _amounts\\n );\\n }\\n\\n /**\\n * @param _recipient can either be a strategy or the Vault\\n */\\n function _withdrawFromStrategy(\\n address _recipient,\\n address _strategyFromAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) internal {\\n require(\\n strategies[_strategyFromAddress].isSupported,\\n \\\"Invalid from Strategy\\\"\\n );\\n require(_assets.length == _amounts.length, \\\"Parameter length mismatch\\\");\\n\\n uint256 assetCount = _assets.length;\\n for (uint256 i = 0; i < assetCount; ++i) {\\n // Withdraw from Strategy to the recipient\\n IStrategy(_strategyFromAddress).withdraw(\\n _recipient,\\n _assets[i],\\n _amounts[i]\\n );\\n }\\n }\\n\\n /**\\n * @notice Sets the maximum allowable difference between\\n * total supply and backing assets' value.\\n */\\n function setMaxSupplyDiff(uint256 _maxSupplyDiff) external onlyGovernor {\\n maxSupplyDiff = _maxSupplyDiff;\\n emit MaxSupplyDiffChanged(_maxSupplyDiff);\\n }\\n\\n /**\\n * @notice Sets the trusteeAddress that can receive a portion of yield.\\n * Setting to the zero address disables this feature.\\n */\\n function setTrusteeAddress(address _address) external onlyGovernor {\\n trusteeAddress = _address;\\n emit TrusteeAddressChanged(_address);\\n }\\n\\n /**\\n * @notice Sets the TrusteeFeeBps to the percentage of yield that should be\\n * received in basis points.\\n */\\n function setTrusteeFeeBps(uint256 _basis) external onlyGovernor {\\n require(_basis <= 5000, \\\"basis cannot exceed 50%\\\");\\n trusteeFeeBps = _basis;\\n emit TrusteeFeeBpsChanged(_basis);\\n }\\n\\n /**\\n * @notice Set OToken Metapool strategy\\n * @param _ousdMetaStrategy Address of OToken metapool strategy\\n */\\n function setOusdMetaStrategy(address _ousdMetaStrategy)\\n external\\n onlyGovernor\\n {\\n ousdMetaStrategy = _ousdMetaStrategy;\\n emit OusdMetaStrategyUpdated(_ousdMetaStrategy);\\n }\\n\\n /***************************************\\n Pause\\n ****************************************/\\n\\n /**\\n * @notice Set the deposit paused flag to true to prevent rebasing.\\n */\\n function pauseRebase() external onlyGovernorOrStrategist {\\n rebasePaused = true;\\n emit RebasePaused();\\n }\\n\\n /**\\n * @notice Set the deposit paused flag to true to allow rebasing.\\n */\\n function unpauseRebase() external onlyGovernorOrStrategist {\\n rebasePaused = false;\\n emit RebaseUnpaused();\\n }\\n\\n /**\\n * @notice Set the deposit paused flag to true to prevent capital movement.\\n */\\n function pauseCapital() external onlyGovernorOrStrategist {\\n capitalPaused = true;\\n emit CapitalPaused();\\n }\\n\\n /**\\n * @notice Set the deposit paused flag to false to enable capital movement.\\n */\\n function unpauseCapital() external onlyGovernorOrStrategist {\\n capitalPaused = false;\\n emit CapitalUnpaused();\\n }\\n\\n /***************************************\\n Utils\\n ****************************************/\\n\\n /**\\n * @notice Transfer token to governor. Intended for recovering tokens stuck in\\n * contract, i.e. mistaken sends.\\n * @param _asset Address for the asset\\n * @param _amount Amount of the asset to transfer\\n */\\n function transferToken(address _asset, uint256 _amount)\\n external\\n onlyGovernor\\n {\\n require(!assets[_asset].isSupported, \\\"Only unsupported assets\\\");\\n IERC20(_asset).safeTransfer(governor(), _amount);\\n }\\n\\n /***************************************\\n Strategies Admin\\n ****************************************/\\n\\n /**\\n * @notice Withdraws all assets from the strategy and sends assets to the Vault.\\n * @param _strategyAddr Strategy address.\\n */\\n function withdrawAllFromStrategy(address _strategyAddr)\\n external\\n onlyGovernorOrStrategist\\n {\\n require(\\n strategies[_strategyAddr].isSupported,\\n \\\"Strategy is not supported\\\"\\n );\\n IStrategy strategy = IStrategy(_strategyAddr);\\n strategy.withdrawAll();\\n }\\n\\n /**\\n * @notice Withdraws all assets from all the strategies and sends assets to the Vault.\\n */\\n function withdrawAllFromStrategies() external onlyGovernorOrStrategist {\\n uint256 stratCount = allStrategies.length;\\n for (uint256 i = 0; i < stratCount; ++i) {\\n IStrategy(allStrategies[i]).withdrawAll();\\n }\\n }\\n\\n /***************************************\\n Utils\\n ****************************************/\\n\\n function _cacheDecimals(address token) internal {\\n Asset storage tokenAsset = assets[token];\\n if (tokenAsset.decimals != 0) {\\n return;\\n }\\n uint8 decimals = IBasicToken(token).decimals();\\n require(decimals >= 6 && decimals <= 18, \\\"Unexpected precision\\\");\\n tokenAsset.decimals = decimals;\\n }\\n}\\n\",\"keccak256\":\"0x597e6301fdcc77fe239b1d8dd7fea534f61b4031016d6035a6027b7dad9412d6\",\"license\":\"MIT\"},\"contracts/vault/VaultStorage.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OToken VaultStorage contract\\n * @notice The VaultStorage contract defines the storage for the Vault contracts\\n * @author Origin Protocol Inc\\n */\\n\\nimport { IERC20 } from \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport { Address } from \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport { IStrategy } from \\\"../interfaces/IStrategy.sol\\\";\\nimport { Governable } from \\\"../governance/Governable.sol\\\";\\nimport { OUSD } from \\\"../token/OUSD.sol\\\";\\nimport { Initializable } from \\\"../utils/Initializable.sol\\\";\\nimport \\\"../utils/Helpers.sol\\\";\\n\\ncontract VaultStorage is Initializable, Governable {\\n using SafeERC20 for IERC20;\\n\\n event AssetSupported(address _asset);\\n event AssetDefaultStrategyUpdated(address _asset, address _strategy);\\n event AssetAllocated(address _asset, address _strategy, uint256 _amount);\\n event StrategyApproved(address _addr);\\n event StrategyRemoved(address _addr);\\n event Mint(address _addr, uint256 _value);\\n event Redeem(address _addr, uint256 _value);\\n event CapitalPaused();\\n event CapitalUnpaused();\\n event RebasePaused();\\n event RebaseUnpaused();\\n event VaultBufferUpdated(uint256 _vaultBuffer);\\n event OusdMetaStrategyUpdated(address _ousdMetaStrategy);\\n event RedeemFeeUpdated(uint256 _redeemFeeBps);\\n event PriceProviderUpdated(address _priceProvider);\\n event AllocateThresholdUpdated(uint256 _threshold);\\n event RebaseThresholdUpdated(uint256 _threshold);\\n event StrategistUpdated(address _address);\\n event MaxSupplyDiffChanged(uint256 maxSupplyDiff);\\n event YieldDistribution(address _to, uint256 _yield, uint256 _fee);\\n event TrusteeFeeBpsChanged(uint256 _basis);\\n event TrusteeAddressChanged(address _address);\\n event NetOusdMintForStrategyThresholdChanged(uint256 _threshold);\\n event SwapperChanged(address _address);\\n event SwapAllowedUndervalueChanged(uint256 _basis);\\n event SwapSlippageChanged(address _asset, uint256 _basis);\\n event Swapped(\\n address indexed _fromAsset,\\n address indexed _toAsset,\\n uint256 _fromAssetAmount,\\n uint256 _toAssetAmount\\n );\\n\\n // Assets supported by the Vault, i.e. Stablecoins\\n enum UnitConversion {\\n DECIMALS,\\n GETEXCHANGERATE\\n }\\n // Changed to fit into a single storage slot so the decimals needs to be recached\\n struct Asset {\\n // Note: OETHVaultCore doesn't use `isSupported` when minting,\\n // redeeming or checking balance of assets.\\n bool isSupported;\\n UnitConversion unitConversion;\\n uint8 decimals;\\n // Max allowed slippage from the Oracle price when swapping collateral assets in basis points.\\n // For example 40 == 0.4% slippage\\n uint16 allowedOracleSlippageBps;\\n }\\n\\n /// @dev mapping of supported vault assets to their configuration\\n // slither-disable-next-line uninitialized-state\\n mapping(address => Asset) internal assets;\\n /// @dev list of all assets supported by the vault.\\n // slither-disable-next-line uninitialized-state\\n address[] internal allAssets;\\n\\n // Strategies approved for use by the Vault\\n struct Strategy {\\n bool isSupported;\\n uint256 _deprecated; // Deprecated storage slot\\n }\\n /// @dev mapping of strategy contracts to their configiration\\n mapping(address => Strategy) internal strategies;\\n /// @dev list of all vault strategies\\n address[] internal allStrategies;\\n\\n /// @notice Address of the Oracle price provider contract\\n // slither-disable-next-line uninitialized-state\\n address public priceProvider;\\n /// @notice pause rebasing if true\\n bool public rebasePaused = false;\\n /// @notice pause operations that change the OToken supply.\\n /// eg mint, redeem, allocate, mint/burn for strategy\\n bool public capitalPaused = true;\\n /// @notice Redemption fee in basis points. eg 50 = 0.5%\\n uint256 public redeemFeeBps;\\n /// @notice Percentage of assets to keep in Vault to handle (most) withdrawals. 100% = 1e18.\\n uint256 public vaultBuffer;\\n /// @notice OToken mints over this amount automatically allocate funds. 18 decimals.\\n uint256 public autoAllocateThreshold;\\n /// @notice OToken mints over this amount automatically rebase. 18 decimals.\\n uint256 public rebaseThreshold;\\n\\n /// @dev Address of the OToken token. eg OUSD or OETH.\\n // slither-disable-next-line uninitialized-state\\n OUSD internal oUSD;\\n\\n //keccak256(\\\"OUSD.vault.governor.admin.impl\\\");\\n bytes32 constant adminImplPosition =\\n 0xa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd9;\\n\\n // Address of the contract responsible for post rebase syncs with AMMs\\n address private _deprecated_rebaseHooksAddr = address(0);\\n\\n // Deprecated: Address of Uniswap\\n // slither-disable-next-line constable-states\\n address private _deprecated_uniswapAddr = address(0);\\n\\n /// @notice Address of the Strategist\\n address public strategistAddr = address(0);\\n\\n /// @notice Mapping of asset address to the Strategy that they should automatically\\n // be allocated to\\n // slither-disable-next-line uninitialized-state\\n mapping(address => address) public assetDefaultStrategies;\\n\\n /// @notice Max difference between total supply and total value of assets. 18 decimals.\\n // slither-disable-next-line uninitialized-state\\n uint256 public maxSupplyDiff;\\n\\n /// @notice Trustee contract that can collect a percentage of yield\\n address public trusteeAddress;\\n\\n /// @notice Amount of yield collected in basis points. eg 2000 = 20%\\n uint256 public trusteeFeeBps;\\n\\n /// @dev Deprecated: Tokens that should be swapped for stablecoins\\n address[] private _deprecated_swapTokens;\\n\\n uint256 constant MINT_MINIMUM_UNIT_PRICE = 0.998e18;\\n\\n /// @notice Metapool strategy that is allowed to mint/burn OTokens without changing collateral\\n address public ousdMetaStrategy = address(0);\\n\\n /// @notice How much OTokens are currently minted by the strategy\\n int256 public netOusdMintedForStrategy = 0;\\n\\n /// @notice How much net total OTokens are allowed to be minted by all strategies\\n uint256 public netOusdMintForStrategyThreshold = 0;\\n\\n uint256 constant MIN_UNIT_PRICE_DRIFT = 0.7e18;\\n uint256 constant MAX_UNIT_PRICE_DRIFT = 1.3e18;\\n\\n /// @notice Collateral swap configuration.\\n /// @dev is packed into a single storage slot to save gas.\\n struct SwapConfig {\\n // Contract that swaps the vault's collateral assets\\n address swapper;\\n // Max allowed percentage the total value can drop below the total supply in basis points.\\n // For example 100 == 1%\\n uint16 allowedUndervalueBps;\\n }\\n SwapConfig internal swapConfig = SwapConfig(address(0), 0);\\n\\n // For future use\\n uint256[50] private __gap;\\n\\n /**\\n * @notice set the implementation for the admin, this needs to be in a base class else we cannot set it\\n * @param newImpl address of the implementation\\n */\\n function setAdminImpl(address newImpl) external onlyGovernor {\\n require(\\n Address.isContract(newImpl),\\n \\\"new implementation is not a contract\\\"\\n );\\n bytes32 position = adminImplPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, newImpl)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xbcefeb5e2b88d99a54dbe6542dc25d0a68eeaf3adfe6e12fb70049cc024b1a79\",\"license\":\"MIT\"}},\"version\":1}", - "bytecode": "0x6037805461ffff60a01b1916600160a81b179055603d80546001600160a01b0319908116909155603e805482169055603f80548216905560458054909116905560006046819055604781905560c0604052608081905260a052604880546001600160b01b03191690553480156200007557600080fd5b506200008e33600080516020620037a983398151915255565b600080516020620037a9833981519152546040516001600160a01b03909116906000907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a36136c380620000e66000396000f3fe608060405234801561001057600080fd5b50600436106102f15760003560e01c80636c7561e81161019d578063b888879e116100e9578063d38bfff4116100a2578063e6cc54321161007c578063e6cc54321461061d578063e829cc1614610631578063eb03654b14610644578063fc0cfeee1461065757600080fd5b8063d38bfff4146105ee578063d58e3b3a14610601578063e45cc9f01461061457600080fd5b8063b888879e1461059d578063b890ebf6146105b0578063bc90106b146105c3578063c5f00841146105d6578063c7af3352146105de578063c9919112146105e657600080fd5b80638ec489a2116101565780639fa1826e116101305780639fa1826e14610545578063a403e4d51461054e578063ae69f3cb14610577578063b2c9336d1461058a57600080fd5b80638ec489a21461051757806394828ffd1461052a5780639c82f2a41461053257600080fd5b80636c7561e8146104b9578063773540b3146104cc5780637a2202f3146104df5780637b9a7096146104e8578063840c4c7a146104fb5780638e510b521461050e57600080fd5b8063372aa2241161025c57806352d38e5d11610215578063597c8910116101ef578063597c8910146104785780635d36b1901461048b578063636e6c4014610493578063663e64ce146104a657600080fd5b806352d38e5d1461043857806353ca9f2414610441578063570d8e1d1461046557600080fd5b8063372aa224146103d15780633b8ae397146103e45780633dbc911f146103f757806349c1d54d146103ff5780634bed3bc01461041257806350ba711c1461042557600080fd5b806318ce56bd116102ae57806318ce56bd146103755780631edfe3da14610388578063207134b0146103915780632b3297f91461039a5780632da845a8146103ab57806336b6d944146103be57600080fd5b806309f49bf5146102f657806309f6442c146103005780630acbda751461031c5780630c340a241461032f5780631072cbea1461034f578063175188e814610362575b600080fd5b6102fe61066a565b005b61030960385481565b6040519081526020015b60405180910390f35b6102fe61032a366004613292565b6106e3565b610337610795565b6040516001600160a01b039091168152602001610313565b6102fe61035d3660046131f4565b6107b2565b6102fe610370366004613055565b61085f565b604554610337906001600160a01b031681565b61030960395481565b61030960435481565b6048546001600160a01b0316610337565b6102fe6103b9366004613055565b610b60565b6102fe6103cc366004613055565b610bd2565b6102fe6103df366004613055565b610c02565b6102fe6103f2366004613055565b610c74565b6102fe610db1565b604254610337906001600160a01b031681565b604854600160a01b900461ffff16610309565b6103096104333660046130a3565b610e27565b610309603b5481565b60375461045590600160a01b900460ff1681565b6040519015158152602001610313565b603f54610337906001600160a01b031681565b6102fe610486366004613055565b611647565b6102fe611743565b6102fe6104a1366004613292565b6117e9565b6102fe6104b4366004613292565b611847565b6102fe6104c736600461321e565b6118a0565b6102fe6104da366004613055565b611b1e565b61030960475481565b6102fe6104f63660046131ca565b611b90565b6102fe610509366004613149565b611cc6565b61030960415481565b6102fe610525366004613292565b611d5f565b6102fe611e14565b6102fe610540366004613055565b611e84565b610309603a5481565b61033761055c366004613055565b6040602081905260009182529020546001600160a01b031681565b6102fe610585366004613149565b611ef6565b6102fe610598366004613292565b611f84565b603754610337906001600160a01b031681565b6102fe6105be366004613292565b611fdd565b6102fe6105d1366004613070565b612036565b6102fe612278565b6104556122ee565b6102fe61231f565b6102fe6105fc366004613055565b6123e9565b6102fe61060f366004613055565b61248d565b61030960465481565b60375461045590600160a81b900460ff1681565b6102fe61063f366004613277565b6124ff565b6102fe610652366004613292565b6125bf565b6102fe610665366004613055565b612674565b603f546001600160a01b031633148061068657506106866122ee565b6106ab5760405162461bcd60e51b81526004016106a2906133c3565b60405180910390fd5b6037805460ff60a01b191690556040517fbc044409505c95b6b851433df96e1beae715c909d8e7c1d6d7ab783300d4e3b990600090a1565b6106eb6122ee565b6107075760405162461bcd60e51b81526004016106a29061338c565b6113888111156107595760405162461bcd60e51b815260206004820152601760248201527f62617369732063616e6e6f74206578636565642035302500000000000000000060448201526064016106a2565b60438190556040518181527f56287a45051933ea374811b3d5d165033047be5572cac676f7c28b8be4f746c7906020015b60405180910390a150565b60006107ad60008051602061366e8339815191525490565b905090565b6107ba6122ee565b6107d65760405162461bcd60e51b81526004016106a29061338c565b6001600160a01b03821660009081526033602052604090205460ff161561083f5760405162461bcd60e51b815260206004820152601760248201527f4f6e6c7920756e737570706f727465642061737365747300000000000000000060448201526064016106a2565b61085b61084a610795565b6001600160a01b0384169083612716565b5050565b6108676122ee565b6108835760405162461bcd60e51b81526004016106a29061338c565b6001600160a01b03811660009081526035602052604090205460ff166108e35760405162461bcd60e51b815260206004820152601560248201527414dd1c985d1959de481b9bdd08185c1c1c9bdd9959605a1b60448201526064016106a2565b60345460005b8181101561099b57826001600160a01b0316604060006034848154811061091257610912613648565b60009182526020808320909101546001600160a01b03908116845290830193909352604090910190205416141561098b5760405162461bcd60e51b815260206004820181905260248201527f53747261746567792069732064656661756c7420666f7220616e20617373657460448201526064016106a2565b610994816135eb565b90506108e9565b506036548060005b828110156109fb57846001600160a01b0316603682815481106109c8576109c8613648565b6000918252602090912001546001600160a01b031614156109eb578091506109fb565b6109f4816135eb565b90506109a3565b5081811015610b5a576036610a116001846135a8565b81548110610a2157610a21613648565b600091825260209091200154603680546001600160a01b039092169183908110610a4d57610a4d613648565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506036805480610a8c57610a8c613632565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b03861680835260359091526040808320805460ff19169055805163429c145b60e11b81529051879363853828b6926004808201939182900301818387803b158015610b0357600080fd5b505af1158015610b17573d6000803e3d6000fd5b50506040516001600160a01b03881681527f09a1db4b80c32706328728508c941a6b954f31eb5affd32f236c1fd405f8fea49250602001905060405180910390a1505b50505050565b610b686122ee565b610b845760405162461bcd60e51b81526004016106a29061338c565b604280546001600160a01b0319166001600160a01b0383169081179091556040519081527f1e4af5ac389e8cde1bdaa6830881b6c987c62a45cfb3b33d27d805cde3b577509060200161078a565b610bda6122ee565b610bf65760405162461bcd60e51b81526004016106a29061338c565b610bff8161276d565b50565b610c0a6122ee565b610c265760405162461bcd60e51b81526004016106a29061338c565b603780546001600160a01b0319166001600160a01b0383169081179091556040519081527fb266add5f3044b17d27db796af992cecbe413921b4e8aaaee03c719e16b9806a9060200161078a565b610c7c6122ee565b610c985760405162461bcd60e51b81526004016106a29061338c565b6001600160a01b03811660009081526035602052604090205460ff1615610d015760405162461bcd60e51b815260206004820152601960248201527f537472617465677920616c726561647920617070726f7665640000000000000060448201526064016106a2565b6040805180820182526001808252600060208084018281526001600160a01b038716808452603583528684209551865460ff19169015151786559051948401949094556036805493840181559091527f4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b890910180546001600160a01b0319168317905591519081527f960dd94cbb79169f09a4e445d58b895df2d9bffa5b31055d0932d801724a20d1910161078a565b603f546001600160a01b0316331480610dcd5750610dcd6122ee565b610de95760405162461bcd60e51b81526004016106a2906133c3565b6037805460ff60a81b1916600160a81b1790556040517f71f0e5b62f846a22e0b4d159e516e62fa9c2b8eb570be15f83e67d98a2ee51e090600090a1565b7f53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45358054600091906002811415610e6f5760405162461bcd60e51b81526004016106a29061340b565b60028255603f546001600160a01b0316331480610e8f5750610e8f6122ee565b610eab5760405162461bcd60e51b81526004016106a2906133c3565b6001600160a01b0389166000908152603360209081526040808320815160808101909252805460ff808216151584529293919291840191610100909104166001811115610efa57610efa61361c565b6001811115610f0b57610f0b61361c565b8152905462010000810460ff908116602080850191909152630100000090920461ffff166040938401526001600160a01b038d1660009081526033835283812084516080810190955280548084161515865295965090949092840191610100909104166001811115610f7f57610f7f61361c565b6001811115610f9057610f9061361c565b8152905462010000810460ff1660208301526301000000900461ffff1660409091015282519091506110045760405162461bcd60e51b815260206004820152601b60248201527f46726f6d206173736574206973206e6f7420737570706f72746564000000000060448201526064016106a2565b80516110525760405162461bcd60e51b815260206004820152601960248201527f546f206173736574206973206e6f7420737570706f727465640000000000000060448201526064016106a2565b6040805180820182526048546001600160a01b038082168352600160a01b90910461ffff16602083015291516370a0823160e01b81523060048201529091600091908d16906370a082319060240160206040518083038186803b1580156110b857600080fd5b505afa1580156110cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110f091906132ab565b825190915061110a906001600160a01b038f16908d612716565b81600001516001600160a01b0316632506c0188e8e60018f61112c91906135a8565b8e8e8e6040518763ffffffff1660e01b8152600401611150969594939291906132fd565b602060405180830381600087803b15801561116a57600080fd5b505af115801561117e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111a291906132ab565b506040516370a0823160e01b815230600482015281906001600160a01b038e16906370a082319060240160206040518083038186803b1580156111e457600080fd5b505afa1580156111f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061121c91906132ab565b61122691906135a8565b965050888610156112795760405162461bcd60e51b815260206004820152601960248201527f5374726174656769737420736c697070616765206c696d69740000000000000060448201526064016106a2565b6000826060015161271061128d9190613433565b6037546040516315d5220f60e31b81526001600160a01b038f8116600483015261ffff93909316929091169063aea910789060240160206040518083038186803b1580156112da57600080fd5b505afa1580156112ee573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061131291906132ab565b61131c9190613566565b603760009054906101000a90046001600160a01b03166001600160a01b031663aea910788f6040518263ffffffff1660e01b815260040161136c91906001600160a01b0391909116815260200190565b60206040518083038186803b15801561138457600080fd5b505afa158015611398573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113bc91906132ab565b60608601516113cd90612710613585565b6113db9061ffff168e613566565b6113e59190613566565b6113ef9190613459565b905061140e6012856040015160ff16836128839092919063ffffffff16565b604084015161142490899060129060ff16612883565b10156114725760405162461bcd60e51b815260206004820152601e60248201527f4f7261636c6520736c697070616765206c696d6974206578636565646564000060448201526064016106a2565b5061271081602001516127106114889190613585565b61ffff16603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156114da57600080fd5b505afa1580156114ee573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061151291906132ab565b61151c9190613566565b6115269190613459565b306001600160a01b031663d4c3eea06040518163ffffffff1660e01b815260040160206040518083038186803b15801561155f57600080fd5b505afa158015611573573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061159791906132ab565b10156115de5760405162461bcd60e51b8152602060048201526016602482015275416c6c6f7765642076616c7565203c20737570706c7960501b60448201526064016106a2565b8a6001600160a01b03168c6001600160a01b03167fa078c4190abe07940190effc1846be0ccf03ad6007bc9e93f9697d0b460befbb8c8960405161162c929190918252602082015260400190565b60405180910390a35050506001825550509695505050505050565b603f546001600160a01b031633148061166357506116636122ee565b61167f5760405162461bcd60e51b81526004016106a2906133c3565b6001600160a01b03811660009081526035602052604090205460ff166116e75760405162461bcd60e51b815260206004820152601960248201527f5374726174656779206973206e6f7420737570706f727465640000000000000060448201526064016106a2565b6000819050806001600160a01b031663853828b66040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561172757600080fd5b505af115801561173b573d6000803e3d6000fd5b505050505050565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b0316146117de5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b60648201526084016106a2565b6117e7336128e7565b565b6117f16122ee565b61180d5760405162461bcd60e51b81526004016106a29061338c565b600060465560478190556040518181527fc29d6fedbc6bdf267a08166c2b976fbd72aca5d6a769528616f8b9224c8f197f9060200161078a565b61184f6122ee565b61186b5760405162461bcd60e51b81526004016106a29061338c565b60418190556040518181527f95201f9c21f26877223b1ff4073936a6484c35495649e60e55730497aeb60d939060200161078a565b6118a86122ee565b6118c45760405162461bcd60e51b81526004016106a29061338c565b6001600160a01b03821660009081526033602052604090205460ff161561192d5760405162461bcd60e51b815260206004820152601760248201527f417373657420616c726561647920737570706f7274656400000000000000000060448201526064016106a2565b60405180608001604052806001151581526020018260ff1660018111156119565761195661361c565b60018111156119675761196761361c565b81526000602080830182905260409283018290526001600160a01b0386168252603381529190208251815490151560ff19821681178355928401519192839161ff001990911661ffff19909116176101008360018111156119ca576119ca61361c565b02179055506040820151815460609093015161ffff1663010000000264ffff0000001960ff90921662010000029190911664ffffff00001990931692909217919091179055611a188261276d565b603480546001810182556000919091527f46bddb1178e94d7f2892ff5f366840eb658911794f2c3a44c450aa2c505186c10180546001600160a01b0319166001600160a01b038481169182179092556037546040516315d5220f60e31b815260048101929092529091169063aea910789060240160206040518083038186803b158015611aa457600080fd5b505afa158015611ab8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611adc91906132ab565b506040516001600160a01b03831681527f4f1ac48525e50059cc1cc6e0e1940ece0dd653a4db4841538d6aef036be2fb7b906020015b60405180910390a15050565b611b266122ee565b611b425760405162461bcd60e51b81526004016106a29061338c565b603f80546001600160a01b0319166001600160a01b0383169081179091556040519081527f869e0abd13cc3a975de7b93be3df1cb2255c802b1cead85963cc79d99f131bee9060200161078a565b611b986122ee565b611bb45760405162461bcd60e51b81526004016106a29061338c565b6001600160a01b03821660009081526033602052604090205460ff16611c125760405162461bcd60e51b8152602060048201526013602482015272105cdcd95d081b9bdd081cdd5c1c1bdc9d1959606a1b60448201526064016106a2565b6103e88161ffff1610611c5b5760405162461bcd60e51b81526020600482015260116024820152700a6d8d2e0e0c2ceca40e8dede40d0d2ced607b1b60448201526064016106a2565b6001600160a01b038216600081815260336020908152604091829020805464ffff0000001916630100000061ffff8716908102919091179091558251938452908301527f8d22e9d2cbe8bb65a3c4412bd8970743864512a1a0e004e8d00fb96277b78b949101611b12565b603f546001600160a01b0316331480611ce25750611ce26122ee565b611cfe5760405162461bcd60e51b81526004016106a2906133c3565b7f53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac453580546002811415611d425760405162461bcd60e51b81526004016106a29061340b565b60028255611d5387878787876129a8565b50600190555050505050565b603f546001600160a01b0316331480611d7b5750611d7b6122ee565b611d975760405162461bcd60e51b81526004016106a2906133c3565b670de0b6b3a7640000811115611ddf5760405162461bcd60e51b815260206004820152600d60248201526c496e76616c69642076616c756560981b60448201526064016106a2565b60398190556040518181527f41ecb23a0e7865b25f38c268b7c3012220d822929e9edff07326e89d5bb822b59060200161078a565b603f546001600160a01b0316331480611e305750611e306122ee565b611e4c5760405162461bcd60e51b81526004016106a2906133c3565b6037805460ff60a81b191690556040517f891ebab18da80ebeeea06b1b1cede098329c4c008906a98370c2ac7a80b571cb90600090a1565b611e8c6122ee565b611ea85760405162461bcd60e51b81526004016106a29061338c565b604880546001600160a01b0319166001600160a01b0383169081179091556040519081527f7d7719313229e558c5a3893cad2eb86a86a049156d1d9ebd5c63a8eedefd1c039060200161078a565b603f546001600160a01b0316331480611f125750611f126122ee565b611f2e5760405162461bcd60e51b81526004016106a2906133c3565b7f53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac453580546002811415611f725760405162461bcd60e51b81526004016106a29061340b565b60028255611d53308888888888612be6565b611f8c6122ee565b611fa85760405162461bcd60e51b81526004016106a29061338c565b603a8190556040518181527f2ec5fb5a3d2703edc461252d92ccd2799c3c74f01d97212b20388207fa17ae459060200161078a565b611fe56122ee565b6120015760405162461bcd60e51b81526004016106a29061338c565b603b8190556040518181527f39367850377ac04920a9a670f2180e7a94d83b15ad302e59875ec58fd10bd37d9060200161078a565b603f546001600160a01b031633148061205257506120526122ee565b61206e5760405162461bcd60e51b81526004016106a2906133c3565b604080516001600160a01b038085168252831660208201527fba58ce12801c949fa65f41c46ed108671c219baf945fa48d21026cea99ff252a910160405180910390a16001600160a01b0381161561224a576001600160a01b03811660009081526035602052604090205460ff166121205760405162461bcd60e51b815260206004820152601560248201527414dd1c985d1959de481b9bdd08185c1c1c9bdd9959605a1b60448201526064016106a2565b6001600160a01b038216600090815260336020526040902054819060ff166121835760405162461bcd60e51b8152602060048201526016602482015275105cdcd95d081a5cc81b9bdd081cdd5c1c1bdc9d195960521b60448201526064016106a2565b60405163551c457b60e11b81526001600160a01b03848116600483015282169063aa388af69060240160206040518083038186803b1580156121c457600080fd5b505afa1580156121d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121fc9190613255565b6122485760405162461bcd60e51b815260206004820152601f60248201527f4173736574206e6f7420737570706f727465642062792053747261746567790060448201526064016106a2565b505b6001600160a01b03918216600090815260406020819052902080546001600160a01b03191691909216179055565b603f546001600160a01b031633148061229457506122946122ee565b6122b05760405162461bcd60e51b81526004016106a2906133c3565b6037805460ff60a01b1916600160a01b1790556040517f8cff26a5985614b3d30629cc4ab83824bf115aec971b718d8f2f99562032e97290600090a1565b600061230660008051602061366e8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b603f546001600160a01b031633148061233b575061233b6122ee565b6123575760405162461bcd60e51b81526004016106a2906133c3565b60365460005b8181101561085b576036818154811061237857612378613648565b60009182526020822001546040805163429c145b60e11b815290516001600160a01b039092169263853828b69260048084019382900301818387803b1580156123c057600080fd5b505af11580156123d4573d6000803e3d6000fd5b50505050806123e2906135eb565b905061235d565b6123f16122ee565b61240d5760405162461bcd60e51b81526004016106a29061338c565b612435817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b031661245560008051602061366e8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b6124956122ee565b6124b15760405162461bcd60e51b81526004016106a29061338c565b604580546001600160a01b0319166001600160a01b0383169081179091556040519081527fa12850fb726e0b2b7b3c9a9342031e1268a8148d0eb06b4bea8613204ffcd2b89060200161078a565b6125076122ee565b6125235760405162461bcd60e51b81526004016106a29061338c565b6127118161ffff161061256f5760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420626173697320706f696e747360601b60448201526064016106a2565b6048805461ffff60a01b1916600160a01b61ffff8416908102919091179091556040519081527ff12c00256bee2b6facb111a88a9b1cff86e79132939b44f1353212d6f74695579060200161078a565b6125c76122ee565b6125e35760405162461bcd60e51b81526004016106a29061338c565b6103e881111561263f5760405162461bcd60e51b815260206004820152602160248201527f52656465656d206665652073686f756c64206e6f74206265206f7665722031306044820152602560f81b60648201526084016106a2565b60388190556040518181527fd6c7508d6658ccee36b7b7d7fd72e5cbaeefb40c64eff24e9ae7470e846304ee9060200161078a565b61267c6122ee565b6126985760405162461bcd60e51b81526004016106a29061338c565b803b6126f25760405162461bcd60e51b8152602060048201526024808201527f6e657720696d706c656d656e746174696f6e206973206e6f74206120636f6e746044820152631c9858dd60e21b60648201526084016106a2565b7fa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd955565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052612768908490612d70565b505050565b6001600160a01b0381166000908152603360205260409020805462010000900460ff1615612799575050565b6000826001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b1580156127d457600080fd5b505afa1580156127e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061280c91906132c4565b905060068160ff1610158015612826575060128160ff1611155b6128695760405162461bcd60e51b81526020600482015260146024820152732ab732bc3832b1ba32b210383932b1b4b9b4b7b760611b60448201526064016106a2565b815460ff909116620100000262ff00001990911617905550565b6000818311156128b3576128ac61289a83856135a8565b6128a590600a6134be565b8590612e42565b93506128dd565b818310156128dd576128da6128c884846135a8565b6128d390600a6134be565b8590612e57565b93505b50825b9392505050565b6001600160a01b03811661293d5760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f72206973206164647265737328302900000000000060448201526064016106a2565b806001600160a01b031661295d60008051602061366e8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a3610bff8160008051602061366e83398151915255565b6001600160a01b03851660009081526035602052604090205460ff16612a065760405162461bcd60e51b8152602060048201526013602482015272496e76616c696420746f20537472617465677960681b60448201526064016106a2565b828114612a515760405162461bcd60e51b81526020600482015260196024820152780a0c2e4c2dacae8cae440d8cadccee8d040dad2e6dac2e8c6d603b1b60448201526064016106a2565b8260005b81811015612b8a576000868683818110612a7157612a71613648565b9050602002016020810190612a869190613055565b60405163551c457b60e11b81526001600160a01b0380831660048301529192509089169063aa388af69060240160206040518083038186803b158015612acb57600080fd5b505afa158015612adf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b039190613255565b612b435760405162461bcd60e51b8152602060048201526011602482015270105cdcd95d081d5b9cdd5c1c1bdc9d1959607a1b60448201526064016106a2565b612b7988868685818110612b5957612b59613648565b90506020020135836001600160a01b03166127169092919063ffffffff16565b50612b83816135eb565b9050612a55565b50856001600160a01b031663de5f62686040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612bc657600080fd5b505af1158015612bda573d6000803e3d6000fd5b50505050505050505050565b6001600160a01b03851660009081526035602052604090205460ff16612c465760405162461bcd60e51b8152602060048201526015602482015274496e76616c69642066726f6d20537472617465677960581b60448201526064016106a2565b828114612c915760405162461bcd60e51b81526020600482015260196024820152780a0c2e4c2dacae8cae440d8cadccee8d040dad2e6dac2e8c6d603b1b60448201526064016106a2565b8260005b81811015612d6657866001600160a01b031663d9caed1289888885818110612cbf57612cbf613648565b9050602002016020810190612cd49190613055565b878786818110612ce657612ce6613648565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b158015612d3d57600080fd5b505af1158015612d51573d6000803e3d6000fd5b5050505080612d5f906135eb565b9050612c95565b5050505050505050565b6000612dc5826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316612e639092919063ffffffff16565b8051909150156127685780806020019051810190612de39190613255565b6127685760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016106a2565b6000612e4e8284613566565b90505b92915050565b6000612e4e8284613459565b6060612e728484600085612e7a565b949350505050565b606082471015612edb5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016106a2565b843b612f295760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016106a2565b600080866001600160a01b03168587604051612f4591906132e1565b60006040518083038185875af1925050503d8060008114612f82576040519150601f19603f3d011682016040523d82523d6000602084013e612f87565b606091505b5091509150612f97828286612fa2565b979650505050505050565b60608315612fb15750816128e0565b825115612fc15782518084602001fd5b8160405162461bcd60e51b81526004016106a29190613359565b80356001600160a01b0381168114612ff257600080fd5b919050565b60008083601f84011261300957600080fd5b50813567ffffffffffffffff81111561302157600080fd5b6020830191508360208260051b850101111561303c57600080fd5b9250929050565b803561ffff81168114612ff257600080fd5b60006020828403121561306757600080fd5b612e4e82612fdb565b6000806040838503121561308357600080fd5b61308c83612fdb565b915061309a60208401612fdb565b90509250929050565b60008060008060008060a087890312156130bc57600080fd5b6130c587612fdb565b95506130d360208801612fdb565b94506040870135935060608701359250608087013567ffffffffffffffff808211156130fe57600080fd5b818901915089601f83011261311257600080fd5b81358181111561312157600080fd5b8a602082850101111561313357600080fd5b6020830194508093505050509295509295509295565b60008060008060006060868803121561316157600080fd5b61316a86612fdb565b9450602086013567ffffffffffffffff8082111561318757600080fd5b61319389838a01612ff7565b909650945060408801359150808211156131ac57600080fd5b506131b988828901612ff7565b969995985093965092949392505050565b600080604083850312156131dd57600080fd5b6131e683612fdb565b915061309a60208401613043565b6000806040838503121561320757600080fd5b61321083612fdb565b946020939093013593505050565b6000806040838503121561323157600080fd5b61323a83612fdb565b9150602083013561324a8161365e565b809150509250929050565b60006020828403121561326757600080fd5b815180151581146128e057600080fd5b60006020828403121561328957600080fd5b612e4e82613043565b6000602082840312156132a457600080fd5b5035919050565b6000602082840312156132bd57600080fd5b5051919050565b6000602082840312156132d657600080fd5b81516128e08161365e565b600082516132f38184602087016135bf565b9190910192915050565b6001600160a01b03878116825286166020820152604081018590526060810184905260a06080820181905281018290526000828460c0840137600060c0848401015260c0601f19601f8501168301019050979650505050505050565b60208152600082518060208401526133788160408501602087016135bf565b601f01601f19169190910160400192915050565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60208082526028908201527f43616c6c6572206973206e6f74207468652053747261746567697374206f722060408201526723b7bb32b93737b960c11b606082015260800190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b600061ffff80831681851680830382111561345057613450613606565b01949350505050565b60008261347657634e487b7160e01b600052601260045260246000fd5b500490565b600181815b808511156134b657816000190482111561349c5761349c613606565b808516156134a957918102915b93841c9390800290613480565b509250929050565b6000612e4e83836000826134d457506001612e51565b816134e157506000612e51565b81600181146134f757600281146135015761351d565b6001915050612e51565b60ff84111561351257613512613606565b50506001821b612e51565b5060208310610133831016604e8410600b8410161715613540575081810a612e51565b61354a838361347b565b806000190482111561355e5761355e613606565b029392505050565b600081600019048311821515161561358057613580613606565b500290565b600061ffff838116908316818110156135a0576135a0613606565b039392505050565b6000828210156135ba576135ba613606565b500390565b60005b838110156135da5781810151838201526020016135c2565b83811115610b5a5750506000910152565b60006000198214156135ff576135ff613606565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b60ff81168114610bff57600080fdfe7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220856c9fec2e98e8d950cc7553495c5c13452851bc0b706e1a29005d23345bcb1364736f6c634300080700337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", - "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106102f15760003560e01c80636c7561e81161019d578063b888879e116100e9578063d38bfff4116100a2578063e6cc54321161007c578063e6cc54321461061d578063e829cc1614610631578063eb03654b14610644578063fc0cfeee1461065757600080fd5b8063d38bfff4146105ee578063d58e3b3a14610601578063e45cc9f01461061457600080fd5b8063b888879e1461059d578063b890ebf6146105b0578063bc90106b146105c3578063c5f00841146105d6578063c7af3352146105de578063c9919112146105e657600080fd5b80638ec489a2116101565780639fa1826e116101305780639fa1826e14610545578063a403e4d51461054e578063ae69f3cb14610577578063b2c9336d1461058a57600080fd5b80638ec489a21461051757806394828ffd1461052a5780639c82f2a41461053257600080fd5b80636c7561e8146104b9578063773540b3146104cc5780637a2202f3146104df5780637b9a7096146104e8578063840c4c7a146104fb5780638e510b521461050e57600080fd5b8063372aa2241161025c57806352d38e5d11610215578063597c8910116101ef578063597c8910146104785780635d36b1901461048b578063636e6c4014610493578063663e64ce146104a657600080fd5b806352d38e5d1461043857806353ca9f2414610441578063570d8e1d1461046557600080fd5b8063372aa224146103d15780633b8ae397146103e45780633dbc911f146103f757806349c1d54d146103ff5780634bed3bc01461041257806350ba711c1461042557600080fd5b806318ce56bd116102ae57806318ce56bd146103755780631edfe3da14610388578063207134b0146103915780632b3297f91461039a5780632da845a8146103ab57806336b6d944146103be57600080fd5b806309f49bf5146102f657806309f6442c146103005780630acbda751461031c5780630c340a241461032f5780631072cbea1461034f578063175188e814610362575b600080fd5b6102fe61066a565b005b61030960385481565b6040519081526020015b60405180910390f35b6102fe61032a366004613292565b6106e3565b610337610795565b6040516001600160a01b039091168152602001610313565b6102fe61035d3660046131f4565b6107b2565b6102fe610370366004613055565b61085f565b604554610337906001600160a01b031681565b61030960395481565b61030960435481565b6048546001600160a01b0316610337565b6102fe6103b9366004613055565b610b60565b6102fe6103cc366004613055565b610bd2565b6102fe6103df366004613055565b610c02565b6102fe6103f2366004613055565b610c74565b6102fe610db1565b604254610337906001600160a01b031681565b604854600160a01b900461ffff16610309565b6103096104333660046130a3565b610e27565b610309603b5481565b60375461045590600160a01b900460ff1681565b6040519015158152602001610313565b603f54610337906001600160a01b031681565b6102fe610486366004613055565b611647565b6102fe611743565b6102fe6104a1366004613292565b6117e9565b6102fe6104b4366004613292565b611847565b6102fe6104c736600461321e565b6118a0565b6102fe6104da366004613055565b611b1e565b61030960475481565b6102fe6104f63660046131ca565b611b90565b6102fe610509366004613149565b611cc6565b61030960415481565b6102fe610525366004613292565b611d5f565b6102fe611e14565b6102fe610540366004613055565b611e84565b610309603a5481565b61033761055c366004613055565b6040602081905260009182529020546001600160a01b031681565b6102fe610585366004613149565b611ef6565b6102fe610598366004613292565b611f84565b603754610337906001600160a01b031681565b6102fe6105be366004613292565b611fdd565b6102fe6105d1366004613070565b612036565b6102fe612278565b6104556122ee565b6102fe61231f565b6102fe6105fc366004613055565b6123e9565b6102fe61060f366004613055565b61248d565b61030960465481565b60375461045590600160a81b900460ff1681565b6102fe61063f366004613277565b6124ff565b6102fe610652366004613292565b6125bf565b6102fe610665366004613055565b612674565b603f546001600160a01b031633148061068657506106866122ee565b6106ab5760405162461bcd60e51b81526004016106a2906133c3565b60405180910390fd5b6037805460ff60a01b191690556040517fbc044409505c95b6b851433df96e1beae715c909d8e7c1d6d7ab783300d4e3b990600090a1565b6106eb6122ee565b6107075760405162461bcd60e51b81526004016106a29061338c565b6113888111156107595760405162461bcd60e51b815260206004820152601760248201527f62617369732063616e6e6f74206578636565642035302500000000000000000060448201526064016106a2565b60438190556040518181527f56287a45051933ea374811b3d5d165033047be5572cac676f7c28b8be4f746c7906020015b60405180910390a150565b60006107ad60008051602061366e8339815191525490565b905090565b6107ba6122ee565b6107d65760405162461bcd60e51b81526004016106a29061338c565b6001600160a01b03821660009081526033602052604090205460ff161561083f5760405162461bcd60e51b815260206004820152601760248201527f4f6e6c7920756e737570706f727465642061737365747300000000000000000060448201526064016106a2565b61085b61084a610795565b6001600160a01b0384169083612716565b5050565b6108676122ee565b6108835760405162461bcd60e51b81526004016106a29061338c565b6001600160a01b03811660009081526035602052604090205460ff166108e35760405162461bcd60e51b815260206004820152601560248201527414dd1c985d1959de481b9bdd08185c1c1c9bdd9959605a1b60448201526064016106a2565b60345460005b8181101561099b57826001600160a01b0316604060006034848154811061091257610912613648565b60009182526020808320909101546001600160a01b03908116845290830193909352604090910190205416141561098b5760405162461bcd60e51b815260206004820181905260248201527f53747261746567792069732064656661756c7420666f7220616e20617373657460448201526064016106a2565b610994816135eb565b90506108e9565b506036548060005b828110156109fb57846001600160a01b0316603682815481106109c8576109c8613648565b6000918252602090912001546001600160a01b031614156109eb578091506109fb565b6109f4816135eb565b90506109a3565b5081811015610b5a576036610a116001846135a8565b81548110610a2157610a21613648565b600091825260209091200154603680546001600160a01b039092169183908110610a4d57610a4d613648565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506036805480610a8c57610a8c613632565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b03861680835260359091526040808320805460ff19169055805163429c145b60e11b81529051879363853828b6926004808201939182900301818387803b158015610b0357600080fd5b505af1158015610b17573d6000803e3d6000fd5b50506040516001600160a01b03881681527f09a1db4b80c32706328728508c941a6b954f31eb5affd32f236c1fd405f8fea49250602001905060405180910390a1505b50505050565b610b686122ee565b610b845760405162461bcd60e51b81526004016106a29061338c565b604280546001600160a01b0319166001600160a01b0383169081179091556040519081527f1e4af5ac389e8cde1bdaa6830881b6c987c62a45cfb3b33d27d805cde3b577509060200161078a565b610bda6122ee565b610bf65760405162461bcd60e51b81526004016106a29061338c565b610bff8161276d565b50565b610c0a6122ee565b610c265760405162461bcd60e51b81526004016106a29061338c565b603780546001600160a01b0319166001600160a01b0383169081179091556040519081527fb266add5f3044b17d27db796af992cecbe413921b4e8aaaee03c719e16b9806a9060200161078a565b610c7c6122ee565b610c985760405162461bcd60e51b81526004016106a29061338c565b6001600160a01b03811660009081526035602052604090205460ff1615610d015760405162461bcd60e51b815260206004820152601960248201527f537472617465677920616c726561647920617070726f7665640000000000000060448201526064016106a2565b6040805180820182526001808252600060208084018281526001600160a01b038716808452603583528684209551865460ff19169015151786559051948401949094556036805493840181559091527f4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b890910180546001600160a01b0319168317905591519081527f960dd94cbb79169f09a4e445d58b895df2d9bffa5b31055d0932d801724a20d1910161078a565b603f546001600160a01b0316331480610dcd5750610dcd6122ee565b610de95760405162461bcd60e51b81526004016106a2906133c3565b6037805460ff60a81b1916600160a81b1790556040517f71f0e5b62f846a22e0b4d159e516e62fa9c2b8eb570be15f83e67d98a2ee51e090600090a1565b7f53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45358054600091906002811415610e6f5760405162461bcd60e51b81526004016106a29061340b565b60028255603f546001600160a01b0316331480610e8f5750610e8f6122ee565b610eab5760405162461bcd60e51b81526004016106a2906133c3565b6001600160a01b0389166000908152603360209081526040808320815160808101909252805460ff808216151584529293919291840191610100909104166001811115610efa57610efa61361c565b6001811115610f0b57610f0b61361c565b8152905462010000810460ff908116602080850191909152630100000090920461ffff166040938401526001600160a01b038d1660009081526033835283812084516080810190955280548084161515865295965090949092840191610100909104166001811115610f7f57610f7f61361c565b6001811115610f9057610f9061361c565b8152905462010000810460ff1660208301526301000000900461ffff1660409091015282519091506110045760405162461bcd60e51b815260206004820152601b60248201527f46726f6d206173736574206973206e6f7420737570706f72746564000000000060448201526064016106a2565b80516110525760405162461bcd60e51b815260206004820152601960248201527f546f206173736574206973206e6f7420737570706f727465640000000000000060448201526064016106a2565b6040805180820182526048546001600160a01b038082168352600160a01b90910461ffff16602083015291516370a0823160e01b81523060048201529091600091908d16906370a082319060240160206040518083038186803b1580156110b857600080fd5b505afa1580156110cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110f091906132ab565b825190915061110a906001600160a01b038f16908d612716565b81600001516001600160a01b0316632506c0188e8e60018f61112c91906135a8565b8e8e8e6040518763ffffffff1660e01b8152600401611150969594939291906132fd565b602060405180830381600087803b15801561116a57600080fd5b505af115801561117e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111a291906132ab565b506040516370a0823160e01b815230600482015281906001600160a01b038e16906370a082319060240160206040518083038186803b1580156111e457600080fd5b505afa1580156111f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061121c91906132ab565b61122691906135a8565b965050888610156112795760405162461bcd60e51b815260206004820152601960248201527f5374726174656769737420736c697070616765206c696d69740000000000000060448201526064016106a2565b6000826060015161271061128d9190613433565b6037546040516315d5220f60e31b81526001600160a01b038f8116600483015261ffff93909316929091169063aea910789060240160206040518083038186803b1580156112da57600080fd5b505afa1580156112ee573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061131291906132ab565b61131c9190613566565b603760009054906101000a90046001600160a01b03166001600160a01b031663aea910788f6040518263ffffffff1660e01b815260040161136c91906001600160a01b0391909116815260200190565b60206040518083038186803b15801561138457600080fd5b505afa158015611398573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113bc91906132ab565b60608601516113cd90612710613585565b6113db9061ffff168e613566565b6113e59190613566565b6113ef9190613459565b905061140e6012856040015160ff16836128839092919063ffffffff16565b604084015161142490899060129060ff16612883565b10156114725760405162461bcd60e51b815260206004820152601e60248201527f4f7261636c6520736c697070616765206c696d6974206578636565646564000060448201526064016106a2565b5061271081602001516127106114889190613585565b61ffff16603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156114da57600080fd5b505afa1580156114ee573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061151291906132ab565b61151c9190613566565b6115269190613459565b306001600160a01b031663d4c3eea06040518163ffffffff1660e01b815260040160206040518083038186803b15801561155f57600080fd5b505afa158015611573573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061159791906132ab565b10156115de5760405162461bcd60e51b8152602060048201526016602482015275416c6c6f7765642076616c7565203c20737570706c7960501b60448201526064016106a2565b8a6001600160a01b03168c6001600160a01b03167fa078c4190abe07940190effc1846be0ccf03ad6007bc9e93f9697d0b460befbb8c8960405161162c929190918252602082015260400190565b60405180910390a35050506001825550509695505050505050565b603f546001600160a01b031633148061166357506116636122ee565b61167f5760405162461bcd60e51b81526004016106a2906133c3565b6001600160a01b03811660009081526035602052604090205460ff166116e75760405162461bcd60e51b815260206004820152601960248201527f5374726174656779206973206e6f7420737570706f727465640000000000000060448201526064016106a2565b6000819050806001600160a01b031663853828b66040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561172757600080fd5b505af115801561173b573d6000803e3d6000fd5b505050505050565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b0316146117de5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b60648201526084016106a2565b6117e7336128e7565b565b6117f16122ee565b61180d5760405162461bcd60e51b81526004016106a29061338c565b600060465560478190556040518181527fc29d6fedbc6bdf267a08166c2b976fbd72aca5d6a769528616f8b9224c8f197f9060200161078a565b61184f6122ee565b61186b5760405162461bcd60e51b81526004016106a29061338c565b60418190556040518181527f95201f9c21f26877223b1ff4073936a6484c35495649e60e55730497aeb60d939060200161078a565b6118a86122ee565b6118c45760405162461bcd60e51b81526004016106a29061338c565b6001600160a01b03821660009081526033602052604090205460ff161561192d5760405162461bcd60e51b815260206004820152601760248201527f417373657420616c726561647920737570706f7274656400000000000000000060448201526064016106a2565b60405180608001604052806001151581526020018260ff1660018111156119565761195661361c565b60018111156119675761196761361c565b81526000602080830182905260409283018290526001600160a01b0386168252603381529190208251815490151560ff19821681178355928401519192839161ff001990911661ffff19909116176101008360018111156119ca576119ca61361c565b02179055506040820151815460609093015161ffff1663010000000264ffff0000001960ff90921662010000029190911664ffffff00001990931692909217919091179055611a188261276d565b603480546001810182556000919091527f46bddb1178e94d7f2892ff5f366840eb658911794f2c3a44c450aa2c505186c10180546001600160a01b0319166001600160a01b038481169182179092556037546040516315d5220f60e31b815260048101929092529091169063aea910789060240160206040518083038186803b158015611aa457600080fd5b505afa158015611ab8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611adc91906132ab565b506040516001600160a01b03831681527f4f1ac48525e50059cc1cc6e0e1940ece0dd653a4db4841538d6aef036be2fb7b906020015b60405180910390a15050565b611b266122ee565b611b425760405162461bcd60e51b81526004016106a29061338c565b603f80546001600160a01b0319166001600160a01b0383169081179091556040519081527f869e0abd13cc3a975de7b93be3df1cb2255c802b1cead85963cc79d99f131bee9060200161078a565b611b986122ee565b611bb45760405162461bcd60e51b81526004016106a29061338c565b6001600160a01b03821660009081526033602052604090205460ff16611c125760405162461bcd60e51b8152602060048201526013602482015272105cdcd95d081b9bdd081cdd5c1c1bdc9d1959606a1b60448201526064016106a2565b6103e88161ffff1610611c5b5760405162461bcd60e51b81526020600482015260116024820152700a6d8d2e0e0c2ceca40e8dede40d0d2ced607b1b60448201526064016106a2565b6001600160a01b038216600081815260336020908152604091829020805464ffff0000001916630100000061ffff8716908102919091179091558251938452908301527f8d22e9d2cbe8bb65a3c4412bd8970743864512a1a0e004e8d00fb96277b78b949101611b12565b603f546001600160a01b0316331480611ce25750611ce26122ee565b611cfe5760405162461bcd60e51b81526004016106a2906133c3565b7f53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac453580546002811415611d425760405162461bcd60e51b81526004016106a29061340b565b60028255611d5387878787876129a8565b50600190555050505050565b603f546001600160a01b0316331480611d7b5750611d7b6122ee565b611d975760405162461bcd60e51b81526004016106a2906133c3565b670de0b6b3a7640000811115611ddf5760405162461bcd60e51b815260206004820152600d60248201526c496e76616c69642076616c756560981b60448201526064016106a2565b60398190556040518181527f41ecb23a0e7865b25f38c268b7c3012220d822929e9edff07326e89d5bb822b59060200161078a565b603f546001600160a01b0316331480611e305750611e306122ee565b611e4c5760405162461bcd60e51b81526004016106a2906133c3565b6037805460ff60a81b191690556040517f891ebab18da80ebeeea06b1b1cede098329c4c008906a98370c2ac7a80b571cb90600090a1565b611e8c6122ee565b611ea85760405162461bcd60e51b81526004016106a29061338c565b604880546001600160a01b0319166001600160a01b0383169081179091556040519081527f7d7719313229e558c5a3893cad2eb86a86a049156d1d9ebd5c63a8eedefd1c039060200161078a565b603f546001600160a01b0316331480611f125750611f126122ee565b611f2e5760405162461bcd60e51b81526004016106a2906133c3565b7f53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac453580546002811415611f725760405162461bcd60e51b81526004016106a29061340b565b60028255611d53308888888888612be6565b611f8c6122ee565b611fa85760405162461bcd60e51b81526004016106a29061338c565b603a8190556040518181527f2ec5fb5a3d2703edc461252d92ccd2799c3c74f01d97212b20388207fa17ae459060200161078a565b611fe56122ee565b6120015760405162461bcd60e51b81526004016106a29061338c565b603b8190556040518181527f39367850377ac04920a9a670f2180e7a94d83b15ad302e59875ec58fd10bd37d9060200161078a565b603f546001600160a01b031633148061205257506120526122ee565b61206e5760405162461bcd60e51b81526004016106a2906133c3565b604080516001600160a01b038085168252831660208201527fba58ce12801c949fa65f41c46ed108671c219baf945fa48d21026cea99ff252a910160405180910390a16001600160a01b0381161561224a576001600160a01b03811660009081526035602052604090205460ff166121205760405162461bcd60e51b815260206004820152601560248201527414dd1c985d1959de481b9bdd08185c1c1c9bdd9959605a1b60448201526064016106a2565b6001600160a01b038216600090815260336020526040902054819060ff166121835760405162461bcd60e51b8152602060048201526016602482015275105cdcd95d081a5cc81b9bdd081cdd5c1c1bdc9d195960521b60448201526064016106a2565b60405163551c457b60e11b81526001600160a01b03848116600483015282169063aa388af69060240160206040518083038186803b1580156121c457600080fd5b505afa1580156121d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121fc9190613255565b6122485760405162461bcd60e51b815260206004820152601f60248201527f4173736574206e6f7420737570706f727465642062792053747261746567790060448201526064016106a2565b505b6001600160a01b03918216600090815260406020819052902080546001600160a01b03191691909216179055565b603f546001600160a01b031633148061229457506122946122ee565b6122b05760405162461bcd60e51b81526004016106a2906133c3565b6037805460ff60a01b1916600160a01b1790556040517f8cff26a5985614b3d30629cc4ab83824bf115aec971b718d8f2f99562032e97290600090a1565b600061230660008051602061366e8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b603f546001600160a01b031633148061233b575061233b6122ee565b6123575760405162461bcd60e51b81526004016106a2906133c3565b60365460005b8181101561085b576036818154811061237857612378613648565b60009182526020822001546040805163429c145b60e11b815290516001600160a01b039092169263853828b69260048084019382900301818387803b1580156123c057600080fd5b505af11580156123d4573d6000803e3d6000fd5b50505050806123e2906135eb565b905061235d565b6123f16122ee565b61240d5760405162461bcd60e51b81526004016106a29061338c565b612435817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b031661245560008051602061366e8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b6124956122ee565b6124b15760405162461bcd60e51b81526004016106a29061338c565b604580546001600160a01b0319166001600160a01b0383169081179091556040519081527fa12850fb726e0b2b7b3c9a9342031e1268a8148d0eb06b4bea8613204ffcd2b89060200161078a565b6125076122ee565b6125235760405162461bcd60e51b81526004016106a29061338c565b6127118161ffff161061256f5760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420626173697320706f696e747360601b60448201526064016106a2565b6048805461ffff60a01b1916600160a01b61ffff8416908102919091179091556040519081527ff12c00256bee2b6facb111a88a9b1cff86e79132939b44f1353212d6f74695579060200161078a565b6125c76122ee565b6125e35760405162461bcd60e51b81526004016106a29061338c565b6103e881111561263f5760405162461bcd60e51b815260206004820152602160248201527f52656465656d206665652073686f756c64206e6f74206265206f7665722031306044820152602560f81b60648201526084016106a2565b60388190556040518181527fd6c7508d6658ccee36b7b7d7fd72e5cbaeefb40c64eff24e9ae7470e846304ee9060200161078a565b61267c6122ee565b6126985760405162461bcd60e51b81526004016106a29061338c565b803b6126f25760405162461bcd60e51b8152602060048201526024808201527f6e657720696d706c656d656e746174696f6e206973206e6f74206120636f6e746044820152631c9858dd60e21b60648201526084016106a2565b7fa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd955565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052612768908490612d70565b505050565b6001600160a01b0381166000908152603360205260409020805462010000900460ff1615612799575050565b6000826001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b1580156127d457600080fd5b505afa1580156127e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061280c91906132c4565b905060068160ff1610158015612826575060128160ff1611155b6128695760405162461bcd60e51b81526020600482015260146024820152732ab732bc3832b1ba32b210383932b1b4b9b4b7b760611b60448201526064016106a2565b815460ff909116620100000262ff00001990911617905550565b6000818311156128b3576128ac61289a83856135a8565b6128a590600a6134be565b8590612e42565b93506128dd565b818310156128dd576128da6128c884846135a8565b6128d390600a6134be565b8590612e57565b93505b50825b9392505050565b6001600160a01b03811661293d5760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f72206973206164647265737328302900000000000060448201526064016106a2565b806001600160a01b031661295d60008051602061366e8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a3610bff8160008051602061366e83398151915255565b6001600160a01b03851660009081526035602052604090205460ff16612a065760405162461bcd60e51b8152602060048201526013602482015272496e76616c696420746f20537472617465677960681b60448201526064016106a2565b828114612a515760405162461bcd60e51b81526020600482015260196024820152780a0c2e4c2dacae8cae440d8cadccee8d040dad2e6dac2e8c6d603b1b60448201526064016106a2565b8260005b81811015612b8a576000868683818110612a7157612a71613648565b9050602002016020810190612a869190613055565b60405163551c457b60e11b81526001600160a01b0380831660048301529192509089169063aa388af69060240160206040518083038186803b158015612acb57600080fd5b505afa158015612adf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b039190613255565b612b435760405162461bcd60e51b8152602060048201526011602482015270105cdcd95d081d5b9cdd5c1c1bdc9d1959607a1b60448201526064016106a2565b612b7988868685818110612b5957612b59613648565b90506020020135836001600160a01b03166127169092919063ffffffff16565b50612b83816135eb565b9050612a55565b50856001600160a01b031663de5f62686040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612bc657600080fd5b505af1158015612bda573d6000803e3d6000fd5b50505050505050505050565b6001600160a01b03851660009081526035602052604090205460ff16612c465760405162461bcd60e51b8152602060048201526015602482015274496e76616c69642066726f6d20537472617465677960581b60448201526064016106a2565b828114612c915760405162461bcd60e51b81526020600482015260196024820152780a0c2e4c2dacae8cae440d8cadccee8d040dad2e6dac2e8c6d603b1b60448201526064016106a2565b8260005b81811015612d6657866001600160a01b031663d9caed1289888885818110612cbf57612cbf613648565b9050602002016020810190612cd49190613055565b878786818110612ce657612ce6613648565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b158015612d3d57600080fd5b505af1158015612d51573d6000803e3d6000fd5b5050505080612d5f906135eb565b9050612c95565b5050505050505050565b6000612dc5826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316612e639092919063ffffffff16565b8051909150156127685780806020019051810190612de39190613255565b6127685760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016106a2565b6000612e4e8284613566565b90505b92915050565b6000612e4e8284613459565b6060612e728484600085612e7a565b949350505050565b606082471015612edb5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016106a2565b843b612f295760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016106a2565b600080866001600160a01b03168587604051612f4591906132e1565b60006040518083038185875af1925050503d8060008114612f82576040519150601f19603f3d011682016040523d82523d6000602084013e612f87565b606091505b5091509150612f97828286612fa2565b979650505050505050565b60608315612fb15750816128e0565b825115612fc15782518084602001fd5b8160405162461bcd60e51b81526004016106a29190613359565b80356001600160a01b0381168114612ff257600080fd5b919050565b60008083601f84011261300957600080fd5b50813567ffffffffffffffff81111561302157600080fd5b6020830191508360208260051b850101111561303c57600080fd5b9250929050565b803561ffff81168114612ff257600080fd5b60006020828403121561306757600080fd5b612e4e82612fdb565b6000806040838503121561308357600080fd5b61308c83612fdb565b915061309a60208401612fdb565b90509250929050565b60008060008060008060a087890312156130bc57600080fd5b6130c587612fdb565b95506130d360208801612fdb565b94506040870135935060608701359250608087013567ffffffffffffffff808211156130fe57600080fd5b818901915089601f83011261311257600080fd5b81358181111561312157600080fd5b8a602082850101111561313357600080fd5b6020830194508093505050509295509295509295565b60008060008060006060868803121561316157600080fd5b61316a86612fdb565b9450602086013567ffffffffffffffff8082111561318757600080fd5b61319389838a01612ff7565b909650945060408801359150808211156131ac57600080fd5b506131b988828901612ff7565b969995985093965092949392505050565b600080604083850312156131dd57600080fd5b6131e683612fdb565b915061309a60208401613043565b6000806040838503121561320757600080fd5b61321083612fdb565b946020939093013593505050565b6000806040838503121561323157600080fd5b61323a83612fdb565b9150602083013561324a8161365e565b809150509250929050565b60006020828403121561326757600080fd5b815180151581146128e057600080fd5b60006020828403121561328957600080fd5b612e4e82613043565b6000602082840312156132a457600080fd5b5035919050565b6000602082840312156132bd57600080fd5b5051919050565b6000602082840312156132d657600080fd5b81516128e08161365e565b600082516132f38184602087016135bf565b9190910192915050565b6001600160a01b03878116825286166020820152604081018590526060810184905260a06080820181905281018290526000828460c0840137600060c0848401015260c0601f19601f8501168301019050979650505050505050565b60208152600082518060208401526133788160408501602087016135bf565b601f01601f19169190910160400192915050565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60208082526028908201527f43616c6c6572206973206e6f74207468652053747261746567697374206f722060408201526723b7bb32b93737b960c11b606082015260800190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b600061ffff80831681851680830382111561345057613450613606565b01949350505050565b60008261347657634e487b7160e01b600052601260045260246000fd5b500490565b600181815b808511156134b657816000190482111561349c5761349c613606565b808516156134a957918102915b93841c9390800290613480565b509250929050565b6000612e4e83836000826134d457506001612e51565b816134e157506000612e51565b81600181146134f757600281146135015761351d565b6001915050612e51565b60ff84111561351257613512613606565b50506001821b612e51565b5060208310610133831016604e8410600b8410161715613540575081810a612e51565b61354a838361347b565b806000190482111561355e5761355e613606565b029392505050565b600081600019048311821515161561358057613580613606565b500290565b600061ffff838116908316818110156135a0576135a0613606565b039392505050565b6000828210156135ba576135ba613606565b500390565b60005b838110156135da5781810151838201526020016135c2565b83811115610b5a5750506000910152565b60006000198214156135ff576135ff613606565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b60ff81168114610bff57600080fdfe7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220856c9fec2e98e8d950cc7553495c5c13452851bc0b706e1a29005d23345bcb1364736f6c63430008070033", + "args": [ + "0x94373a4919B3240D86eA41593D5eBa789FEF3848" + ], + "numDeployments": 2, + "solcInputHash": "9b811e7a632431f9f724307daee2b897", + "metadata": "{\"compiler\":{\"version\":\"0.8.7+commit.e28d00a7\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_weth\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"AllocateThresholdUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_strategy\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"AssetAllocated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_strategy\",\"type\":\"address\"}],\"name\":\"AssetDefaultStrategyUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"AssetRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"AssetSupported\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"CapitalPaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"CapitalUnpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_dripper\",\"type\":\"address\"}],\"name\":\"DripperChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"GovernorshipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"maxSupplyDiff\",\"type\":\"uint256\"}],\"name\":\"MaxSupplyDiffChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"Mint\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"NetOusdMintForStrategyThresholdChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_ousdMetaStrategy\",\"type\":\"address\"}],\"name\":\"OusdMetaStrategyUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"PendingGovernorshipTransfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_priceProvider\",\"type\":\"address\"}],\"name\":\"PriceProviderUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"RebasePaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"RebaseThresholdUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"RebaseUnpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"Redeem\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_redeemFeeBps\",\"type\":\"uint256\"}],\"name\":\"RedeemFeeUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"StrategistUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"StrategyApproved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"StrategyRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_basis\",\"type\":\"uint256\"}],\"name\":\"SwapAllowedUndervalueChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_basis\",\"type\":\"uint256\"}],\"name\":\"SwapSlippageChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_fromAsset\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_toAsset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_fromAssetAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_toAssetAmount\",\"type\":\"uint256\"}],\"name\":\"Swapped\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"SwapperChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"TrusteeAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_basis\",\"type\":\"uint256\"}],\"name\":\"TrusteeFeeBpsChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_vaultBuffer\",\"type\":\"uint256\"}],\"name\":\"VaultBufferUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_claimable\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_newClaimable\",\"type\":\"uint256\"}],\"name\":\"WithdrawalClaimable\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_withdrawer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"WithdrawalClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_withdrawer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_queued\",\"type\":\"uint256\"}],\"name\":\"WithdrawalRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_yield\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_fee\",\"type\":\"uint256\"}],\"name\":\"YieldDistribution\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"allowedSwapUndervalue\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"approveStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"assetDefaultStrategies\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"autoAllocateThreshold\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"cacheDecimals\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"capitalPaused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategyToAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"_assets\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_amounts\",\"type\":\"uint256[]\"}],\"name\":\"depositToStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"dripper\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"governor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maxSupplyDiff\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"netOusdMintForStrategyThreshold\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"netOusdMintedForStrategy\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"ousdMetaStrategy\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pauseCapital\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pauseRebase\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"priceProvider\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebasePaused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebaseThreshold\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"redeemFeeBps\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"removeAsset\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"removeStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImpl\",\"type\":\"address\"}],\"name\":\"setAdminImpl\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_strategy\",\"type\":\"address\"}],\"name\":\"setAssetDefaultStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"setAutoAllocateThreshold\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_dripper\",\"type\":\"address\"}],\"name\":\"setDripper\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_maxSupplyDiff\",\"type\":\"uint256\"}],\"name\":\"setMaxSupplyDiff\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"setNetOusdMintForStrategyThreshold\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"_allowedOracleSlippageBps\",\"type\":\"uint16\"}],\"name\":\"setOracleSlippage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_ousdMetaStrategy\",\"type\":\"address\"}],\"name\":\"setOusdMetaStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_priceProvider\",\"type\":\"address\"}],\"name\":\"setPriceProvider\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"setRebaseThreshold\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_redeemFeeBps\",\"type\":\"uint256\"}],\"name\":\"setRedeemFeeBps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"setStrategistAddr\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"_basis\",\"type\":\"uint16\"}],\"name\":\"setSwapAllowedUndervalue\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_swapperAddr\",\"type\":\"address\"}],\"name\":\"setSwapper\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"setTrusteeAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_basis\",\"type\":\"uint256\"}],\"name\":\"setTrusteeFeeBps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_vaultBuffer\",\"type\":\"uint256\"}],\"name\":\"setVaultBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"strategistAddr\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"_unitConversion\",\"type\":\"uint8\"}],\"name\":\"supportAsset\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_fromAsset\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_toAsset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_fromAssetAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_minToAssetAmount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"swapCollateral\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"toAssetAmount\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"swapper\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"swapper_\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newGovernor\",\"type\":\"address\"}],\"name\":\"transferGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"transferToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"trusteeAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"trusteeFeeBps\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpauseCapital\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpauseRebase\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"vaultBuffer\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"weth\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawAllFromStrategies\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategyAddr\",\"type\":\"address\"}],\"name\":\"withdrawAllFromStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategyFromAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"_assets\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_amounts\",\"type\":\"uint256[]\"}],\"name\":\"withdrawFromStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawalQueueMetadata\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"queued\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"claimable\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"claimed\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"nextWithdrawalIndex\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"withdrawalRequests\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"withdrawer\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"claimed\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"queued\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"Origin Protocol Inc\",\"kind\":\"dev\",\"methods\":{\"allowedSwapUndervalue()\":{\"returns\":{\"value\":\"Percentage in basis points.\"}},\"approveStrategy(address)\":{\"params\":{\"_addr\":\"Address of the strategy to add\"}},\"cacheDecimals(address)\":{\"params\":{\"_asset\":\"Address of asset token\"}},\"depositToStrategy(address,address[],uint256[])\":{\"params\":{\"_amounts\":\"Array of amounts of each corresponding asset to deposit.\",\"_assets\":\"Array of asset address that will be deposited into the strategy.\",\"_strategyToAddress\":\"Address of the Strategy to deposit assets into.\"}},\"removeAsset(address)\":{\"params\":{\"_asset\":\"Address of asset\"}},\"removeStrategy(address)\":{\"params\":{\"_addr\":\"Address of the strategy to remove\"}},\"setAdminImpl(address)\":{\"params\":{\"newImpl\":\"address of the implementation\"}},\"setAssetDefaultStrategy(address,address)\":{\"params\":{\"_asset\":\"Address of the asset\",\"_strategy\":\"Address of the Strategy\"}},\"setAutoAllocateThreshold(uint256)\":{\"params\":{\"_threshold\":\"OToken amount with 18 fixed decimals.\"}},\"setDripper(address)\":{\"params\":{\"_dripper\":\"Address of the Dripper contract.\"}},\"setNetOusdMintForStrategyThreshold(uint256)\":{\"params\":{\"_threshold\":\"OToken amount with 18 fixed decimals.\"}},\"setOracleSlippage(address,uint16)\":{\"params\":{\"_allowedOracleSlippageBps\":\"allowed slippage from Oracle in basis points. eg 20 = 0.2%. Max 10%.\",\"_asset\":\"Address of the asset token.\"}},\"setOusdMetaStrategy(address)\":{\"params\":{\"_ousdMetaStrategy\":\"Address of OToken metapool strategy\"}},\"setPriceProvider(address)\":{\"params\":{\"_priceProvider\":\"Address of price provider\"}},\"setRebaseThreshold(uint256)\":{\"params\":{\"_threshold\":\"OToken amount with 18 fixed decimals.\"}},\"setRedeemFeeBps(uint256)\":{\"params\":{\"_redeemFeeBps\":\"Basis point fee to be charged\"}},\"setStrategistAddr(address)\":{\"params\":{\"_address\":\"Address of Strategist\"}},\"setSwapAllowedUndervalue(uint16)\":{\"params\":{\"_basis\":\"Percentage in basis points. eg 100 == 1%\"}},\"setSwapper(address)\":{\"params\":{\"_swapperAddr\":\"Address of the Swapper contract that implements the ISwapper interface.\"}},\"setVaultBuffer(uint256)\":{\"params\":{\"_vaultBuffer\":\"Percentage using 18 decimals. 100% = 1e18.\"}},\"supportAsset(address,uint8)\":{\"params\":{\"_asset\":\"Address of asset\"}},\"swapCollateral(address,address,uint256,uint256,bytes)\":{\"params\":{\"_data\":\"implementation specific data. eg 1Inch swap data\",\"_fromAsset\":\"The token address of the asset being sold by the vault.\",\"_fromAssetAmount\":\"The amount of assets being sold by the vault.\",\"_minToAssetAmount\":\"The minimum amount of assets to be purchased.\",\"_toAsset\":\"The token address of the asset being purchased by the vault.\"},\"returns\":{\"toAssetAmount\":\"The amount of toAssets that was received from the swap\"}},\"transferGovernance(address)\":{\"params\":{\"_newGovernor\":\"Address of the new Governor\"}},\"transferToken(address,uint256)\":{\"params\":{\"_amount\":\"Amount of the asset to transfer\",\"_asset\":\"Address for the asset\"}},\"withdrawAllFromStrategy(address)\":{\"params\":{\"_strategyAddr\":\"Strategy address.\"}},\"withdrawFromStrategy(address,address[],uint256[])\":{\"params\":{\"_amounts\":\"Array of amounts of each corresponding asset to withdraw.\",\"_assets\":\"Array of asset address that will be withdrawn from the strategy.\",\"_strategyFromAddress\":\"Address of the Strategy to withdraw assets from.\"}}},\"title\":\"OETH VaultAdmin Contract\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"allowedSwapUndervalue()\":{\"notice\":\"Max allowed percentage the vault total value can drop below the OToken total supply in basis points when executing a collateral swap. For example 100 == 1%\"},\"approveStrategy(address)\":{\"notice\":\"Add a strategy to the Vault.\"},\"assetDefaultStrategies(address)\":{\"notice\":\"Mapping of asset address to the Strategy that they should automatically\"},\"autoAllocateThreshold()\":{\"notice\":\"OToken mints over this amount automatically allocate funds. 18 decimals.\"},\"cacheDecimals(address)\":{\"notice\":\"Cache decimals on OracleRouter for a particular asset. This action is required before that asset's price can be accessed.\"},\"capitalPaused()\":{\"notice\":\"pause operations that change the OToken supply. eg mint, redeem, allocate, mint/burn for strategy\"},\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"depositToStrategy(address,address[],uint256[])\":{\"notice\":\"Deposit multiple assets from the vault into the strategy.\"},\"dripper()\":{\"notice\":\"Address of the Dripper contract that streams harvested rewards to the Vault\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"maxSupplyDiff()\":{\"notice\":\"Max difference between total supply and total value of assets. 18 decimals.\"},\"netOusdMintForStrategyThreshold()\":{\"notice\":\"How much net total OTokens are allowed to be minted by all strategies\"},\"netOusdMintedForStrategy()\":{\"notice\":\"How much OTokens are currently minted by the strategy\"},\"ousdMetaStrategy()\":{\"notice\":\"Metapool strategy that is allowed to mint/burn OTokens without changing collateral\"},\"pauseCapital()\":{\"notice\":\"Set the deposit paused flag to true to prevent capital movement.\"},\"pauseRebase()\":{\"notice\":\"Set the deposit paused flag to true to prevent rebasing.\"},\"priceProvider()\":{\"notice\":\"Address of the Oracle price provider contract\"},\"rebasePaused()\":{\"notice\":\"pause rebasing if true\"},\"rebaseThreshold()\":{\"notice\":\"OToken mints over this amount automatically rebase. 18 decimals.\"},\"redeemFeeBps()\":{\"notice\":\"Redemption fee in basis points. eg 50 = 0.5%\"},\"removeAsset(address)\":{\"notice\":\"Remove a supported asset from the Vault\"},\"removeStrategy(address)\":{\"notice\":\"Remove a strategy from the Vault.\"},\"setAdminImpl(address)\":{\"notice\":\"set the implementation for the admin, this needs to be in a base class else we cannot set it\"},\"setAssetDefaultStrategy(address,address)\":{\"notice\":\"Set the default Strategy for an asset, i.e. the one which the asset will be automatically allocated to and withdrawn from\"},\"setAutoAllocateThreshold(uint256)\":{\"notice\":\"Sets the minimum amount of OTokens in a mint to trigger an automatic allocation of funds afterwords.\"},\"setDripper(address)\":{\"notice\":\"Set the Dripper contract that streams harvested rewards to the vault.\"},\"setMaxSupplyDiff(uint256)\":{\"notice\":\"Sets the maximum allowable difference between total supply and backing assets' value.\"},\"setNetOusdMintForStrategyThreshold(uint256)\":{\"notice\":\"Set maximum amount of OTokens that can at any point be minted and deployed to strategy (used only by ConvexOUSDMetaStrategy for now).\"},\"setOracleSlippage(address,uint16)\":{\"notice\":\"Set the allowed slippage from the Oracle price for collateral asset swaps.\"},\"setOusdMetaStrategy(address)\":{\"notice\":\"Set OToken Metapool strategy\"},\"setPriceProvider(address)\":{\"notice\":\"Set address of price provider.\"},\"setRebaseThreshold(uint256)\":{\"notice\":\"Set a minimum amount of OTokens in a mint or redeem that triggers a rebase\"},\"setRedeemFeeBps(uint256)\":{\"notice\":\"Set a fee in basis points to be charged for a redeem.\"},\"setStrategistAddr(address)\":{\"notice\":\"Set address of Strategist\"},\"setSwapAllowedUndervalue(uint16)\":{\"notice\":\"Set max allowed percentage the vault total value can drop below the OToken total supply in basis points when executing collateral swaps.\"},\"setSwapper(address)\":{\"notice\":\"Set the contract the performs swaps of collateral assets.\"},\"setTrusteeAddress(address)\":{\"notice\":\"Sets the trusteeAddress that can receive a portion of yield. Setting to the zero address disables this feature.\"},\"setTrusteeFeeBps(uint256)\":{\"notice\":\"Sets the TrusteeFeeBps to the percentage of yield that should be received in basis points.\"},\"setVaultBuffer(uint256)\":{\"notice\":\"Set a buffer of assets to keep in the Vault to handle most redemptions without needing to spend gas unwinding assets from a Strategy.\"},\"strategistAddr()\":{\"notice\":\"Address of the Strategist\"},\"supportAsset(address,uint8)\":{\"notice\":\"Add a supported asset to the contract, i.e. one that can be to mint OTokens.\"},\"swapCollateral(address,address,uint256,uint256,bytes)\":{\"notice\":\"Strategist swaps collateral assets sitting in the vault.\"},\"swapper()\":{\"notice\":\"Contract that swaps the vault's collateral assets\"},\"transferGovernance(address)\":{\"notice\":\"Transfers Governance of the contract to a new account (`newGovernor`). Can only be called by the current Governor. Must be claimed for this to complete\"},\"transferToken(address,uint256)\":{\"notice\":\"Transfer token to governor. Intended for recovering tokens stuck in contract, i.e. mistaken sends.\"},\"trusteeAddress()\":{\"notice\":\"Trustee contract that can collect a percentage of yield\"},\"trusteeFeeBps()\":{\"notice\":\"Amount of yield collected in basis points. eg 2000 = 20%\"},\"unpauseCapital()\":{\"notice\":\"Set the deposit paused flag to false to enable capital movement.\"},\"unpauseRebase()\":{\"notice\":\"Set the deposit paused flag to true to allow rebasing.\"},\"vaultBuffer()\":{\"notice\":\"Percentage of assets to keep in Vault to handle (most) withdrawals. 100% = 1e18.\"},\"withdrawAllFromStrategies()\":{\"notice\":\"Withdraws all assets from all the strategies and sends assets to the Vault.\"},\"withdrawAllFromStrategy(address)\":{\"notice\":\"Withdraws all assets from the strategy and sends assets to the Vault.\"},\"withdrawFromStrategy(address,address[],uint256[])\":{\"notice\":\"Withdraw multiple assets from the strategy to the vault.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/vault/OETHVaultAdmin.sol\":\"OETHVaultAdmin\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address recipient, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address sender,\\n address recipient,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0x61437cb513a887a1bbad006e7b1c8b414478427d33de47c5600af3c748f108da\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Address.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize, which returns 0 for contracts in\\n // construction, since the code is only stored at the end of the\\n // constructor execution.\\n\\n uint256 size;\\n assembly {\\n size := extcodesize(account)\\n }\\n return size > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x51b758a8815ecc9596c66c37d56b1d33883a444631a3f916b9fe65cb863ef7c4\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/math/SafeMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\\n\\npragma solidity ^0.8.0;\\n\\n// CAUTION\\n// This version of SafeMath should only be used with Solidity 0.8 or later,\\n// because it relies on the compiler's built in overflow checks.\\n\\n/**\\n * @dev Wrappers over Solidity's arithmetic operations.\\n *\\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\\n * now has built in overflow checking.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n uint256 c = a + b;\\n if (c < a) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b > a) return (false, 0);\\n return (true, a - b);\\n }\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) return (true, 0);\\n uint256 c = a * b;\\n if (c / a != b) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a / b);\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a % b);\\n }\\n }\\n\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n *\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a + b;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n *\\n * - Subtraction cannot overflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a - b;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n *\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a * b;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator.\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a / b;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a % b;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\\n * overflow (when the result is negative).\\n *\\n * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {trySub}.\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n *\\n * - Subtraction cannot overflow.\\n */\\n function sub(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b <= a, errorMessage);\\n return a - b;\\n }\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function div(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a / b;\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting with custom message when dividing by zero.\\n *\\n * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {tryMod}.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function mod(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a % b;\\n }\\n }\\n}\\n\",\"keccak256\":\"0xa2f576be637946f767aa56601c26d717f48a0aff44f82e46f13807eea1009a21\",\"license\":\"MIT\"},\"contracts/governance/Governable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Base for contracts that are managed by the Origin Protocol's Governor.\\n * @dev Copy of the openzeppelin Ownable.sol contract with nomenclature change\\n * from owner to governor and renounce methods removed. Does not use\\n * Context.sol like Ownable.sol does for simplification.\\n * @author Origin Protocol Inc\\n */\\ncontract Governable {\\n // Storage position of the owner and pendingOwner of the contract\\n // keccak256(\\\"OUSD.governor\\\");\\n bytes32 private constant governorPosition =\\n 0x7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a;\\n\\n // keccak256(\\\"OUSD.pending.governor\\\");\\n bytes32 private constant pendingGovernorPosition =\\n 0x44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db;\\n\\n // keccak256(\\\"OUSD.reentry.status\\\");\\n bytes32 private constant reentryStatusPosition =\\n 0x53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac4535;\\n\\n // See OpenZeppelin ReentrancyGuard implementation\\n uint256 constant _NOT_ENTERED = 1;\\n uint256 constant _ENTERED = 2;\\n\\n event PendingGovernorshipTransfer(\\n address indexed previousGovernor,\\n address indexed newGovernor\\n );\\n\\n event GovernorshipTransferred(\\n address indexed previousGovernor,\\n address indexed newGovernor\\n );\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial Governor.\\n */\\n constructor() {\\n _setGovernor(msg.sender);\\n emit GovernorshipTransferred(address(0), _governor());\\n }\\n\\n /**\\n * @notice Returns the address of the current Governor.\\n */\\n function governor() public view returns (address) {\\n return _governor();\\n }\\n\\n /**\\n * @dev Returns the address of the current Governor.\\n */\\n function _governor() internal view returns (address governorOut) {\\n bytes32 position = governorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n governorOut := sload(position)\\n }\\n }\\n\\n /**\\n * @dev Returns the address of the pending Governor.\\n */\\n function _pendingGovernor()\\n internal\\n view\\n returns (address pendingGovernor)\\n {\\n bytes32 position = pendingGovernorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n pendingGovernor := sload(position)\\n }\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the Governor.\\n */\\n modifier onlyGovernor() {\\n require(isGovernor(), \\\"Caller is not the Governor\\\");\\n _;\\n }\\n\\n /**\\n * @notice Returns true if the caller is the current Governor.\\n */\\n function isGovernor() public view returns (bool) {\\n return msg.sender == _governor();\\n }\\n\\n function _setGovernor(address newGovernor) internal {\\n bytes32 position = governorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, newGovernor)\\n }\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a `nonReentrant` function from another `nonReentrant`\\n * function is not supported. It is possible to prevent this from happening\\n * by making the `nonReentrant` function external, and make it call a\\n * `private` function that does the actual work.\\n */\\n modifier nonReentrant() {\\n bytes32 position = reentryStatusPosition;\\n uint256 _reentry_status;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n _reentry_status := sload(position)\\n }\\n\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_reentry_status != _ENTERED, \\\"Reentrant call\\\");\\n\\n // Any calls to nonReentrant after this point will fail\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, _ENTERED)\\n }\\n\\n _;\\n\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, _NOT_ENTERED)\\n }\\n }\\n\\n function _setPendingGovernor(address newGovernor) internal {\\n bytes32 position = pendingGovernorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, newGovernor)\\n }\\n }\\n\\n /**\\n * @notice Transfers Governance of the contract to a new account (`newGovernor`).\\n * Can only be called by the current Governor. Must be claimed for this to complete\\n * @param _newGovernor Address of the new Governor\\n */\\n function transferGovernance(address _newGovernor) external onlyGovernor {\\n _setPendingGovernor(_newGovernor);\\n emit PendingGovernorshipTransfer(_governor(), _newGovernor);\\n }\\n\\n /**\\n * @notice Claim Governance of the contract to a new account (`newGovernor`).\\n * Can only be called by the new Governor.\\n */\\n function claimGovernance() external {\\n require(\\n msg.sender == _pendingGovernor(),\\n \\\"Only the pending Governor can complete the claim\\\"\\n );\\n _changeGovernor(msg.sender);\\n }\\n\\n /**\\n * @dev Change Governance of the contract to a new account (`newGovernor`).\\n * @param _newGovernor Address of the new Governor\\n */\\n function _changeGovernor(address _newGovernor) internal {\\n require(_newGovernor != address(0), \\\"New Governor is address(0)\\\");\\n emit GovernorshipTransferred(_governor(), _newGovernor);\\n _setGovernor(_newGovernor);\\n }\\n}\\n\",\"keccak256\":\"0xb7133d6ce7a9e673ff79fcedb3fd41ae6e58e251f94915bb65731abe524270b4\",\"license\":\"MIT\"},\"contracts/interfaces/IBasicToken.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IBasicToken {\\n function symbol() external view returns (string memory);\\n\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0xa562062698aa12572123b36dfd2072f1a39e44fed2031cc19c2c9fd522f96ec2\",\"license\":\"MIT\"},\"contracts/interfaces/IOracle.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IOracle {\\n /**\\n * @dev returns the asset price in USD, in 8 decimal digits.\\n *\\n * The version of priceProvider deployed for OETH has 18 decimal digits\\n */\\n function price(address asset) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0x9eabf152389f145c9c23ed71972af73fb1708cbc4b26e524a9ba29a557b7cfe5\",\"license\":\"MIT\"},\"contracts/interfaces/IStrategy.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Platform interface to integrate with lending platform like Compound, AAVE etc.\\n */\\ninterface IStrategy {\\n /**\\n * @dev Deposit the given asset to platform\\n * @param _asset asset address\\n * @param _amount Amount to deposit\\n */\\n function deposit(address _asset, uint256 _amount) external;\\n\\n /**\\n * @dev Deposit the entire balance of all supported assets in the Strategy\\n * to the platform\\n */\\n function depositAll() external;\\n\\n /**\\n * @dev Withdraw given asset from Lending platform\\n */\\n function withdraw(\\n address _recipient,\\n address _asset,\\n uint256 _amount\\n ) external;\\n\\n /**\\n * @dev Liquidate all assets in strategy and return them to Vault.\\n */\\n function withdrawAll() external;\\n\\n /**\\n * @dev Returns the current balance of the given asset.\\n */\\n function checkBalance(address _asset)\\n external\\n view\\n returns (uint256 balance);\\n\\n /**\\n * @dev Returns bool indicating whether strategy supports asset.\\n */\\n function supportsAsset(address _asset) external view returns (bool);\\n\\n /**\\n * @dev Collect reward tokens from the Strategy.\\n */\\n function collectRewardTokens() external;\\n\\n /**\\n * @dev The address array of the reward tokens for the Strategy.\\n */\\n function getRewardTokenAddresses() external view returns (address[] memory);\\n}\\n\",\"keccak256\":\"0xb291e409a9b95527f9ed19cd6bff8eeb9921a21c1f5194a48c0bb9ce6613959a\",\"license\":\"MIT\"},\"contracts/interfaces/ISwapper.sol\":{\"content\":\"pragma solidity ^0.8.0;\\n\\ninterface ISwapper {\\n /**\\n * @param fromAsset The token address of the asset being sold.\\n * @param toAsset The token address of the asset being purchased.\\n * @param fromAssetAmount The amount of assets being sold.\\n * @param minToAssetAmmount The minimum amount of assets to be purchased.\\n * @param data tx.data returned from 1Inch's /v5.0/1/swap API\\n */\\n function swap(\\n address fromAsset,\\n address toAsset,\\n uint256 fromAssetAmount,\\n uint256 minToAssetAmmount,\\n bytes calldata data\\n ) external returns (uint256 toAssetAmount);\\n}\\n\",\"keccak256\":\"0xf6452c70d5dbfde99e6e82cd6b49d8cbec8efb48da77e28603bea981b8b0759e\"},\"contracts/interfaces/IVault.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { VaultStorage } from \\\"../vault/VaultStorage.sol\\\";\\n\\ninterface IVault {\\n event AssetSupported(address _asset);\\n event AssetDefaultStrategyUpdated(address _asset, address _strategy);\\n event AssetAllocated(address _asset, address _strategy, uint256 _amount);\\n event StrategyApproved(address _addr);\\n event StrategyRemoved(address _addr);\\n event Mint(address _addr, uint256 _value);\\n event Redeem(address _addr, uint256 _value);\\n event CapitalPaused();\\n event CapitalUnpaused();\\n event RebasePaused();\\n event RebaseUnpaused();\\n event VaultBufferUpdated(uint256 _vaultBuffer);\\n event RedeemFeeUpdated(uint256 _redeemFeeBps);\\n event PriceProviderUpdated(address _priceProvider);\\n event AllocateThresholdUpdated(uint256 _threshold);\\n event RebaseThresholdUpdated(uint256 _threshold);\\n event StrategistUpdated(address _address);\\n event MaxSupplyDiffChanged(uint256 maxSupplyDiff);\\n event YieldDistribution(address _to, uint256 _yield, uint256 _fee);\\n event TrusteeFeeBpsChanged(uint256 _basis);\\n event TrusteeAddressChanged(address _address);\\n event SwapperChanged(address _address);\\n event SwapAllowedUndervalueChanged(uint256 _basis);\\n event SwapSlippageChanged(address _asset, uint256 _basis);\\n event Swapped(\\n address indexed _fromAsset,\\n address indexed _toAsset,\\n uint256 _fromAssetAmount,\\n uint256 _toAssetAmount\\n );\\n event DripperChanged(address indexed _dripper);\\n event WithdrawalRequested(\\n address indexed _withdrawer,\\n uint256 indexed _requestId,\\n uint256 _amount,\\n uint256 _queued\\n );\\n event WithdrawalClaimed(\\n address indexed _withdrawer,\\n uint256 indexed _requestId,\\n uint256 _amount\\n );\\n event WithdrawalClaimable(uint256 _claimable, uint256 _newClaimable);\\n\\n // Governable.sol\\n function transferGovernance(address _newGovernor) external;\\n\\n function claimGovernance() external;\\n\\n function governor() external view returns (address);\\n\\n // VaultAdmin.sol\\n function setPriceProvider(address _priceProvider) external;\\n\\n function priceProvider() external view returns (address);\\n\\n function setRedeemFeeBps(uint256 _redeemFeeBps) external;\\n\\n function redeemFeeBps() external view returns (uint256);\\n\\n function setVaultBuffer(uint256 _vaultBuffer) external;\\n\\n function vaultBuffer() external view returns (uint256);\\n\\n function setAutoAllocateThreshold(uint256 _threshold) external;\\n\\n function autoAllocateThreshold() external view returns (uint256);\\n\\n function setRebaseThreshold(uint256 _threshold) external;\\n\\n function rebaseThreshold() external view returns (uint256);\\n\\n function setStrategistAddr(address _address) external;\\n\\n function strategistAddr() external view returns (address);\\n\\n function setMaxSupplyDiff(uint256 _maxSupplyDiff) external;\\n\\n function maxSupplyDiff() external view returns (uint256);\\n\\n function setTrusteeAddress(address _address) external;\\n\\n function trusteeAddress() external view returns (address);\\n\\n function setTrusteeFeeBps(uint256 _basis) external;\\n\\n function trusteeFeeBps() external view returns (uint256);\\n\\n function ousdMetaStrategy() external view returns (address);\\n\\n function setSwapper(address _swapperAddr) external;\\n\\n function setSwapAllowedUndervalue(uint16 _percentageBps) external;\\n\\n function setOracleSlippage(address _asset, uint16 _allowedOracleSlippageBps)\\n external;\\n\\n function supportAsset(address _asset, uint8 _supportsAsset) external;\\n\\n function approveStrategy(address _addr) external;\\n\\n function removeStrategy(address _addr) external;\\n\\n function setAssetDefaultStrategy(address _asset, address _strategy)\\n external;\\n\\n function assetDefaultStrategies(address _asset)\\n external\\n view\\n returns (address);\\n\\n function pauseRebase() external;\\n\\n function unpauseRebase() external;\\n\\n function rebasePaused() external view returns (bool);\\n\\n function pauseCapital() external;\\n\\n function unpauseCapital() external;\\n\\n function capitalPaused() external view returns (bool);\\n\\n function transferToken(address _asset, uint256 _amount) external;\\n\\n function priceUnitMint(address asset) external view returns (uint256);\\n\\n function priceUnitRedeem(address asset) external view returns (uint256);\\n\\n function withdrawAllFromStrategy(address _strategyAddr) external;\\n\\n function withdrawAllFromStrategies() external;\\n\\n function withdrawFromStrategy(\\n address _strategyFromAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) external;\\n\\n function depositToStrategy(\\n address _strategyToAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) external;\\n\\n // VaultCore.sol\\n function mint(\\n address _asset,\\n uint256 _amount,\\n uint256 _minimumOusdAmount\\n ) external;\\n\\n function mintForStrategy(uint256 _amount) external;\\n\\n function redeem(uint256 _amount, uint256 _minimumUnitAmount) external;\\n\\n function burnForStrategy(uint256 _amount) external;\\n\\n function redeemAll(uint256 _minimumUnitAmount) external;\\n\\n function allocate() external;\\n\\n function rebase() external;\\n\\n function swapCollateral(\\n address fromAsset,\\n address toAsset,\\n uint256 fromAssetAmount,\\n uint256 minToAssetAmount,\\n bytes calldata data\\n ) external returns (uint256 toAssetAmount);\\n\\n function totalValue() external view returns (uint256 value);\\n\\n function checkBalance(address _asset) external view returns (uint256);\\n\\n function calculateRedeemOutputs(uint256 _amount)\\n external\\n view\\n returns (uint256[] memory);\\n\\n function getAssetCount() external view returns (uint256);\\n\\n function getAssetConfig(address _asset)\\n external\\n view\\n returns (VaultStorage.Asset memory config);\\n\\n function getAllAssets() external view returns (address[] memory);\\n\\n function getStrategyCount() external view returns (uint256);\\n\\n function swapper() external view returns (address);\\n\\n function allowedSwapUndervalue() external view returns (uint256);\\n\\n function getAllStrategies() external view returns (address[] memory);\\n\\n function isSupportedAsset(address _asset) external view returns (bool);\\n\\n function netOusdMintForStrategyThreshold() external view returns (uint256);\\n\\n function setOusdMetaStrategy(address _ousdMetaStrategy) external;\\n\\n function setNetOusdMintForStrategyThreshold(uint256 _threshold) external;\\n\\n function netOusdMintedForStrategy() external view returns (int256);\\n\\n function setDripper(address _dripper) external;\\n\\n function weth() external view returns (address);\\n\\n function cacheWETHAssetIndex() external;\\n\\n function wethAssetIndex() external view returns (uint256);\\n\\n function initialize(address, address) external;\\n\\n function setAdminImpl(address) external;\\n\\n function removeAsset(address _asset) external;\\n\\n // These are OETH specific functions\\n function addWithdrawalQueueLiquidity() external;\\n\\n function requestWithdrawal(uint256 _amount)\\n external\\n returns (uint256 requestId, uint256 queued);\\n\\n function claimWithdrawal(uint256 requestId)\\n external\\n returns (uint256 amount);\\n\\n function claimWithdrawals(uint256[] memory requestIds)\\n external\\n returns (uint256[] memory amounts, uint256 totalAmount);\\n\\n function withdrawalQueueMetadata()\\n external\\n view\\n returns (VaultStorage.WithdrawalQueueMetadata memory);\\n\\n function withdrawalRequests(uint256 requestId)\\n external\\n view\\n returns (VaultStorage.WithdrawalRequest memory);\\n}\\n\",\"keccak256\":\"0x5cc3617c2dfed68097a4dc754f17c6c32dd6e11038e6fc9c18ff6f68cd6b029f\",\"license\":\"MIT\"},\"contracts/token/OUSD.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OUSD Token Contract\\n * @dev ERC20 compatible contract for OUSD\\n * @dev Implements an elastic supply\\n * @author Origin Protocol Inc\\n */\\nimport { SafeMath } from \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\nimport { Address } from \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport { Initializable } from \\\"../utils/Initializable.sol\\\";\\nimport { InitializableERC20Detailed } from \\\"../utils/InitializableERC20Detailed.sol\\\";\\nimport { StableMath } from \\\"../utils/StableMath.sol\\\";\\nimport { Governable } from \\\"../governance/Governable.sol\\\";\\n\\n/**\\n * NOTE that this is an ERC20 token but the invariant that the sum of\\n * balanceOf(x) for all x is not >= totalSupply(). This is a consequence of the\\n * rebasing design. Any integrations with OUSD should be aware.\\n */\\n\\ncontract OUSD is Initializable, InitializableERC20Detailed, Governable {\\n using SafeMath for uint256;\\n using StableMath for uint256;\\n\\n event TotalSupplyUpdatedHighres(\\n uint256 totalSupply,\\n uint256 rebasingCredits,\\n uint256 rebasingCreditsPerToken\\n );\\n event AccountRebasingEnabled(address account);\\n event AccountRebasingDisabled(address account);\\n\\n enum RebaseOptions {\\n NotSet,\\n OptOut,\\n OptIn\\n }\\n\\n uint256 private constant MAX_SUPPLY = ~uint128(0); // (2^128) - 1\\n uint256 public _totalSupply;\\n mapping(address => mapping(address => uint256)) private _allowances;\\n address public vaultAddress = address(0);\\n mapping(address => uint256) private _creditBalances;\\n uint256 private _rebasingCredits;\\n uint256 private _rebasingCreditsPerToken;\\n // Frozen address/credits are non rebasing (value is held in contracts which\\n // do not receive yield unless they explicitly opt in)\\n uint256 public nonRebasingSupply;\\n mapping(address => uint256) public nonRebasingCreditsPerToken;\\n mapping(address => RebaseOptions) public rebaseState;\\n mapping(address => uint256) public isUpgraded;\\n\\n uint256 private constant RESOLUTION_INCREASE = 1e9;\\n\\n function initialize(\\n string calldata _nameArg,\\n string calldata _symbolArg,\\n address _vaultAddress,\\n uint256 _initialCreditsPerToken\\n ) external onlyGovernor initializer {\\n InitializableERC20Detailed._initialize(_nameArg, _symbolArg, 18);\\n _rebasingCreditsPerToken = _initialCreditsPerToken;\\n vaultAddress = _vaultAddress;\\n }\\n\\n /**\\n * @dev Verifies that the caller is the Vault contract\\n */\\n modifier onlyVault() {\\n require(vaultAddress == msg.sender, \\\"Caller is not the Vault\\\");\\n _;\\n }\\n\\n /**\\n * @return The total supply of OUSD.\\n */\\n function totalSupply() public view override returns (uint256) {\\n return _totalSupply;\\n }\\n\\n /**\\n * @return Low resolution rebasingCreditsPerToken\\n */\\n function rebasingCreditsPerToken() public view returns (uint256) {\\n return _rebasingCreditsPerToken / RESOLUTION_INCREASE;\\n }\\n\\n /**\\n * @return Low resolution total number of rebasing credits\\n */\\n function rebasingCredits() public view returns (uint256) {\\n return _rebasingCredits / RESOLUTION_INCREASE;\\n }\\n\\n /**\\n * @return High resolution rebasingCreditsPerToken\\n */\\n function rebasingCreditsPerTokenHighres() public view returns (uint256) {\\n return _rebasingCreditsPerToken;\\n }\\n\\n /**\\n * @return High resolution total number of rebasing credits\\n */\\n function rebasingCreditsHighres() public view returns (uint256) {\\n return _rebasingCredits;\\n }\\n\\n /**\\n * @dev Gets the balance of the specified address.\\n * @param _account Address to query the balance of.\\n * @return A uint256 representing the amount of base units owned by the\\n * specified address.\\n */\\n function balanceOf(address _account)\\n public\\n view\\n override\\n returns (uint256)\\n {\\n if (_creditBalances[_account] == 0) return 0;\\n return\\n _creditBalances[_account].divPrecisely(_creditsPerToken(_account));\\n }\\n\\n /**\\n * @dev Gets the credits balance of the specified address.\\n * @dev Backwards compatible with old low res credits per token.\\n * @param _account The address to query the balance of.\\n * @return (uint256, uint256) Credit balance and credits per token of the\\n * address\\n */\\n function creditsBalanceOf(address _account)\\n public\\n view\\n returns (uint256, uint256)\\n {\\n uint256 cpt = _creditsPerToken(_account);\\n if (cpt == 1e27) {\\n // For a period before the resolution upgrade, we created all new\\n // contract accounts at high resolution. Since they are not changing\\n // as a result of this upgrade, we will return their true values\\n return (_creditBalances[_account], cpt);\\n } else {\\n return (\\n _creditBalances[_account] / RESOLUTION_INCREASE,\\n cpt / RESOLUTION_INCREASE\\n );\\n }\\n }\\n\\n /**\\n * @dev Gets the credits balance of the specified address.\\n * @param _account The address to query the balance of.\\n * @return (uint256, uint256, bool) Credit balance, credits per token of the\\n * address, and isUpgraded\\n */\\n function creditsBalanceOfHighres(address _account)\\n public\\n view\\n returns (\\n uint256,\\n uint256,\\n bool\\n )\\n {\\n return (\\n _creditBalances[_account],\\n _creditsPerToken(_account),\\n isUpgraded[_account] == 1\\n );\\n }\\n\\n /**\\n * @dev Transfer tokens to a specified address.\\n * @param _to the address to transfer to.\\n * @param _value the amount to be transferred.\\n * @return true on success.\\n */\\n function transfer(address _to, uint256 _value)\\n public\\n override\\n returns (bool)\\n {\\n require(_to != address(0), \\\"Transfer to zero address\\\");\\n require(\\n _value <= balanceOf(msg.sender),\\n \\\"Transfer greater than balance\\\"\\n );\\n\\n _executeTransfer(msg.sender, _to, _value);\\n\\n emit Transfer(msg.sender, _to, _value);\\n\\n return true;\\n }\\n\\n /**\\n * @dev Transfer tokens from one address to another.\\n * @param _from The address you want to send tokens from.\\n * @param _to The address you want to transfer to.\\n * @param _value The amount of tokens to be transferred.\\n */\\n function transferFrom(\\n address _from,\\n address _to,\\n uint256 _value\\n ) public override returns (bool) {\\n require(_to != address(0), \\\"Transfer to zero address\\\");\\n require(_value <= balanceOf(_from), \\\"Transfer greater than balance\\\");\\n\\n _allowances[_from][msg.sender] = _allowances[_from][msg.sender].sub(\\n _value\\n );\\n\\n _executeTransfer(_from, _to, _value);\\n\\n emit Transfer(_from, _to, _value);\\n\\n return true;\\n }\\n\\n /**\\n * @dev Update the count of non rebasing credits in response to a transfer\\n * @param _from The address you want to send tokens from.\\n * @param _to The address you want to transfer to.\\n * @param _value Amount of OUSD to transfer\\n */\\n function _executeTransfer(\\n address _from,\\n address _to,\\n uint256 _value\\n ) internal {\\n bool isNonRebasingTo = _isNonRebasingAccount(_to);\\n bool isNonRebasingFrom = _isNonRebasingAccount(_from);\\n\\n // Credits deducted and credited might be different due to the\\n // differing creditsPerToken used by each account\\n uint256 creditsCredited = _value.mulTruncate(_creditsPerToken(_to));\\n uint256 creditsDeducted = _value.mulTruncate(_creditsPerToken(_from));\\n\\n _creditBalances[_from] = _creditBalances[_from].sub(\\n creditsDeducted,\\n \\\"Transfer amount exceeds balance\\\"\\n );\\n _creditBalances[_to] = _creditBalances[_to].add(creditsCredited);\\n\\n if (isNonRebasingTo && !isNonRebasingFrom) {\\n // Transfer to non-rebasing account from rebasing account, credits\\n // are removed from the non rebasing tally\\n nonRebasingSupply = nonRebasingSupply.add(_value);\\n // Update rebasingCredits by subtracting the deducted amount\\n _rebasingCredits = _rebasingCredits.sub(creditsDeducted);\\n } else if (!isNonRebasingTo && isNonRebasingFrom) {\\n // Transfer to rebasing account from non-rebasing account\\n // Decreasing non-rebasing credits by the amount that was sent\\n nonRebasingSupply = nonRebasingSupply.sub(_value);\\n // Update rebasingCredits by adding the credited amount\\n _rebasingCredits = _rebasingCredits.add(creditsCredited);\\n }\\n }\\n\\n /**\\n * @dev Function to check the amount of tokens that _owner has allowed to\\n * `_spender`.\\n * @param _owner The address which owns the funds.\\n * @param _spender The address which will spend the funds.\\n * @return The number of tokens still available for the _spender.\\n */\\n function allowance(address _owner, address _spender)\\n public\\n view\\n override\\n returns (uint256)\\n {\\n return _allowances[_owner][_spender];\\n }\\n\\n /**\\n * @dev Approve the passed address to spend the specified amount of tokens\\n * on behalf of msg.sender. This method is included for ERC20\\n * compatibility. `increaseAllowance` and `decreaseAllowance` should be\\n * used instead.\\n *\\n * Changing an allowance with this method brings the risk that someone\\n * may transfer both the old and the new allowance - if they are both\\n * greater than zero - if a transfer transaction is mined before the\\n * later approve() call is mined.\\n * @param _spender The address which will spend the funds.\\n * @param _value The amount of tokens to be spent.\\n */\\n function approve(address _spender, uint256 _value)\\n public\\n override\\n returns (bool)\\n {\\n _allowances[msg.sender][_spender] = _value;\\n emit Approval(msg.sender, _spender, _value);\\n return true;\\n }\\n\\n /**\\n * @dev Increase the amount of tokens that an owner has allowed to\\n * `_spender`.\\n * This method should be used instead of approve() to avoid the double\\n * approval vulnerability described above.\\n * @param _spender The address which will spend the funds.\\n * @param _addedValue The amount of tokens to increase the allowance by.\\n */\\n function increaseAllowance(address _spender, uint256 _addedValue)\\n public\\n returns (bool)\\n {\\n _allowances[msg.sender][_spender] = _allowances[msg.sender][_spender]\\n .add(_addedValue);\\n emit Approval(msg.sender, _spender, _allowances[msg.sender][_spender]);\\n return true;\\n }\\n\\n /**\\n * @dev Decrease the amount of tokens that an owner has allowed to\\n `_spender`.\\n * @param _spender The address which will spend the funds.\\n * @param _subtractedValue The amount of tokens to decrease the allowance\\n * by.\\n */\\n function decreaseAllowance(address _spender, uint256 _subtractedValue)\\n public\\n returns (bool)\\n {\\n uint256 oldValue = _allowances[msg.sender][_spender];\\n if (_subtractedValue >= oldValue) {\\n _allowances[msg.sender][_spender] = 0;\\n } else {\\n _allowances[msg.sender][_spender] = oldValue.sub(_subtractedValue);\\n }\\n emit Approval(msg.sender, _spender, _allowances[msg.sender][_spender]);\\n return true;\\n }\\n\\n /**\\n * @dev Mints new tokens, increasing totalSupply.\\n */\\n function mint(address _account, uint256 _amount) external onlyVault {\\n _mint(_account, _amount);\\n }\\n\\n /**\\n * @dev Creates `_amount` tokens and assigns them to `_account`, increasing\\n * the total supply.\\n *\\n * Emits a {Transfer} event with `from` set to the zero address.\\n *\\n * Requirements\\n *\\n * - `to` cannot be the zero address.\\n */\\n function _mint(address _account, uint256 _amount) internal nonReentrant {\\n require(_account != address(0), \\\"Mint to the zero address\\\");\\n\\n bool isNonRebasingAccount = _isNonRebasingAccount(_account);\\n\\n uint256 creditAmount = _amount.mulTruncate(_creditsPerToken(_account));\\n _creditBalances[_account] = _creditBalances[_account].add(creditAmount);\\n\\n // If the account is non rebasing and doesn't have a set creditsPerToken\\n // then set it i.e. this is a mint from a fresh contract\\n if (isNonRebasingAccount) {\\n nonRebasingSupply = nonRebasingSupply.add(_amount);\\n } else {\\n _rebasingCredits = _rebasingCredits.add(creditAmount);\\n }\\n\\n _totalSupply = _totalSupply.add(_amount);\\n\\n require(_totalSupply < MAX_SUPPLY, \\\"Max supply\\\");\\n\\n emit Transfer(address(0), _account, _amount);\\n }\\n\\n /**\\n * @dev Burns tokens, decreasing totalSupply.\\n */\\n function burn(address account, uint256 amount) external onlyVault {\\n _burn(account, amount);\\n }\\n\\n /**\\n * @dev Destroys `_amount` tokens from `_account`, reducing the\\n * total supply.\\n *\\n * Emits a {Transfer} event with `to` set to the zero address.\\n *\\n * Requirements\\n *\\n * - `_account` cannot be the zero address.\\n * - `_account` must have at least `_amount` tokens.\\n */\\n function _burn(address _account, uint256 _amount) internal nonReentrant {\\n require(_account != address(0), \\\"Burn from the zero address\\\");\\n if (_amount == 0) {\\n return;\\n }\\n\\n bool isNonRebasingAccount = _isNonRebasingAccount(_account);\\n uint256 creditAmount = _amount.mulTruncate(_creditsPerToken(_account));\\n uint256 currentCredits = _creditBalances[_account];\\n\\n // Remove the credits, burning rounding errors\\n if (\\n currentCredits == creditAmount || currentCredits - 1 == creditAmount\\n ) {\\n // Handle dust from rounding\\n _creditBalances[_account] = 0;\\n } else if (currentCredits > creditAmount) {\\n _creditBalances[_account] = _creditBalances[_account].sub(\\n creditAmount\\n );\\n } else {\\n revert(\\\"Remove exceeds balance\\\");\\n }\\n\\n // Remove from the credit tallies and non-rebasing supply\\n if (isNonRebasingAccount) {\\n nonRebasingSupply = nonRebasingSupply.sub(_amount);\\n } else {\\n _rebasingCredits = _rebasingCredits.sub(creditAmount);\\n }\\n\\n _totalSupply = _totalSupply.sub(_amount);\\n\\n emit Transfer(_account, address(0), _amount);\\n }\\n\\n /**\\n * @dev Get the credits per token for an account. Returns a fixed amount\\n * if the account is non-rebasing.\\n * @param _account Address of the account.\\n */\\n function _creditsPerToken(address _account)\\n internal\\n view\\n returns (uint256)\\n {\\n if (nonRebasingCreditsPerToken[_account] != 0) {\\n return nonRebasingCreditsPerToken[_account];\\n } else {\\n return _rebasingCreditsPerToken;\\n }\\n }\\n\\n /**\\n * @dev Is an account using rebasing accounting or non-rebasing accounting?\\n * Also, ensure contracts are non-rebasing if they have not opted in.\\n * @param _account Address of the account.\\n */\\n function _isNonRebasingAccount(address _account) internal returns (bool) {\\n bool isContract = Address.isContract(_account);\\n if (isContract && rebaseState[_account] == RebaseOptions.NotSet) {\\n _ensureRebasingMigration(_account);\\n }\\n return nonRebasingCreditsPerToken[_account] > 0;\\n }\\n\\n /**\\n * @dev Ensures internal account for rebasing and non-rebasing credits and\\n * supply is updated following deployment of frozen yield change.\\n */\\n function _ensureRebasingMigration(address _account) internal {\\n if (nonRebasingCreditsPerToken[_account] == 0) {\\n emit AccountRebasingDisabled(_account);\\n if (_creditBalances[_account] == 0) {\\n // Since there is no existing balance, we can directly set to\\n // high resolution, and do not have to do any other bookkeeping\\n nonRebasingCreditsPerToken[_account] = 1e27;\\n } else {\\n // Migrate an existing account:\\n\\n // Set fixed credits per token for this account\\n nonRebasingCreditsPerToken[_account] = _rebasingCreditsPerToken;\\n // Update non rebasing supply\\n nonRebasingSupply = nonRebasingSupply.add(balanceOf(_account));\\n // Update credit tallies\\n _rebasingCredits = _rebasingCredits.sub(\\n _creditBalances[_account]\\n );\\n }\\n }\\n }\\n\\n /**\\n * @notice Enable rebasing for an account.\\n * @dev Add a contract address to the non-rebasing exception list. The\\n * address's balance will be part of rebases and the account will be exposed\\n * to upside and downside.\\n * @param _account Address of the account.\\n */\\n function governanceRebaseOptIn(address _account)\\n public\\n nonReentrant\\n onlyGovernor\\n {\\n _rebaseOptIn(_account);\\n }\\n\\n /**\\n * @dev Add a contract address to the non-rebasing exception list. The\\n * address's balance will be part of rebases and the account will be exposed\\n * to upside and downside.\\n */\\n function rebaseOptIn() public nonReentrant {\\n _rebaseOptIn(msg.sender);\\n }\\n\\n function _rebaseOptIn(address _account) internal {\\n require(_isNonRebasingAccount(_account), \\\"Account has not opted out\\\");\\n\\n // Convert balance into the same amount at the current exchange rate\\n uint256 newCreditBalance = _creditBalances[_account]\\n .mul(_rebasingCreditsPerToken)\\n .div(_creditsPerToken(_account));\\n\\n // Decreasing non rebasing supply\\n nonRebasingSupply = nonRebasingSupply.sub(balanceOf(_account));\\n\\n _creditBalances[_account] = newCreditBalance;\\n\\n // Increase rebasing credits, totalSupply remains unchanged so no\\n // adjustment necessary\\n _rebasingCredits = _rebasingCredits.add(_creditBalances[_account]);\\n\\n rebaseState[_account] = RebaseOptions.OptIn;\\n\\n // Delete any fixed credits per token\\n delete nonRebasingCreditsPerToken[_account];\\n emit AccountRebasingEnabled(_account);\\n }\\n\\n /**\\n * @dev Explicitly mark that an address is non-rebasing.\\n */\\n function rebaseOptOut() public nonReentrant {\\n require(!_isNonRebasingAccount(msg.sender), \\\"Account has not opted in\\\");\\n\\n // Increase non rebasing supply\\n nonRebasingSupply = nonRebasingSupply.add(balanceOf(msg.sender));\\n // Set fixed credits per token\\n nonRebasingCreditsPerToken[msg.sender] = _rebasingCreditsPerToken;\\n\\n // Decrease rebasing credits, total supply remains unchanged so no\\n // adjustment necessary\\n _rebasingCredits = _rebasingCredits.sub(_creditBalances[msg.sender]);\\n\\n // Mark explicitly opted out of rebasing\\n rebaseState[msg.sender] = RebaseOptions.OptOut;\\n emit AccountRebasingDisabled(msg.sender);\\n }\\n\\n /**\\n * @dev Modify the supply without minting new tokens. This uses a change in\\n * the exchange rate between \\\"credits\\\" and OUSD tokens to change balances.\\n * @param _newTotalSupply New total supply of OUSD.\\n */\\n function changeSupply(uint256 _newTotalSupply)\\n external\\n onlyVault\\n nonReentrant\\n {\\n require(_totalSupply > 0, \\\"Cannot increase 0 supply\\\");\\n\\n if (_totalSupply == _newTotalSupply) {\\n emit TotalSupplyUpdatedHighres(\\n _totalSupply,\\n _rebasingCredits,\\n _rebasingCreditsPerToken\\n );\\n return;\\n }\\n\\n _totalSupply = _newTotalSupply > MAX_SUPPLY\\n ? MAX_SUPPLY\\n : _newTotalSupply;\\n\\n _rebasingCreditsPerToken = _rebasingCredits.divPrecisely(\\n _totalSupply.sub(nonRebasingSupply)\\n );\\n\\n require(_rebasingCreditsPerToken > 0, \\\"Invalid change in supply\\\");\\n\\n _totalSupply = _rebasingCredits\\n .divPrecisely(_rebasingCreditsPerToken)\\n .add(nonRebasingSupply);\\n\\n emit TotalSupplyUpdatedHighres(\\n _totalSupply,\\n _rebasingCredits,\\n _rebasingCreditsPerToken\\n );\\n }\\n}\\n\",\"keccak256\":\"0x2dc66b1ba02716d64eb47dd9117fda62650d8b57669e6c351437e0ad29ad5f19\",\"license\":\"MIT\"},\"contracts/utils/Helpers.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { IBasicToken } from \\\"../interfaces/IBasicToken.sol\\\";\\n\\nlibrary Helpers {\\n /**\\n * @notice Fetch the `symbol()` from an ERC20 token\\n * @dev Grabs the `symbol()` from a contract\\n * @param _token Address of the ERC20 token\\n * @return string Symbol of the ERC20 token\\n */\\n function getSymbol(address _token) internal view returns (string memory) {\\n string memory symbol = IBasicToken(_token).symbol();\\n return symbol;\\n }\\n\\n /**\\n * @notice Fetch the `decimals()` from an ERC20 token\\n * @dev Grabs the `decimals()` from a contract and fails if\\n * the decimal value does not live within a certain range\\n * @param _token Address of the ERC20 token\\n * @return uint256 Decimals of the ERC20 token\\n */\\n function getDecimals(address _token) internal view returns (uint256) {\\n uint256 decimals = IBasicToken(_token).decimals();\\n require(\\n decimals >= 4 && decimals <= 18,\\n \\\"Token must have sufficient decimal places\\\"\\n );\\n\\n return decimals;\\n }\\n}\\n\",\"keccak256\":\"0x108b7a69e0140da0072ca18f90a03a3340574400f81aa6076cd2cccdf13699c2\",\"license\":\"MIT\"},\"contracts/utils/Initializable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Base contract any contracts that need to initialize state after deployment.\\n * @author Origin Protocol Inc\\n */\\nabstract contract Initializable {\\n /**\\n * @dev Indicates that the contract has been initialized.\\n */\\n bool private initialized;\\n\\n /**\\n * @dev Indicates that the contract is in the process of being initialized.\\n */\\n bool private initializing;\\n\\n /**\\n * @dev Modifier to protect an initializer function from being invoked twice.\\n */\\n modifier initializer() {\\n require(\\n initializing || !initialized,\\n \\\"Initializable: contract is already initialized\\\"\\n );\\n\\n bool isTopLevelCall = !initializing;\\n if (isTopLevelCall) {\\n initializing = true;\\n initialized = true;\\n }\\n\\n _;\\n\\n if (isTopLevelCall) {\\n initializing = false;\\n }\\n }\\n\\n uint256[50] private ______gap;\\n}\\n\",\"keccak256\":\"0xaadbcc138114afed4af4f353c2ced2916e6ee14be91434789187f192caf0d786\",\"license\":\"MIT\"},\"contracts/utils/InitializableERC20Detailed.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { IERC20 } from \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @dev Optional functions from the ERC20 standard.\\n * Converted from openzeppelin/contracts/token/ERC20/ERC20Detailed.sol\\n * @author Origin Protocol Inc\\n */\\nabstract contract InitializableERC20Detailed is IERC20 {\\n // Storage gap to skip storage from prior to OUSD reset\\n uint256[100] private _____gap;\\n\\n string private _name;\\n string private _symbol;\\n uint8 private _decimals;\\n\\n /**\\n * @dev Sets the values for `name`, `symbol`, and `decimals`. All three of\\n * these values are immutable: they can only be set once during\\n * construction.\\n * @notice To avoid variable shadowing appended `Arg` after arguments name.\\n */\\n function _initialize(\\n string memory nameArg,\\n string memory symbolArg,\\n uint8 decimalsArg\\n ) internal {\\n _name = nameArg;\\n _symbol = symbolArg;\\n _decimals = decimalsArg;\\n }\\n\\n /**\\n * @notice Returns the name of the token.\\n */\\n function name() public view returns (string memory) {\\n return _name;\\n }\\n\\n /**\\n * @notice Returns the symbol of the token, usually a shorter version of the\\n * name.\\n */\\n function symbol() public view returns (string memory) {\\n return _symbol;\\n }\\n\\n /**\\n * @notice Returns the number of decimals used to get its user representation.\\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\\n * be displayed to a user as `5,05` (`505 / 10 ** 2`).\\n *\\n * Tokens usually opt for a value of 18, imitating the relationship between\\n * Ether and Wei.\\n *\\n * NOTE: This information is only used for _display_ purposes: it in\\n * no way affects any of the arithmetic of the contract, including\\n * {IERC20-balanceOf} and {IERC20-transfer}.\\n */\\n function decimals() public view returns (uint8) {\\n return _decimals;\\n }\\n}\\n\",\"keccak256\":\"0xe35ac2d813a30d845a3b52bba72588d7e936c2b3f3373d15568c14db46aeed60\",\"license\":\"MIT\"},\"contracts/utils/StableMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { SafeMath } from \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\n\\n// Based on StableMath from Stability Labs Pty. Ltd.\\n// https://github.com/mstable/mStable-contracts/blob/master/contracts/shared/StableMath.sol\\n\\nlibrary StableMath {\\n using SafeMath for uint256;\\n\\n /**\\n * @dev Scaling unit for use in specific calculations,\\n * where 1 * 10**18, or 1e18 represents a unit '1'\\n */\\n uint256 private constant FULL_SCALE = 1e18;\\n\\n /***************************************\\n Helpers\\n ****************************************/\\n\\n /**\\n * @dev Adjust the scale of an integer\\n * @param to Decimals to scale to\\n * @param from Decimals to scale from\\n */\\n function scaleBy(\\n uint256 x,\\n uint256 to,\\n uint256 from\\n ) internal pure returns (uint256) {\\n if (to > from) {\\n x = x.mul(10**(to - from));\\n } else if (to < from) {\\n // slither-disable-next-line divide-before-multiply\\n x = x.div(10**(from - to));\\n }\\n return x;\\n }\\n\\n /***************************************\\n Precise Arithmetic\\n ****************************************/\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the full scale\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit\\n */\\n function mulTruncate(uint256 x, uint256 y) internal pure returns (uint256) {\\n return mulTruncateScale(x, y, FULL_SCALE);\\n }\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the given scale. For example,\\n * when calculating 90% of 10e18, (10e18 * 9e17) / 1e18 = (9e36) / 1e18 = 9e18\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @param scale Scale unit\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit\\n */\\n function mulTruncateScale(\\n uint256 x,\\n uint256 y,\\n uint256 scale\\n ) internal pure returns (uint256) {\\n // e.g. assume scale = fullScale\\n // z = 10e18 * 9e17 = 9e36\\n uint256 z = x.mul(y);\\n // return 9e36 / 1e18 = 9e18\\n return z.div(scale);\\n }\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the full scale, rounding up the result\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit, rounded up to the closest base unit.\\n */\\n function mulTruncateCeil(uint256 x, uint256 y)\\n internal\\n pure\\n returns (uint256)\\n {\\n // e.g. 8e17 * 17268172638 = 138145381104e17\\n uint256 scaled = x.mul(y);\\n // e.g. 138145381104e17 + 9.99...e17 = 138145381113.99...e17\\n uint256 ceil = scaled.add(FULL_SCALE.sub(1));\\n // e.g. 13814538111.399...e18 / 1e18 = 13814538111\\n return ceil.div(FULL_SCALE);\\n }\\n\\n /**\\n * @dev Precisely divides two units, by first scaling the left hand operand. Useful\\n * for finding percentage weightings, i.e. 8e18/10e18 = 80% (or 8e17)\\n * @param x Left hand input to division\\n * @param y Right hand input to division\\n * @return Result after multiplying the left operand by the scale, and\\n * executing the division on the right hand input.\\n */\\n function divPrecisely(uint256 x, uint256 y)\\n internal\\n pure\\n returns (uint256)\\n {\\n // e.g. 8e18 * 1e18 = 8e36\\n uint256 z = x.mul(FULL_SCALE);\\n // e.g. 8e36 / 10e18 = 8e17\\n return z.div(y);\\n }\\n}\\n\",\"keccak256\":\"0x1eb49f6f79045d9e0a8e1dced8e01d9e559e5fac554dcbb53e43140b601b04e7\",\"license\":\"MIT\"},\"contracts/vault/OETHVaultAdmin.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport { IERC20 } from \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\nimport { IStrategy } from \\\"../interfaces/IStrategy.sol\\\";\\nimport { IVault } from \\\"../interfaces/IVault.sol\\\";\\nimport { VaultAdmin } from \\\"./VaultAdmin.sol\\\";\\n\\n/**\\n * @title OETH VaultAdmin Contract\\n * @author Origin Protocol Inc\\n */\\ncontract OETHVaultAdmin is VaultAdmin {\\n using SafeERC20 for IERC20;\\n\\n address public immutable weth;\\n\\n constructor(address _weth) {\\n weth = _weth;\\n }\\n\\n /// @dev Simplified version of the deposit function as WETH is the only supported asset.\\n function _depositToStrategy(\\n address _strategyToAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) internal override {\\n require(\\n strategies[_strategyToAddress].isSupported,\\n \\\"Invalid to Strategy\\\"\\n );\\n require(\\n _assets.length == 1 && _amounts.length == 1 && _assets[0] == weth,\\n \\\"Only WETH is supported\\\"\\n );\\n\\n // Check the there is enough WETH to transfer once the WETH reserved for the withdrawal queue is accounted for\\n require(_amounts[0] <= _wethAvailable(), \\\"Not enough WETH available\\\");\\n\\n // Send required amount of funds to the strategy\\n IERC20(weth).safeTransfer(_strategyToAddress, _amounts[0]);\\n\\n // Deposit all the funds that have been sent to the strategy\\n IStrategy(_strategyToAddress).depositAll();\\n }\\n\\n function _withdrawFromStrategy(\\n address _recipient,\\n address _strategyFromAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) internal override {\\n super._withdrawFromStrategy(\\n _recipient,\\n _strategyFromAddress,\\n _assets,\\n _amounts\\n );\\n\\n IVault(address(this)).addWithdrawalQueueLiquidity();\\n }\\n\\n function _withdrawAllFromStrategy(address _strategyAddr) internal override {\\n super._withdrawAllFromStrategy(_strategyAddr);\\n\\n IVault(address(this)).addWithdrawalQueueLiquidity();\\n }\\n\\n function _withdrawAllFromStrategies() internal override {\\n super._withdrawAllFromStrategies();\\n\\n IVault(address(this)).addWithdrawalQueueLiquidity();\\n }\\n\\n // TODO move to a library?\\n function _wethAvailable() internal view returns (uint256 wethAvailable) {\\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\\n\\n // Check if the claimable WETH is less than the queued amount\\n uint256 queueShortfall = queue.queued - queue.claimable;\\n uint256 wethBalance = IERC20(weth).balanceOf(address(this));\\n // Of the claimable withdrawal requests, how much is unclaimed?\\n uint256 unclaimed = queue.claimable - queue.claimed;\\n\\n if (wethBalance > queueShortfall + unclaimed) {\\n wethAvailable = wethBalance - queueShortfall - unclaimed;\\n }\\n }\\n\\n function _swapCollateral(\\n address _fromAsset,\\n address _toAsset,\\n uint256 _fromAssetAmount,\\n uint256 _minToAssetAmount,\\n bytes calldata _data\\n ) internal override returns (uint256 toAssetAmount) {\\n require(_fromAsset != weth, \\\"swap from WETH not supported\\\");\\n require(_toAsset == weth, \\\"only swap to WETH\\\");\\n toAssetAmount = super._swapCollateral(\\n _fromAsset,\\n _toAsset,\\n _fromAssetAmount,\\n _minToAssetAmount,\\n _data\\n );\\n\\n // Add any new WETH to the withdrawal queue first\\n IVault(address(this)).addWithdrawalQueueLiquidity();\\n }\\n}\\n\",\"keccak256\":\"0x4c322850471633079ed3648094b4b3f166dbe2da6ce143edce47c999e51cbd0b\",\"license\":\"MIT\"},\"contracts/vault/VaultAdmin.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OToken VaultAdmin contract\\n * @notice The VaultAdmin contract makes configuration and admin calls on the vault.\\n * @author Origin Protocol Inc\\n */\\n\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\nimport { IOracle } from \\\"../interfaces/IOracle.sol\\\";\\nimport { ISwapper } from \\\"../interfaces/ISwapper.sol\\\";\\nimport { IVault } from \\\"../interfaces/IVault.sol\\\";\\nimport { StableMath } from \\\"../utils/StableMath.sol\\\";\\n\\nimport \\\"./VaultStorage.sol\\\";\\n\\ncontract VaultAdmin is VaultStorage {\\n using SafeERC20 for IERC20;\\n using StableMath for uint256;\\n\\n /**\\n * @dev Verifies that the caller is the Governor or Strategist.\\n */\\n modifier onlyGovernorOrStrategist() {\\n require(\\n msg.sender == strategistAddr || isGovernor(),\\n \\\"Caller is not the Strategist or Governor\\\"\\n );\\n _;\\n }\\n\\n /***************************************\\n Configuration\\n ****************************************/\\n\\n /**\\n * @notice Set address of price provider.\\n * @param _priceProvider Address of price provider\\n */\\n function setPriceProvider(address _priceProvider) external onlyGovernor {\\n priceProvider = _priceProvider;\\n emit PriceProviderUpdated(_priceProvider);\\n }\\n\\n /**\\n * @notice Set a fee in basis points to be charged for a redeem.\\n * @param _redeemFeeBps Basis point fee to be charged\\n */\\n function setRedeemFeeBps(uint256 _redeemFeeBps) external onlyGovernor {\\n require(_redeemFeeBps <= 1000, \\\"Redeem fee should not be over 10%\\\");\\n redeemFeeBps = _redeemFeeBps;\\n emit RedeemFeeUpdated(_redeemFeeBps);\\n }\\n\\n /**\\n * @notice Set a buffer of assets to keep in the Vault to handle most\\n * redemptions without needing to spend gas unwinding assets from a Strategy.\\n * @param _vaultBuffer Percentage using 18 decimals. 100% = 1e18.\\n */\\n function setVaultBuffer(uint256 _vaultBuffer)\\n external\\n onlyGovernorOrStrategist\\n {\\n require(_vaultBuffer <= 1e18, \\\"Invalid value\\\");\\n vaultBuffer = _vaultBuffer;\\n emit VaultBufferUpdated(_vaultBuffer);\\n }\\n\\n /**\\n * @notice Sets the minimum amount of OTokens in a mint to trigger an\\n * automatic allocation of funds afterwords.\\n * @param _threshold OToken amount with 18 fixed decimals.\\n */\\n function setAutoAllocateThreshold(uint256 _threshold)\\n external\\n onlyGovernor\\n {\\n autoAllocateThreshold = _threshold;\\n emit AllocateThresholdUpdated(_threshold);\\n }\\n\\n /**\\n * @notice Set a minimum amount of OTokens in a mint or redeem that triggers a\\n * rebase\\n * @param _threshold OToken amount with 18 fixed decimals.\\n */\\n function setRebaseThreshold(uint256 _threshold) external onlyGovernor {\\n rebaseThreshold = _threshold;\\n emit RebaseThresholdUpdated(_threshold);\\n }\\n\\n /**\\n * @notice Set address of Strategist\\n * @param _address Address of Strategist\\n */\\n function setStrategistAddr(address _address) external onlyGovernor {\\n strategistAddr = _address;\\n emit StrategistUpdated(_address);\\n }\\n\\n /**\\n * @notice Set the default Strategy for an asset, i.e. the one which the asset\\n will be automatically allocated to and withdrawn from\\n * @param _asset Address of the asset\\n * @param _strategy Address of the Strategy\\n */\\n function setAssetDefaultStrategy(address _asset, address _strategy)\\n external\\n onlyGovernorOrStrategist\\n {\\n emit AssetDefaultStrategyUpdated(_asset, _strategy);\\n // If its a zero address being passed for the strategy we are removing\\n // the default strategy\\n if (_strategy != address(0)) {\\n // Make sure the strategy meets some criteria\\n require(strategies[_strategy].isSupported, \\\"Strategy not approved\\\");\\n IStrategy strategy = IStrategy(_strategy);\\n require(assets[_asset].isSupported, \\\"Asset is not supported\\\");\\n require(\\n strategy.supportsAsset(_asset),\\n \\\"Asset not supported by Strategy\\\"\\n );\\n }\\n assetDefaultStrategies[_asset] = _strategy;\\n }\\n\\n /**\\n * @notice Set maximum amount of OTokens that can at any point be minted and deployed\\n * to strategy (used only by ConvexOUSDMetaStrategy for now).\\n * @param _threshold OToken amount with 18 fixed decimals.\\n */\\n function setNetOusdMintForStrategyThreshold(uint256 _threshold)\\n external\\n onlyGovernor\\n {\\n /**\\n * Because `netOusdMintedForStrategy` check in vault core works both ways\\n * (positive and negative) the actual impact of the amount of OToken minted\\n * could be double the threshold. E.g.:\\n * - contract has threshold set to 100\\n * - state of netOusdMinted is -90\\n * - in effect it can mint 190 OToken and still be within limits\\n *\\n * We are somewhat mitigating this behaviour by resetting the netOusdMinted\\n * counter whenever new threshold is set. So it can only move one threshold\\n * amount in each direction. This also enables us to reduce the threshold\\n * amount and not have problems with current netOusdMinted being near\\n * limits on either side.\\n */\\n netOusdMintedForStrategy = 0;\\n netOusdMintForStrategyThreshold = _threshold;\\n emit NetOusdMintForStrategyThresholdChanged(_threshold);\\n }\\n\\n /**\\n * @notice Set the Dripper contract that streams harvested rewards to the vault.\\n * @param _dripper Address of the Dripper contract.\\n */\\n function setDripper(address _dripper) external onlyGovernor {\\n dripper = _dripper;\\n emit DripperChanged(_dripper);\\n }\\n\\n /***************************************\\n Swaps\\n ****************************************/\\n\\n /**\\n * @notice Strategist swaps collateral assets sitting in the vault.\\n * @param _fromAsset The token address of the asset being sold by the vault.\\n * @param _toAsset The token address of the asset being purchased by the vault.\\n * @param _fromAssetAmount The amount of assets being sold by the vault.\\n * @param _minToAssetAmount The minimum amount of assets to be purchased.\\n * @param _data implementation specific data. eg 1Inch swap data\\n * @return toAssetAmount The amount of toAssets that was received from the swap\\n */\\n function swapCollateral(\\n address _fromAsset,\\n address _toAsset,\\n uint256 _fromAssetAmount,\\n uint256 _minToAssetAmount,\\n bytes calldata _data\\n )\\n external\\n nonReentrant\\n onlyGovernorOrStrategist\\n returns (uint256 toAssetAmount)\\n {\\n toAssetAmount = _swapCollateral(\\n _fromAsset,\\n _toAsset,\\n _fromAssetAmount,\\n _minToAssetAmount,\\n _data\\n );\\n }\\n\\n function _swapCollateral(\\n address _fromAsset,\\n address _toAsset,\\n uint256 _fromAssetAmount,\\n uint256 _minToAssetAmount,\\n bytes calldata _data\\n ) internal virtual returns (uint256 toAssetAmount) {\\n // Check fromAsset and toAsset are valid\\n Asset memory fromAssetConfig = assets[address(_fromAsset)];\\n Asset memory toAssetConfig = assets[_toAsset];\\n require(fromAssetConfig.isSupported, \\\"From asset is not supported\\\");\\n require(toAssetConfig.isSupported, \\\"To asset is not supported\\\");\\n\\n // Load swap config into memory to avoid separate SLOADs\\n SwapConfig memory config = swapConfig;\\n\\n // Scope a new block to remove toAssetBalBefore from the scope of swapCollateral.\\n // This avoids a stack too deep error.\\n {\\n uint256 toAssetBalBefore = IERC20(_toAsset).balanceOf(\\n address(this)\\n );\\n\\n // Transfer from assets to the swapper contract\\n IERC20(_fromAsset).safeTransfer(config.swapper, _fromAssetAmount);\\n\\n // Call to the Swapper contract to do the actual swap\\n // The -1 is required for stETH which sometimes transfers 1 wei less than what was specified.\\n // slither-disable-next-line unused-return\\n ISwapper(config.swapper).swap(\\n _fromAsset,\\n _toAsset,\\n _fromAssetAmount - 1,\\n _minToAssetAmount,\\n _data\\n );\\n\\n // Compute the change in asset balance held by the Vault\\n toAssetAmount =\\n IERC20(_toAsset).balanceOf(address(this)) -\\n toAssetBalBefore;\\n }\\n\\n // Check the to assets returned is above slippage amount specified by the strategist\\n require(\\n toAssetAmount >= _minToAssetAmount,\\n \\\"Strategist slippage limit\\\"\\n );\\n\\n // Scope a new block to remove minOracleToAssetAmount from the scope of swapCollateral.\\n // This avoids a stack too deep error.\\n {\\n // Check the slippage against the Oracle in case the strategist made a mistake or has become malicious.\\n // to asset amount = from asset amount * from asset price / to asset price\\n uint256 minOracleToAssetAmount = (_fromAssetAmount *\\n (1e4 - fromAssetConfig.allowedOracleSlippageBps) *\\n IOracle(priceProvider).price(_fromAsset)) /\\n (IOracle(priceProvider).price(_toAsset) *\\n (1e4 + toAssetConfig.allowedOracleSlippageBps));\\n\\n // Scale both sides up to 18 decimals to compare\\n require(\\n toAssetAmount.scaleBy(18, toAssetConfig.decimals) >=\\n minOracleToAssetAmount.scaleBy(\\n 18,\\n fromAssetConfig.decimals\\n ),\\n \\\"Oracle slippage limit exceeded\\\"\\n );\\n }\\n\\n // Check the vault's total value hasn't gone below the OToken total supply\\n // by more than the allowed percentage.\\n require(\\n IVault(address(this)).totalValue() >=\\n (oUSD.totalSupply() * ((1e4 - config.allowedUndervalueBps))) /\\n 1e4,\\n \\\"Allowed value < supply\\\"\\n );\\n\\n emit Swapped(_fromAsset, _toAsset, _fromAssetAmount, toAssetAmount);\\n }\\n\\n /***************************************\\n Swap Config\\n ****************************************/\\n\\n /**\\n * @notice Set the contract the performs swaps of collateral assets.\\n * @param _swapperAddr Address of the Swapper contract that implements the ISwapper interface.\\n */\\n function setSwapper(address _swapperAddr) external onlyGovernor {\\n swapConfig.swapper = _swapperAddr;\\n emit SwapperChanged(_swapperAddr);\\n }\\n\\n /// @notice Contract that swaps the vault's collateral assets\\n function swapper() external view returns (address swapper_) {\\n swapper_ = swapConfig.swapper;\\n }\\n\\n /**\\n * @notice Set max allowed percentage the vault total value can drop below the OToken total supply in basis points\\n * when executing collateral swaps.\\n * @param _basis Percentage in basis points. eg 100 == 1%\\n */\\n function setSwapAllowedUndervalue(uint16 _basis) external onlyGovernor {\\n require(_basis < 10001, \\\"Invalid basis points\\\");\\n swapConfig.allowedUndervalueBps = _basis;\\n emit SwapAllowedUndervalueChanged(_basis);\\n }\\n\\n /**\\n * @notice Max allowed percentage the vault total value can drop below the OToken total supply in basis points\\n * when executing a collateral swap.\\n * For example 100 == 1%\\n * @return value Percentage in basis points.\\n */\\n function allowedSwapUndervalue() external view returns (uint256 value) {\\n value = swapConfig.allowedUndervalueBps;\\n }\\n\\n /**\\n * @notice Set the allowed slippage from the Oracle price for collateral asset swaps.\\n * @param _asset Address of the asset token.\\n * @param _allowedOracleSlippageBps allowed slippage from Oracle in basis points. eg 20 = 0.2%. Max 10%.\\n */\\n function setOracleSlippage(address _asset, uint16 _allowedOracleSlippageBps)\\n external\\n onlyGovernor\\n {\\n require(assets[_asset].isSupported, \\\"Asset not supported\\\");\\n require(_allowedOracleSlippageBps < 1000, \\\"Slippage too high\\\");\\n\\n assets[_asset].allowedOracleSlippageBps = _allowedOracleSlippageBps;\\n\\n emit SwapSlippageChanged(_asset, _allowedOracleSlippageBps);\\n }\\n\\n /***************************************\\n Asset Config\\n ****************************************/\\n\\n /**\\n * @notice Add a supported asset to the contract, i.e. one that can be\\n * to mint OTokens.\\n * @param _asset Address of asset\\n */\\n function supportAsset(address _asset, uint8 _unitConversion)\\n external\\n onlyGovernor\\n {\\n require(!assets[_asset].isSupported, \\\"Asset already supported\\\");\\n\\n assets[_asset] = Asset({\\n isSupported: true,\\n unitConversion: UnitConversion(_unitConversion),\\n decimals: 0, // will be overridden in _cacheDecimals\\n allowedOracleSlippageBps: 0 // 0% by default\\n });\\n\\n _cacheDecimals(_asset);\\n allAssets.push(_asset);\\n\\n // Verify that our oracle supports the asset\\n // slither-disable-next-line unused-return\\n IOracle(priceProvider).price(_asset);\\n\\n emit AssetSupported(_asset);\\n }\\n\\n /**\\n * @notice Remove a supported asset from the Vault\\n * @param _asset Address of asset\\n */\\n function removeAsset(address _asset) external onlyGovernor {\\n require(assets[_asset].isSupported, \\\"Asset not supported\\\");\\n require(\\n IVault(address(this)).checkBalance(_asset) <= 1e13,\\n \\\"Vault still holds asset\\\"\\n );\\n\\n uint256 assetsCount = allAssets.length;\\n uint256 assetIndex = assetsCount; // initialize at invaid index\\n for (uint256 i = 0; i < assetsCount; ++i) {\\n if (allAssets[i] == _asset) {\\n assetIndex = i;\\n break;\\n }\\n }\\n\\n // Note: If asset is not found in `allAssets`, the following line\\n // will revert with an out-of-bound error. However, there's no\\n // reason why an asset would have `Asset.isSupported = true` but\\n // not exist in `allAssets`.\\n\\n // Update allAssets array\\n allAssets[assetIndex] = allAssets[assetsCount - 1];\\n allAssets.pop();\\n\\n // Reset default strategy\\n assetDefaultStrategies[_asset] = address(0);\\n emit AssetDefaultStrategyUpdated(_asset, address(0));\\n\\n // Remove asset from storage\\n delete assets[_asset];\\n\\n emit AssetRemoved(_asset);\\n }\\n\\n /**\\n * @notice Cache decimals on OracleRouter for a particular asset. This action\\n * is required before that asset's price can be accessed.\\n * @param _asset Address of asset token\\n */\\n function cacheDecimals(address _asset) external onlyGovernor {\\n _cacheDecimals(_asset);\\n }\\n\\n /***************************************\\n Strategy Config\\n ****************************************/\\n\\n /**\\n * @notice Add a strategy to the Vault.\\n * @param _addr Address of the strategy to add\\n */\\n function approveStrategy(address _addr) external onlyGovernor {\\n require(!strategies[_addr].isSupported, \\\"Strategy already approved\\\");\\n strategies[_addr] = Strategy({ isSupported: true, _deprecated: 0 });\\n allStrategies.push(_addr);\\n emit StrategyApproved(_addr);\\n }\\n\\n /**\\n * @notice Remove a strategy from the Vault.\\n * @param _addr Address of the strategy to remove\\n */\\n\\n function removeStrategy(address _addr) external onlyGovernor {\\n require(strategies[_addr].isSupported, \\\"Strategy not approved\\\");\\n\\n uint256 assetCount = allAssets.length;\\n for (uint256 i = 0; i < assetCount; ++i) {\\n require(\\n assetDefaultStrategies[allAssets[i]] != _addr,\\n \\\"Strategy is default for an asset\\\"\\n );\\n }\\n\\n // Initialize strategyIndex with out of bounds result so function will\\n // revert if no valid index found\\n uint256 stratCount = allStrategies.length;\\n uint256 strategyIndex = stratCount;\\n for (uint256 i = 0; i < stratCount; ++i) {\\n if (allStrategies[i] == _addr) {\\n strategyIndex = i;\\n break;\\n }\\n }\\n\\n if (strategyIndex < stratCount) {\\n allStrategies[strategyIndex] = allStrategies[stratCount - 1];\\n allStrategies.pop();\\n\\n // Mark the strategy as not supported\\n strategies[_addr].isSupported = false;\\n\\n // Withdraw all assets\\n IStrategy strategy = IStrategy(_addr);\\n strategy.withdrawAll();\\n\\n emit StrategyRemoved(_addr);\\n }\\n }\\n\\n /***************************************\\n Strategies\\n ****************************************/\\n\\n /**\\n * @notice Deposit multiple assets from the vault into the strategy.\\n * @param _strategyToAddress Address of the Strategy to deposit assets into.\\n * @param _assets Array of asset address that will be deposited into the strategy.\\n * @param _amounts Array of amounts of each corresponding asset to deposit.\\n */\\n function depositToStrategy(\\n address _strategyToAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) external onlyGovernorOrStrategist nonReentrant {\\n _depositToStrategy(_strategyToAddress, _assets, _amounts);\\n }\\n\\n function _depositToStrategy(\\n address _strategyToAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) internal virtual {\\n require(\\n strategies[_strategyToAddress].isSupported,\\n \\\"Invalid to Strategy\\\"\\n );\\n require(_assets.length == _amounts.length, \\\"Parameter length mismatch\\\");\\n\\n uint256 assetCount = _assets.length;\\n for (uint256 i = 0; i < assetCount; ++i) {\\n address assetAddr = _assets[i];\\n require(\\n IStrategy(_strategyToAddress).supportsAsset(assetAddr),\\n \\\"Asset unsupported\\\"\\n );\\n // Send required amount of funds to the strategy\\n IERC20(assetAddr).safeTransfer(_strategyToAddress, _amounts[i]);\\n }\\n\\n // Deposit all the funds that have been sent to the strategy\\n IStrategy(_strategyToAddress).depositAll();\\n }\\n\\n /**\\n * @notice Withdraw multiple assets from the strategy to the vault.\\n * @param _strategyFromAddress Address of the Strategy to withdraw assets from.\\n * @param _assets Array of asset address that will be withdrawn from the strategy.\\n * @param _amounts Array of amounts of each corresponding asset to withdraw.\\n */\\n function withdrawFromStrategy(\\n address _strategyFromAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) external onlyGovernorOrStrategist nonReentrant {\\n _withdrawFromStrategy(\\n address(this),\\n _strategyFromAddress,\\n _assets,\\n _amounts\\n );\\n }\\n\\n /**\\n * @param _recipient can either be a strategy or the Vault\\n */\\n function _withdrawFromStrategy(\\n address _recipient,\\n address _strategyFromAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) internal virtual {\\n require(\\n strategies[_strategyFromAddress].isSupported,\\n \\\"Invalid from Strategy\\\"\\n );\\n require(_assets.length == _amounts.length, \\\"Parameter length mismatch\\\");\\n\\n uint256 assetCount = _assets.length;\\n for (uint256 i = 0; i < assetCount; ++i) {\\n // Withdraw from Strategy to the recipient\\n IStrategy(_strategyFromAddress).withdraw(\\n _recipient,\\n _assets[i],\\n _amounts[i]\\n );\\n }\\n }\\n\\n /**\\n * @notice Sets the maximum allowable difference between\\n * total supply and backing assets' value.\\n */\\n function setMaxSupplyDiff(uint256 _maxSupplyDiff) external onlyGovernor {\\n maxSupplyDiff = _maxSupplyDiff;\\n emit MaxSupplyDiffChanged(_maxSupplyDiff);\\n }\\n\\n /**\\n * @notice Sets the trusteeAddress that can receive a portion of yield.\\n * Setting to the zero address disables this feature.\\n */\\n function setTrusteeAddress(address _address) external onlyGovernor {\\n trusteeAddress = _address;\\n emit TrusteeAddressChanged(_address);\\n }\\n\\n /**\\n * @notice Sets the TrusteeFeeBps to the percentage of yield that should be\\n * received in basis points.\\n */\\n function setTrusteeFeeBps(uint256 _basis) external onlyGovernor {\\n require(_basis <= 5000, \\\"basis cannot exceed 50%\\\");\\n trusteeFeeBps = _basis;\\n emit TrusteeFeeBpsChanged(_basis);\\n }\\n\\n /**\\n * @notice Set OToken Metapool strategy\\n * @param _ousdMetaStrategy Address of OToken metapool strategy\\n */\\n function setOusdMetaStrategy(address _ousdMetaStrategy)\\n external\\n onlyGovernor\\n {\\n ousdMetaStrategy = _ousdMetaStrategy;\\n emit OusdMetaStrategyUpdated(_ousdMetaStrategy);\\n }\\n\\n /***************************************\\n Pause\\n ****************************************/\\n\\n /**\\n * @notice Set the deposit paused flag to true to prevent rebasing.\\n */\\n function pauseRebase() external onlyGovernorOrStrategist {\\n rebasePaused = true;\\n emit RebasePaused();\\n }\\n\\n /**\\n * @notice Set the deposit paused flag to true to allow rebasing.\\n */\\n function unpauseRebase() external onlyGovernorOrStrategist {\\n rebasePaused = false;\\n emit RebaseUnpaused();\\n }\\n\\n /**\\n * @notice Set the deposit paused flag to true to prevent capital movement.\\n */\\n function pauseCapital() external onlyGovernorOrStrategist {\\n capitalPaused = true;\\n emit CapitalPaused();\\n }\\n\\n /**\\n * @notice Set the deposit paused flag to false to enable capital movement.\\n */\\n function unpauseCapital() external onlyGovernorOrStrategist {\\n capitalPaused = false;\\n emit CapitalUnpaused();\\n }\\n\\n /***************************************\\n Utils\\n ****************************************/\\n\\n /**\\n * @notice Transfer token to governor. Intended for recovering tokens stuck in\\n * contract, i.e. mistaken sends.\\n * @param _asset Address for the asset\\n * @param _amount Amount of the asset to transfer\\n */\\n function transferToken(address _asset, uint256 _amount)\\n external\\n onlyGovernor\\n {\\n require(!assets[_asset].isSupported, \\\"Only unsupported assets\\\");\\n IERC20(_asset).safeTransfer(governor(), _amount);\\n }\\n\\n /***************************************\\n Strategies Admin\\n ****************************************/\\n\\n /**\\n * @notice Withdraws all assets from the strategy and sends assets to the Vault.\\n * @param _strategyAddr Strategy address.\\n */\\n function withdrawAllFromStrategy(address _strategyAddr)\\n external\\n onlyGovernorOrStrategist\\n {\\n _withdrawAllFromStrategy(_strategyAddr);\\n }\\n\\n function _withdrawAllFromStrategy(address _strategyAddr) internal virtual {\\n require(\\n strategies[_strategyAddr].isSupported,\\n \\\"Strategy is not supported\\\"\\n );\\n IStrategy strategy = IStrategy(_strategyAddr);\\n strategy.withdrawAll();\\n }\\n\\n /**\\n * @notice Withdraws all assets from all the strategies and sends assets to the Vault.\\n */\\n function withdrawAllFromStrategies() external onlyGovernorOrStrategist {\\n _withdrawAllFromStrategies();\\n }\\n\\n function _withdrawAllFromStrategies() internal virtual {\\n uint256 stratCount = allStrategies.length;\\n for (uint256 i = 0; i < stratCount; ++i) {\\n IStrategy(allStrategies[i]).withdrawAll();\\n }\\n }\\n\\n /***************************************\\n Utils\\n ****************************************/\\n\\n function _cacheDecimals(address token) internal {\\n Asset storage tokenAsset = assets[token];\\n if (tokenAsset.decimals != 0) {\\n return;\\n }\\n uint8 decimals = IBasicToken(token).decimals();\\n require(decimals >= 6 && decimals <= 18, \\\"Unexpected precision\\\");\\n tokenAsset.decimals = decimals;\\n }\\n}\\n\",\"keccak256\":\"0xc4daad97bdcc4d62e7cf595301c949195d989739dd108f2e3dfefd3f96624762\",\"license\":\"MIT\"},\"contracts/vault/VaultStorage.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OToken VaultStorage contract\\n * @notice The VaultStorage contract defines the storage for the Vault contracts\\n * @author Origin Protocol Inc\\n */\\n\\nimport { IERC20 } from \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport { Address } from \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport { IStrategy } from \\\"../interfaces/IStrategy.sol\\\";\\nimport { Governable } from \\\"../governance/Governable.sol\\\";\\nimport { OUSD } from \\\"../token/OUSD.sol\\\";\\nimport { Initializable } from \\\"../utils/Initializable.sol\\\";\\nimport \\\"../utils/Helpers.sol\\\";\\n\\ncontract VaultStorage is Initializable, Governable {\\n using SafeERC20 for IERC20;\\n\\n event AssetSupported(address _asset);\\n event AssetRemoved(address _asset);\\n event AssetDefaultStrategyUpdated(address _asset, address _strategy);\\n event AssetAllocated(address _asset, address _strategy, uint256 _amount);\\n event StrategyApproved(address _addr);\\n event StrategyRemoved(address _addr);\\n event Mint(address _addr, uint256 _value);\\n event Redeem(address _addr, uint256 _value);\\n event CapitalPaused();\\n event CapitalUnpaused();\\n event RebasePaused();\\n event RebaseUnpaused();\\n event VaultBufferUpdated(uint256 _vaultBuffer);\\n event OusdMetaStrategyUpdated(address _ousdMetaStrategy);\\n event RedeemFeeUpdated(uint256 _redeemFeeBps);\\n event PriceProviderUpdated(address _priceProvider);\\n event AllocateThresholdUpdated(uint256 _threshold);\\n event RebaseThresholdUpdated(uint256 _threshold);\\n event StrategistUpdated(address _address);\\n event MaxSupplyDiffChanged(uint256 maxSupplyDiff);\\n event YieldDistribution(address _to, uint256 _yield, uint256 _fee);\\n event TrusteeFeeBpsChanged(uint256 _basis);\\n event TrusteeAddressChanged(address _address);\\n event NetOusdMintForStrategyThresholdChanged(uint256 _threshold);\\n event SwapperChanged(address _address);\\n event SwapAllowedUndervalueChanged(uint256 _basis);\\n event SwapSlippageChanged(address _asset, uint256 _basis);\\n event Swapped(\\n address indexed _fromAsset,\\n address indexed _toAsset,\\n uint256 _fromAssetAmount,\\n uint256 _toAssetAmount\\n );\\n event DripperChanged(address indexed _dripper);\\n event WithdrawalRequested(\\n address indexed _withdrawer,\\n uint256 indexed _requestId,\\n uint256 _amount,\\n uint256 _queued\\n );\\n event WithdrawalClaimed(\\n address indexed _withdrawer,\\n uint256 indexed _requestId,\\n uint256 _amount\\n );\\n event WithdrawalClaimable(uint256 _claimable, uint256 _newClaimable);\\n\\n // Assets supported by the Vault, i.e. Stablecoins\\n enum UnitConversion {\\n DECIMALS,\\n GETEXCHANGERATE\\n }\\n // Changed to fit into a single storage slot so the decimals needs to be recached\\n struct Asset {\\n // Note: OETHVaultCore doesn't use `isSupported` when minting,\\n // redeeming or checking balance of assets.\\n bool isSupported;\\n UnitConversion unitConversion;\\n uint8 decimals;\\n // Max allowed slippage from the Oracle price when swapping collateral assets in basis points.\\n // For example 40 == 0.4% slippage\\n uint16 allowedOracleSlippageBps;\\n }\\n\\n /// @dev mapping of supported vault assets to their configuration\\n // slither-disable-next-line uninitialized-state\\n mapping(address => Asset) internal assets;\\n /// @dev list of all assets supported by the vault.\\n // slither-disable-next-line uninitialized-state\\n address[] internal allAssets;\\n\\n // Strategies approved for use by the Vault\\n struct Strategy {\\n bool isSupported;\\n uint256 _deprecated; // Deprecated storage slot\\n }\\n /// @dev mapping of strategy contracts to their configuration\\n mapping(address => Strategy) internal strategies;\\n /// @dev list of all vault strategies\\n address[] internal allStrategies;\\n\\n /// @notice Address of the Oracle price provider contract\\n // slither-disable-next-line uninitialized-state\\n address public priceProvider;\\n /// @notice pause rebasing if true\\n bool public rebasePaused = false;\\n /// @notice pause operations that change the OToken supply.\\n /// eg mint, redeem, allocate, mint/burn for strategy\\n bool public capitalPaused = true;\\n /// @notice Redemption fee in basis points. eg 50 = 0.5%\\n uint256 public redeemFeeBps;\\n /// @notice Percentage of assets to keep in Vault to handle (most) withdrawals. 100% = 1e18.\\n uint256 public vaultBuffer;\\n /// @notice OToken mints over this amount automatically allocate funds. 18 decimals.\\n uint256 public autoAllocateThreshold;\\n /// @notice OToken mints over this amount automatically rebase. 18 decimals.\\n uint256 public rebaseThreshold;\\n\\n /// @dev Address of the OToken token. eg OUSD or OETH.\\n // slither-disable-next-line uninitialized-state\\n OUSD internal oUSD;\\n\\n //keccak256(\\\"OUSD.vault.governor.admin.impl\\\");\\n bytes32 constant adminImplPosition =\\n 0xa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd9;\\n\\n // Address of the contract responsible for post rebase syncs with AMMs\\n address private _deprecated_rebaseHooksAddr = address(0);\\n\\n // Deprecated: Address of Uniswap\\n // slither-disable-next-line constable-states\\n address private _deprecated_uniswapAddr = address(0);\\n\\n /// @notice Address of the Strategist\\n address public strategistAddr = address(0);\\n\\n /// @notice Mapping of asset address to the Strategy that they should automatically\\n // be allocated to\\n // slither-disable-next-line uninitialized-state\\n mapping(address => address) public assetDefaultStrategies;\\n\\n /// @notice Max difference between total supply and total value of assets. 18 decimals.\\n // slither-disable-next-line uninitialized-state\\n uint256 public maxSupplyDiff;\\n\\n /// @notice Trustee contract that can collect a percentage of yield\\n address public trusteeAddress;\\n\\n /// @notice Amount of yield collected in basis points. eg 2000 = 20%\\n uint256 public trusteeFeeBps;\\n\\n /// @dev Deprecated: Tokens that should be swapped for stablecoins\\n address[] private _deprecated_swapTokens;\\n\\n uint256 constant MINT_MINIMUM_UNIT_PRICE = 0.998e18;\\n\\n /// @notice Metapool strategy that is allowed to mint/burn OTokens without changing collateral\\n address public ousdMetaStrategy = address(0);\\n\\n /// @notice How much OTokens are currently minted by the strategy\\n int256 public netOusdMintedForStrategy = 0;\\n\\n /// @notice How much net total OTokens are allowed to be minted by all strategies\\n uint256 public netOusdMintForStrategyThreshold = 0;\\n\\n uint256 constant MIN_UNIT_PRICE_DRIFT = 0.7e18;\\n uint256 constant MAX_UNIT_PRICE_DRIFT = 1.3e18;\\n\\n /// @notice Collateral swap configuration.\\n /// @dev is packed into a single storage slot to save gas.\\n struct SwapConfig {\\n // Contract that swaps the vault's collateral assets\\n address swapper;\\n // Max allowed percentage the total value can drop below the total supply in basis points.\\n // For example 100 == 1%\\n uint16 allowedUndervalueBps;\\n }\\n SwapConfig internal swapConfig = SwapConfig(address(0), 0);\\n\\n /// @notice Address of the Dripper contract that streams harvested rewards to the Vault\\n /// @dev The vault is proxied so needs to be set with setDripper against the proxy contract.\\n // slither-disable-start constable-states\\n // slither-disable-next-line uninitialized-state\\n address public dripper;\\n // slither-disable-end constable-states\\n\\n /// Withdrawal Queue Storage /////\\n\\n struct WithdrawalQueueMetadata {\\n // cumulative total of all withdrawal requests included the ones that have already been claimed\\n uint128 queued;\\n // cumulative total of all the requests that can be claimed included the ones that have already been claimed\\n uint128 claimable;\\n // total of all the requests that have been claimed\\n uint128 claimed;\\n // index of the next withdrawal request starting at 0\\n uint128 nextWithdrawalIndex;\\n }\\n\\n // slither-disable-next-line uninitialized-state\\n WithdrawalQueueMetadata public withdrawalQueueMetadata;\\n\\n struct WithdrawalRequest {\\n address withdrawer;\\n bool claimed;\\n // Amount of oTokens to redeem\\n uint128 amount;\\n // cumulative total of all withdrawal requests including this one.\\n // this request can be claimed when this queued amount is less than or equal to the queue's claimable amount.\\n uint128 queued;\\n }\\n\\n // Mapping of withdrawal requests indexes to the user withdrawal request data\\n mapping(uint256 => WithdrawalRequest) public withdrawalRequests;\\n\\n // For future use\\n uint256[46] private __gap;\\n\\n /**\\n * @notice set the implementation for the admin, this needs to be in a base class else we cannot set it\\n * @param newImpl address of the implementation\\n */\\n function setAdminImpl(address newImpl) external onlyGovernor {\\n require(\\n Address.isContract(newImpl),\\n \\\"new implementation is not a contract\\\"\\n );\\n bytes32 position = adminImplPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, newImpl)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xe13565f58d63805320aa4aac336b294fa6b6e55b028a6727510bf99764ebce14\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x6037805461ffff60a01b1916600160a81b179055603d80546001600160a01b0319908116909155603e805482169055603f80548216905560458054909116905560006046819055604781905560e060405260a081905260c052604880546001600160b01b03191690553480156200007557600080fd5b50604051620041c1380380620041c183398101604081905262000098916200010e565b620000b033600080516020620041a183398151915255565b600080516020620041a1833981519152546040516001600160a01b03909116906000907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a360601b6001600160601b03191660805262000140565b6000602082840312156200012157600080fd5b81516001600160a01b03811681146200013957600080fd5b9392505050565b60805160601c61401f62000182600039600081816105080152818161251b0152818161259d01528181612814015281816129440152613415015261401f6000f3fe608060405234801561001057600080fd5b50600436106103835760003560e01c8063636e6c40116101de578063ae69f3cb1161010f578063c9919112116100ad578063e6cc54321161007c578063e6cc5432146107f8578063e829cc161461080c578063eb03654b1461081f578063fc0cfeee1461083257600080fd5b8063c9919112146107c1578063d38bfff4146107c9578063d58e3b3a146107dc578063e45cc9f0146107ef57600080fd5b8063b890ebf6116100e9578063b890ebf61461078b578063bc90106b1461079e578063c5f00841146107b1578063c7af3352146107b957600080fd5b8063ae69f3cb14610752578063b2c9336d14610765578063b888879e1461077857600080fd5b80638e510b521161017c57806394828ffd1161015657806394828ffd146107055780639c82f2a41461070d5780639fa1826e14610720578063a403e4d51461072957600080fd5b80638e510b521461065f5780638ec489a214610668578063937b25811461067b57600080fd5b8063773540b3116101b8578063773540b31461061d5780637a2202f3146106305780637b9a709614610639578063840c4c7a1461064c57600080fd5b8063636e6c40146105e4578063663e64ce146105f75780636c7561e81461060a57600080fd5b8063372aa224116102b857806350ba711c11610256578063570d8e1d11610230578063570d8e1d146105a3578063597c8910146105b65780635d36b190146105c9578063603ea03b146105d157600080fd5b806350ba711c1461056357806352d38e5d1461057657806353ca9f241461057f57600080fd5b80633fc8cef3116102925780633fc8cef31461050357806349c1d54d1461052a5780634a5e42b11461053d5780634bed3bc01461055057600080fd5b8063372aa224146104d55780633b8ae397146104e85780633dbc911f146104fb57600080fd5b80631edfe3da116103255780632da845a8116102ff5780632da845a81461043d5780632e9958ab14610450578063362bd1a31461046357806336b6d944146104c257600080fd5b80631edfe3da1461041a578063207134b0146104235780632b3297f91461042c57600080fd5b80630c340a24116103615780630c340a24146103c15780631072cbea146103e1578063175188e8146103f457806318ce56bd1461040757600080fd5b806309f49bf51461038857806309f6442c146103925780630acbda75146103ae575b600080fd5b610390610845565b005b61039b60385481565b6040519081526020015b60405180910390f35b6103906103bc366004613bb6565b6108be565b6103c9610970565b6040516001600160a01b0390911681526020016103a5565b6103906103ef366004613b18565b61098d565b610390610402366004613979565b610a3a565b6045546103c9906001600160a01b031681565b61039b60395481565b61039b60435481565b6048546001600160a01b03166103c9565b61039061044b366004613979565b610d3b565b61039061045e366004613979565b610dad565b604a54604b5461048f916001600160801b0380821692600160801b928390048216928183169291041684565b604080516001600160801b03958616815293851660208501529184169183019190915290911660608201526080016103a5565b6103906104d0366004613979565b610e1b565b6103906104e3366004613979565b610e4b565b6103906104f6366004613979565b610ebd565b610390610ffa565b6103c97f000000000000000000000000000000000000000000000000000000000000000081565b6042546103c9906001600160a01b031681565b61039061054b366004613979565b611070565b604854600160a01b900461ffff1661039b565b61039b6105713660046139c7565b61137d565b61039b603b5481565b60375461059390600160a01b900460ff1681565b60405190151581526020016103a5565b603f546103c9906001600160a01b031681565b6103906105c4366004613979565b611420565b610390611461565b6049546103c9906001600160a01b031681565b6103906105f2366004613bb6565b611507565b610390610605366004613bb6565b611565565b610390610618366004613b42565b6115be565b61039061062b366004613979565b61183c565b61039b60475481565b610390610647366004613aee565b6118ae565b61039061065a366004613a6d565b6119e4565b61039b60415481565b610390610676366004613bb6565b611a7d565b6106cc610689366004613bb6565b604c60205260009081526040902080546001909101546001600160a01b03821691600160a01b900460ff16906001600160801b0380821691600160801b90041684565b604080516001600160a01b03909516855292151560208501526001600160801b03918216928401929092521660608201526080016103a5565b610390611b32565b61039061071b366004613979565b611ba2565b61039b603a5481565b6103c9610737366004613979565b6040602081905260009182529020546001600160a01b031681565b610390610760366004613a6d565b611c14565b610390610773366004613bb6565b611ca2565b6037546103c9906001600160a01b031681565b610390610799366004613bb6565b611cfb565b6103906107ac366004613994565b611d54565b610390611f96565b61059361200c565b61039061203d565b6103906107d7366004613979565b61207d565b6103906107ea366004613979565b612121565b61039b60465481565b60375461059390600160a81b900460ff1681565b61039061081a366004613b9b565b612193565b61039061082d366004613bb6565b612253565b610390610840366004613979565b612308565b603f546001600160a01b0316331480610861575061086161200c565b6108865760405162461bcd60e51b815260040161087d90613ce7565b60405180910390fd5b6037805460ff60a01b191690556040517fbc044409505c95b6b851433df96e1beae715c909d8e7c1d6d7ab783300d4e3b990600090a1565b6108c661200c565b6108e25760405162461bcd60e51b815260040161087d90613cb0565b6113888111156109345760405162461bcd60e51b815260206004820152601760248201527f62617369732063616e6e6f742065786365656420353025000000000000000000604482015260640161087d565b60438190556040518181527f56287a45051933ea374811b3d5d165033047be5572cac676f7c28b8be4f746c7906020015b60405180910390a150565b6000610988600080516020613fca8339815191525490565b905090565b61099561200c565b6109b15760405162461bcd60e51b815260040161087d90613cb0565b6001600160a01b03821660009081526033602052604090205460ff1615610a1a5760405162461bcd60e51b815260206004820152601760248201527f4f6e6c7920756e737570706f7274656420617373657473000000000000000000604482015260640161087d565b610a36610a25610970565b6001600160a01b03841690836123aa565b5050565b610a4261200c565b610a5e5760405162461bcd60e51b815260040161087d90613cb0565b6001600160a01b03811660009081526035602052604090205460ff16610abe5760405162461bcd60e51b815260206004820152601560248201527414dd1c985d1959de481b9bdd08185c1c1c9bdd9959605a1b604482015260640161087d565b60345460005b81811015610b7657826001600160a01b03166040600060348481548110610aed57610aed613fa4565b60009182526020808320909101546001600160a01b039081168452908301939093526040909101902054161415610b665760405162461bcd60e51b815260206004820181905260248201527f53747261746567792069732064656661756c7420666f7220616e206173736574604482015260640161087d565b610b6f81613f47565b9050610ac4565b506036548060005b82811015610bd657846001600160a01b031660368281548110610ba357610ba3613fa4565b6000918252602090912001546001600160a01b03161415610bc657809150610bd6565b610bcf81613f47565b9050610b7e565b5081811015610d35576036610bec600184613f04565b81548110610bfc57610bfc613fa4565b600091825260209091200154603680546001600160a01b039092169183908110610c2857610c28613fa4565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506036805480610c6757610c67613f8e565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b03861680835260359091526040808320805460ff19169055805163429c145b60e11b81529051879363853828b6926004808201939182900301818387803b158015610cde57600080fd5b505af1158015610cf2573d6000803e3d6000fd5b50506040516001600160a01b03881681527f09a1db4b80c32706328728508c941a6b954f31eb5affd32f236c1fd405f8fea49250602001905060405180910390a1505b50505050565b610d4361200c565b610d5f5760405162461bcd60e51b815260040161087d90613cb0565b604280546001600160a01b0319166001600160a01b0383169081179091556040519081527f1e4af5ac389e8cde1bdaa6830881b6c987c62a45cfb3b33d27d805cde3b5775090602001610965565b610db561200c565b610dd15760405162461bcd60e51b815260040161087d90613cb0565b604980546001600160a01b0319166001600160a01b0383169081179091556040517faf2910d9759321733de15af1827a49830692912adeb2b3646334861f2cd2eed490600090a250565b610e2361200c565b610e3f5760405162461bcd60e51b815260040161087d90613cb0565b610e4881612401565b50565b610e5361200c565b610e6f5760405162461bcd60e51b815260040161087d90613cb0565b603780546001600160a01b0319166001600160a01b0383169081179091556040519081527fb266add5f3044b17d27db796af992cecbe413921b4e8aaaee03c719e16b9806a90602001610965565b610ec561200c565b610ee15760405162461bcd60e51b815260040161087d90613cb0565b6001600160a01b03811660009081526035602052604090205460ff1615610f4a5760405162461bcd60e51b815260206004820152601960248201527f537472617465677920616c726561647920617070726f76656400000000000000604482015260640161087d565b6040805180820182526001808252600060208084018281526001600160a01b038716808452603583528684209551865460ff19169015151786559051948401949094556036805493840181559091527f4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b890910180546001600160a01b0319168317905591519081527f960dd94cbb79169f09a4e445d58b895df2d9bffa5b31055d0932d801724a20d19101610965565b603f546001600160a01b0316331480611016575061101661200c565b6110325760405162461bcd60e51b815260040161087d90613ce7565b6037805460ff60a81b1916600160a81b1790556040517f71f0e5b62f846a22e0b4d159e516e62fa9c2b8eb570be15f83e67d98a2ee51e090600090a1565b61107861200c565b6110945760405162461bcd60e51b815260040161087d90613cb0565b6001600160a01b03811660009081526033602052604090205460ff166110f25760405162461bcd60e51b8152602060048201526013602482015272105cdcd95d081b9bdd081cdd5c1c1bdc9d1959606a1b604482015260640161087d565b604051632fa8a91360e11b81526001600160a01b03821660048201526509184e72a000903090635f5152269060240160206040518083038186803b15801561113957600080fd5b505afa15801561114d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111719190613bcf565b11156111bf5760405162461bcd60e51b815260206004820152601760248201527f5661756c74207374696c6c20686f6c6473206173736574000000000000000000604482015260640161087d565b6034548060005b8281101561121e57836001600160a01b0316603482815481106111eb576111eb613fa4565b6000918252602090912001546001600160a01b0316141561120e5780915061121e565b61121781613f47565b90506111c6565b50603461122c600184613f04565b8154811061123c5761123c613fa4565b600091825260209091200154603480546001600160a01b03909216918390811061126857611268613fa4565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060348054806112a7576112a7613f8e565b60008281526020808220600019908401810180546001600160a01b031990811690915593019093556001600160a01b038616808252604080855280832080549094169093558251908152928301527fba58ce12801c949fa65f41c46ed108671c219baf945fa48d21026cea99ff252a910160405180910390a16001600160a01b038316600081815260336020908152604091829020805464ffffffffff1916905590519182527f37803e2125c48ee96c38ddf04e826daf335b0e1603579040fd275aba6d06b6fc910160405180910390a1505050565b7f53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac453580546000919060028114156113c55760405162461bcd60e51b815260040161087d90613d2f565b60028255603f546001600160a01b03163314806113e557506113e561200c565b6114015760405162461bcd60e51b815260040161087d90613ce7565b61140f898989898989612517565b600190925550979650505050505050565b603f546001600160a01b031633148061143c575061143c61200c565b6114585760405162461bcd60e51b815260040161087d90613ce7565b610e488161267d565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b0316146114fc5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b606482015260840161087d565b611505336126dc565b565b61150f61200c565b61152b5760405162461bcd60e51b815260040161087d90613cb0565b600060465560478190556040518181527fc29d6fedbc6bdf267a08166c2b976fbd72aca5d6a769528616f8b9224c8f197f90602001610965565b61156d61200c565b6115895760405162461bcd60e51b815260040161087d90613cb0565b60418190556040518181527f95201f9c21f26877223b1ff4073936a6484c35495649e60e55730497aeb60d9390602001610965565b6115c661200c565b6115e25760405162461bcd60e51b815260040161087d90613cb0565b6001600160a01b03821660009081526033602052604090205460ff161561164b5760405162461bcd60e51b815260206004820152601760248201527f417373657420616c726561647920737570706f72746564000000000000000000604482015260640161087d565b60405180608001604052806001151581526020018260ff16600181111561167457611674613f78565b600181111561168557611685613f78565b81526000602080830182905260409283018290526001600160a01b0386168252603381529190208251815490151560ff19821681178355928401519192839161ff001990911661ffff19909116176101008360018111156116e8576116e8613f78565b02179055506040820151815460609093015161ffff1663010000000264ffff0000001960ff90921662010000029190911664ffffff0000199093169290921791909117905561173682612401565b603480546001810182556000919091527f46bddb1178e94d7f2892ff5f366840eb658911794f2c3a44c450aa2c505186c10180546001600160a01b0319166001600160a01b038481169182179092556037546040516315d5220f60e31b815260048101929092529091169063aea910789060240160206040518083038186803b1580156117c257600080fd5b505afa1580156117d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117fa9190613bcf565b506040516001600160a01b03831681527f4f1ac48525e50059cc1cc6e0e1940ece0dd653a4db4841538d6aef036be2fb7b906020015b60405180910390a15050565b61184461200c565b6118605760405162461bcd60e51b815260040161087d90613cb0565b603f80546001600160a01b0319166001600160a01b0383169081179091556040519081527f869e0abd13cc3a975de7b93be3df1cb2255c802b1cead85963cc79d99f131bee90602001610965565b6118b661200c565b6118d25760405162461bcd60e51b815260040161087d90613cb0565b6001600160a01b03821660009081526033602052604090205460ff166119305760405162461bcd60e51b8152602060048201526013602482015272105cdcd95d081b9bdd081cdd5c1c1bdc9d1959606a1b604482015260640161087d565b6103e88161ffff16106119795760405162461bcd60e51b81526020600482015260116024820152700a6d8d2e0e0c2ceca40e8dede40d0d2ced607b1b604482015260640161087d565b6001600160a01b038216600081815260336020908152604091829020805464ffff0000001916630100000061ffff8716908102919091179091558251938452908301527f8d22e9d2cbe8bb65a3c4412bd8970743864512a1a0e004e8d00fb96277b78b949101611830565b603f546001600160a01b0316331480611a005750611a0061200c565b611a1c5760405162461bcd60e51b815260040161087d90613ce7565b7f53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac453580546002811415611a605760405162461bcd60e51b815260040161087d90613d2f565b60028255611a71878787878761279d565b50600190555050505050565b603f546001600160a01b0316331480611a995750611a9961200c565b611ab55760405162461bcd60e51b815260040161087d90613ce7565b670de0b6b3a7640000811115611afd5760405162461bcd60e51b815260206004820152600d60248201526c496e76616c69642076616c756560981b604482015260640161087d565b60398190556040518181527f41ecb23a0e7865b25f38c268b7c3012220d822929e9edff07326e89d5bb822b590602001610965565b603f546001600160a01b0316331480611b4e5750611b4e61200c565b611b6a5760405162461bcd60e51b815260040161087d90613ce7565b6037805460ff60a81b191690556040517f891ebab18da80ebeeea06b1b1cede098329c4c008906a98370c2ac7a80b571cb90600090a1565b611baa61200c565b611bc65760405162461bcd60e51b815260040161087d90613cb0565b604880546001600160a01b0319166001600160a01b0383169081179091556040519081527f7d7719313229e558c5a3893cad2eb86a86a049156d1d9ebd5c63a8eedefd1c0390602001610965565b603f546001600160a01b0316331480611c305750611c3061200c565b611c4c5760405162461bcd60e51b815260040161087d90613ce7565b7f53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac453580546002811415611c905760405162461bcd60e51b815260040161087d90613d2f565b60028255611a713088888888886129d5565b611caa61200c565b611cc65760405162461bcd60e51b815260040161087d90613cb0565b603a8190556040518181527f2ec5fb5a3d2703edc461252d92ccd2799c3c74f01d97212b20388207fa17ae4590602001610965565b611d0361200c565b611d1f5760405162461bcd60e51b815260040161087d90613cb0565b603b8190556040518181527f39367850377ac04920a9a670f2180e7a94d83b15ad302e59875ec58fd10bd37d90602001610965565b603f546001600160a01b0316331480611d705750611d7061200c565b611d8c5760405162461bcd60e51b815260040161087d90613ce7565b604080516001600160a01b038085168252831660208201527fba58ce12801c949fa65f41c46ed108671c219baf945fa48d21026cea99ff252a910160405180910390a16001600160a01b03811615611f68576001600160a01b03811660009081526035602052604090205460ff16611e3e5760405162461bcd60e51b815260206004820152601560248201527414dd1c985d1959de481b9bdd08185c1c1c9bdd9959605a1b604482015260640161087d565b6001600160a01b038216600090815260336020526040902054819060ff16611ea15760405162461bcd60e51b8152602060048201526016602482015275105cdcd95d081a5cc81b9bdd081cdd5c1c1bdc9d195960521b604482015260640161087d565b60405163551c457b60e11b81526001600160a01b03848116600483015282169063aa388af69060240160206040518083038186803b158015611ee257600080fd5b505afa158015611ef6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f1a9190613b79565b611f665760405162461bcd60e51b815260206004820152601f60248201527f4173736574206e6f7420737570706f7274656420627920537472617465677900604482015260640161087d565b505b6001600160a01b03918216600090815260406020819052902080546001600160a01b03191691909216179055565b603f546001600160a01b0316331480611fb25750611fb261200c565b611fce5760405162461bcd60e51b815260040161087d90613ce7565b6037805460ff60a01b1916600160a01b1790556040517f8cff26a5985614b3d30629cc4ab83824bf115aec971b718d8f2f99562032e97290600090a1565b6000612024600080516020613fca8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b603f546001600160a01b0316331480612059575061205961200c565b6120755760405162461bcd60e51b815260040161087d90613ce7565b611505612a3e565b61208561200c565b6120a15760405162461bcd60e51b815260040161087d90613cb0565b6120c9817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166120e9600080516020613fca8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b61212961200c565b6121455760405162461bcd60e51b815260040161087d90613cb0565b604580546001600160a01b0319166001600160a01b0383169081179091556040519081527fa12850fb726e0b2b7b3c9a9342031e1268a8148d0eb06b4bea8613204ffcd2b890602001610965565b61219b61200c565b6121b75760405162461bcd60e51b815260040161087d90613cb0565b6127118161ffff16106122035760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420626173697320706f696e747360601b604482015260640161087d565b6048805461ffff60a01b1916600160a01b61ffff8416908102919091179091556040519081527ff12c00256bee2b6facb111a88a9b1cff86e79132939b44f1353212d6f746955790602001610965565b61225b61200c565b6122775760405162461bcd60e51b815260040161087d90613cb0565b6103e88111156122d35760405162461bcd60e51b815260206004820152602160248201527f52656465656d206665652073686f756c64206e6f74206265206f7665722031306044820152602560f81b606482015260840161087d565b60388190556040518181527fd6c7508d6658ccee36b7b7d7fd72e5cbaeefb40c64eff24e9ae7470e846304ee90602001610965565b61231061200c565b61232c5760405162461bcd60e51b815260040161087d90613cb0565b803b6123865760405162461bcd60e51b8152602060048201526024808201527f6e657720696d706c656d656e746174696f6e206973206e6f74206120636f6e746044820152631c9858dd60e21b606482015260840161087d565b7fa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd955565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526123fc908490612a95565b505050565b6001600160a01b0381166000908152603360205260409020805462010000900460ff161561242d575050565b6000826001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b15801561246857600080fd5b505afa15801561247c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124a09190613be8565b905060068160ff16101580156124ba575060128160ff1611155b6124fd5760405162461bcd60e51b81526020600482015260146024820152732ab732bc3832b1ba32b210383932b1b4b9b4b7b760611b604482015260640161087d565b815460ff909116620100000262ff00001990911617905550565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316876001600160a01b0316141561259b5760405162461bcd60e51b815260206004820152601c60248201527f737761702066726f6d2057455448206e6f7420737570706f7274656400000000604482015260640161087d565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316866001600160a01b0316146126105760405162461bcd60e51b81526020600482015260116024820152700dedcd8f240e6eec2e040e8de40ae8aa89607b1b604482015260640161087d565b61261e878787878787612b67565b9050306001600160a01b031663b9b17f9f6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561265b57600080fd5b505af115801561266f573d6000803e3d6000fd5b505050509695505050505050565b612686816132d1565b306001600160a01b031663b9b17f9f6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156126c157600080fd5b505af11580156126d5573d6000803e3d6000fd5b5050505050565b6001600160a01b0381166127325760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f722069732061646472657373283029000000000000604482015260640161087d565b806001600160a01b0316612752600080516020613fca8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a3610e4881600080516020613fca83398151915255565b6001600160a01b03851660009081526035602052604090205460ff166127fb5760405162461bcd60e51b8152602060048201526013602482015272496e76616c696420746f20537472617465677960681b604482015260640161087d565b60018314801561280b5750600181145b801561286f57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168484600081811061284f5761284f613fa4565b90506020020160208101906128649190613979565b6001600160a01b0316145b6128b45760405162461bcd60e51b815260206004820152601660248201527513db9b1e4815d15512081a5cc81cdd5c1c1bdc9d195960521b604482015260640161087d565b6128bc613395565b828260008181106128cf576128cf613fa4565b9050602002013511156129245760405162461bcd60e51b815260206004820152601960248201527f4e6f7420656e6f756768205745544820617661696c61626c6500000000000000604482015260640161087d565b61297b858383600081811061293b5761293b613fa4565b905060200201357f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166123aa9092919063ffffffff16565b846001600160a01b031663de5f62686040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156129b657600080fd5b505af11580156129ca573d6000803e3d6000fd5b505050505050505050565b6129e38686868686866134e2565b306001600160a01b031663b9b17f9f6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612a1e57600080fd5b505af1158015612a32573d6000803e3d6000fd5b50505050505050505050565b612a46613670565b306001600160a01b031663b9b17f9f6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612a8157600080fd5b505af1158015610d35573d6000803e3d6000fd5b6000612aea826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166137029092919063ffffffff16565b8051909150156123fc5780806020019051810190612b089190613b79565b6123fc5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161087d565b6001600160a01b0386166000908152603360209081526040808320815160808101909252805460ff8082161515845285948401916101009004166001811115612bb257612bb2613f78565b6001811115612bc357612bc3613f78565b8152905462010000810460ff908116602080850191909152630100000090920461ffff166040938401526001600160a01b038b1660009081526033835283812084516080810190955280548084161515865295965090949092840191610100909104166001811115612c3757612c37613f78565b6001811115612c4857612c48613f78565b8152905462010000810460ff1660208301526301000000900461ffff166040909101528251909150612cbc5760405162461bcd60e51b815260206004820152601b60248201527f46726f6d206173736574206973206e6f7420737570706f727465640000000000604482015260640161087d565b8051612d0a5760405162461bcd60e51b815260206004820152601960248201527f546f206173736574206973206e6f7420737570706f7274656400000000000000604482015260640161087d565b6040805180820182526048546001600160a01b038082168352600160a01b90910461ffff16602083015291516370a0823160e01b81523060048201529091600091908b16906370a082319060240160206040518083038186803b158015612d7057600080fd5b505afa158015612d84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612da89190613bcf565b8251909150612dc2906001600160a01b038d16908b6123aa565b81516001600160a01b0316632506c0188c8c612ddf60018e613f04565b8c8c8c6040518763ffffffff1660e01b8152600401612e0396959493929190613c21565b602060405180830381600087803b158015612e1d57600080fd5b505af1158015612e31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e559190613bcf565b506040516370a0823160e01b815230600482015281906001600160a01b038c16906370a082319060240160206040518083038186803b158015612e9757600080fd5b505afa158015612eab573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ecf9190613bcf565b612ed99190613f04565b94505086841015612f2c5760405162461bcd60e51b815260206004820152601960248201527f5374726174656769737420736c697070616765206c696d697400000000000000604482015260640161087d565b60008260600151612710612f409190613d57565b6037546040516315d5220f60e31b81526001600160a01b038d8116600483015261ffff93909316929091169063aea910789060240160206040518083038186803b158015612f8d57600080fd5b505afa158015612fa1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fc59190613bcf565b612fcf9190613ea2565b6037546040516315d5220f60e31b81526001600160a01b038e811660048301529091169063aea910789060240160206040518083038186803b15801561301457600080fd5b505afa158015613028573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061304c9190613bcf565b606086015161305d90612710613ee9565b61306b9061ffff168c613ea2565b6130759190613ea2565b61307f9190613d95565b905061309e6012856040015160ff168361371b9092919063ffffffff16565b60408401516130b490879060129060ff1661371b565b10156131025760405162461bcd60e51b815260206004820152601e60248201527f4f7261636c6520736c697070616765206c696d69742065786365656465640000604482015260640161087d565b5061271081602001516127106131189190613ee9565b61ffff16603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561316a57600080fd5b505afa15801561317e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131a29190613bcf565b6131ac9190613ea2565b6131b69190613d95565b306001600160a01b031663d4c3eea06040518163ffffffff1660e01b815260040160206040518083038186803b1580156131ef57600080fd5b505afa158015613203573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132279190613bcf565b101561326e5760405162461bcd60e51b8152602060048201526016602482015275416c6c6f7765642076616c7565203c20737570706c7960501b604482015260640161087d565b886001600160a01b03168a6001600160a01b03167fa078c4190abe07940190effc1846be0ccf03ad6007bc9e93f9697d0b460befbb8a876040516132bc929190918252602082015260400190565b60405180910390a35050509695505050505050565b6001600160a01b03811660009081526035602052604090205460ff166133395760405162461bcd60e51b815260206004820152601960248201527f5374726174656779206973206e6f7420737570706f7274656400000000000000604482015260640161087d565b6000819050806001600160a01b031663853828b66040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561337957600080fd5b505af115801561338d573d6000803e3d6000fd5b505050505050565b60408051608081018252604a546001600160801b03808216808452600160801b92839004821660208501819052604b54808416968601969096529290940416606083015260009283916133e791613ec1565b6040516370a0823160e01b81523060048201526001600160801b039190911691506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a082319060240160206040518083038186803b15801561345757600080fd5b505afa15801561346b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061348f9190613bcf565b90506000836040015184602001516134a79190613ec1565b6001600160801b031690506134bc8184613d7d565b8211156134db57806134ce8484613f04565b6134d89190613f04565b94505b5050505090565b6001600160a01b03851660009081526035602052604090205460ff166135425760405162461bcd60e51b8152602060048201526015602482015274496e76616c69642066726f6d20537472617465677960581b604482015260640161087d565b8281146135915760405162461bcd60e51b815260206004820152601960248201527f506172616d65746572206c656e677468206d69736d6174636800000000000000604482015260640161087d565b8260005b8181101561366657866001600160a01b031663d9caed12898888858181106135bf576135bf613fa4565b90506020020160208101906135d49190613979565b8787868181106135e6576135e6613fa4565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b15801561363d57600080fd5b505af1158015613651573d6000803e3d6000fd5b505050508061365f90613f47565b9050613595565b5050505050505050565b60365460005b81811015610a36576036818154811061369157613691613fa4565b60009182526020822001546040805163429c145b60e11b815290516001600160a01b039092169263853828b69260048084019382900301818387803b1580156136d957600080fd5b505af11580156136ed573d6000803e3d6000fd5b50505050806136fb90613f47565b9050613676565b6060613711848460008561377d565b90505b9392505050565b60008183111561374b576137446137328385613f04565b61373d90600a613dfa565b85906138a5565b9350613775565b81831015613775576137726137608484613f04565b61376b90600a613dfa565b85906138ba565b93505b509192915050565b6060824710156137de5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161087d565b843b61382c5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161087d565b600080866001600160a01b031685876040516138489190613c05565b60006040518083038185875af1925050503d8060008114613885576040519150601f19603f3d011682016040523d82523d6000602084013e61388a565b606091505b509150915061389a8282866138c6565b979650505050505050565b60006138b18284613ea2565b90505b92915050565b60006138b18284613d95565b606083156138d5575081613714565b8251156138e55782518084602001fd5b8160405162461bcd60e51b815260040161087d9190613c7d565b80356001600160a01b038116811461391657600080fd5b919050565b60008083601f84011261392d57600080fd5b50813567ffffffffffffffff81111561394557600080fd5b6020830191508360208260051b850101111561396057600080fd5b9250929050565b803561ffff8116811461391657600080fd5b60006020828403121561398b57600080fd5b6138b1826138ff565b600080604083850312156139a757600080fd5b6139b0836138ff565b91506139be602084016138ff565b90509250929050565b60008060008060008060a087890312156139e057600080fd5b6139e9876138ff565b95506139f7602088016138ff565b94506040870135935060608701359250608087013567ffffffffffffffff80821115613a2257600080fd5b818901915089601f830112613a3657600080fd5b813581811115613a4557600080fd5b8a6020828501011115613a5757600080fd5b6020830194508093505050509295509295509295565b600080600080600060608688031215613a8557600080fd5b613a8e866138ff565b9450602086013567ffffffffffffffff80821115613aab57600080fd5b613ab789838a0161391b565b90965094506040880135915080821115613ad057600080fd5b50613add8882890161391b565b969995985093965092949392505050565b60008060408385031215613b0157600080fd5b613b0a836138ff565b91506139be60208401613967565b60008060408385031215613b2b57600080fd5b613b34836138ff565b946020939093013593505050565b60008060408385031215613b5557600080fd5b613b5e836138ff565b91506020830135613b6e81613fba565b809150509250929050565b600060208284031215613b8b57600080fd5b8151801515811461371457600080fd5b600060208284031215613bad57600080fd5b6138b182613967565b600060208284031215613bc857600080fd5b5035919050565b600060208284031215613be157600080fd5b5051919050565b600060208284031215613bfa57600080fd5b815161371481613fba565b60008251613c17818460208701613f1b565b9190910192915050565b6001600160a01b03878116825286166020820152604081018590526060810184905260a06080820181905281018290526000828460c0840137600060c0848401015260c0601f19601f8501168301019050979650505050505050565b6020815260008251806020840152613c9c816040850160208701613f1b565b601f01601f19169190910160400192915050565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60208082526028908201527f43616c6c6572206973206e6f74207468652053747261746567697374206f722060408201526723b7bb32b93737b960c11b606082015260800190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b600061ffff808316818516808303821115613d7457613d74613f62565b01949350505050565b60008219821115613d9057613d90613f62565b500190565b600082613db257634e487b7160e01b600052601260045260246000fd5b500490565b600181815b80851115613df2578160001904821115613dd857613dd8613f62565b80851615613de557918102915b93841c9390800290613dbc565b509250929050565b60006138b18383600082613e10575060016138b4565b81613e1d575060006138b4565b8160018114613e335760028114613e3d57613e59565b60019150506138b4565b60ff841115613e4e57613e4e613f62565b50506001821b6138b4565b5060208310610133831016604e8410600b8410161715613e7c575081810a6138b4565b613e868383613db7565b8060001904821115613e9a57613e9a613f62565b029392505050565b6000816000190483118215151615613ebc57613ebc613f62565b500290565b60006001600160801b0383811690831681811015613ee157613ee1613f62565b039392505050565b600061ffff83811690831681811015613ee157613ee1613f62565b600082821015613f1657613f16613f62565b500390565b60005b83811015613f36578181015183820152602001613f1e565b83811115610d355750506000910152565b6000600019821415613f5b57613f5b613f62565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b60ff81168114610e4857600080fdfe7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa26469706673582212204c349976718ffeea8451b6fc51a97a047f4b6a442f1c7d8cb4ff7a709c77e97e64736f6c634300080700337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106103835760003560e01c8063636e6c40116101de578063ae69f3cb1161010f578063c9919112116100ad578063e6cc54321161007c578063e6cc5432146107f8578063e829cc161461080c578063eb03654b1461081f578063fc0cfeee1461083257600080fd5b8063c9919112146107c1578063d38bfff4146107c9578063d58e3b3a146107dc578063e45cc9f0146107ef57600080fd5b8063b890ebf6116100e9578063b890ebf61461078b578063bc90106b1461079e578063c5f00841146107b1578063c7af3352146107b957600080fd5b8063ae69f3cb14610752578063b2c9336d14610765578063b888879e1461077857600080fd5b80638e510b521161017c57806394828ffd1161015657806394828ffd146107055780639c82f2a41461070d5780639fa1826e14610720578063a403e4d51461072957600080fd5b80638e510b521461065f5780638ec489a214610668578063937b25811461067b57600080fd5b8063773540b3116101b8578063773540b31461061d5780637a2202f3146106305780637b9a709614610639578063840c4c7a1461064c57600080fd5b8063636e6c40146105e4578063663e64ce146105f75780636c7561e81461060a57600080fd5b8063372aa224116102b857806350ba711c11610256578063570d8e1d11610230578063570d8e1d146105a3578063597c8910146105b65780635d36b190146105c9578063603ea03b146105d157600080fd5b806350ba711c1461056357806352d38e5d1461057657806353ca9f241461057f57600080fd5b80633fc8cef3116102925780633fc8cef31461050357806349c1d54d1461052a5780634a5e42b11461053d5780634bed3bc01461055057600080fd5b8063372aa224146104d55780633b8ae397146104e85780633dbc911f146104fb57600080fd5b80631edfe3da116103255780632da845a8116102ff5780632da845a81461043d5780632e9958ab14610450578063362bd1a31461046357806336b6d944146104c257600080fd5b80631edfe3da1461041a578063207134b0146104235780632b3297f91461042c57600080fd5b80630c340a24116103615780630c340a24146103c15780631072cbea146103e1578063175188e8146103f457806318ce56bd1461040757600080fd5b806309f49bf51461038857806309f6442c146103925780630acbda75146103ae575b600080fd5b610390610845565b005b61039b60385481565b6040519081526020015b60405180910390f35b6103906103bc366004613bb6565b6108be565b6103c9610970565b6040516001600160a01b0390911681526020016103a5565b6103906103ef366004613b18565b61098d565b610390610402366004613979565b610a3a565b6045546103c9906001600160a01b031681565b61039b60395481565b61039b60435481565b6048546001600160a01b03166103c9565b61039061044b366004613979565b610d3b565b61039061045e366004613979565b610dad565b604a54604b5461048f916001600160801b0380821692600160801b928390048216928183169291041684565b604080516001600160801b03958616815293851660208501529184169183019190915290911660608201526080016103a5565b6103906104d0366004613979565b610e1b565b6103906104e3366004613979565b610e4b565b6103906104f6366004613979565b610ebd565b610390610ffa565b6103c97f000000000000000000000000000000000000000000000000000000000000000081565b6042546103c9906001600160a01b031681565b61039061054b366004613979565b611070565b604854600160a01b900461ffff1661039b565b61039b6105713660046139c7565b61137d565b61039b603b5481565b60375461059390600160a01b900460ff1681565b60405190151581526020016103a5565b603f546103c9906001600160a01b031681565b6103906105c4366004613979565b611420565b610390611461565b6049546103c9906001600160a01b031681565b6103906105f2366004613bb6565b611507565b610390610605366004613bb6565b611565565b610390610618366004613b42565b6115be565b61039061062b366004613979565b61183c565b61039b60475481565b610390610647366004613aee565b6118ae565b61039061065a366004613a6d565b6119e4565b61039b60415481565b610390610676366004613bb6565b611a7d565b6106cc610689366004613bb6565b604c60205260009081526040902080546001909101546001600160a01b03821691600160a01b900460ff16906001600160801b0380821691600160801b90041684565b604080516001600160a01b03909516855292151560208501526001600160801b03918216928401929092521660608201526080016103a5565b610390611b32565b61039061071b366004613979565b611ba2565b61039b603a5481565b6103c9610737366004613979565b6040602081905260009182529020546001600160a01b031681565b610390610760366004613a6d565b611c14565b610390610773366004613bb6565b611ca2565b6037546103c9906001600160a01b031681565b610390610799366004613bb6565b611cfb565b6103906107ac366004613994565b611d54565b610390611f96565b61059361200c565b61039061203d565b6103906107d7366004613979565b61207d565b6103906107ea366004613979565b612121565b61039b60465481565b60375461059390600160a81b900460ff1681565b61039061081a366004613b9b565b612193565b61039061082d366004613bb6565b612253565b610390610840366004613979565b612308565b603f546001600160a01b0316331480610861575061086161200c565b6108865760405162461bcd60e51b815260040161087d90613ce7565b60405180910390fd5b6037805460ff60a01b191690556040517fbc044409505c95b6b851433df96e1beae715c909d8e7c1d6d7ab783300d4e3b990600090a1565b6108c661200c565b6108e25760405162461bcd60e51b815260040161087d90613cb0565b6113888111156109345760405162461bcd60e51b815260206004820152601760248201527f62617369732063616e6e6f742065786365656420353025000000000000000000604482015260640161087d565b60438190556040518181527f56287a45051933ea374811b3d5d165033047be5572cac676f7c28b8be4f746c7906020015b60405180910390a150565b6000610988600080516020613fca8339815191525490565b905090565b61099561200c565b6109b15760405162461bcd60e51b815260040161087d90613cb0565b6001600160a01b03821660009081526033602052604090205460ff1615610a1a5760405162461bcd60e51b815260206004820152601760248201527f4f6e6c7920756e737570706f7274656420617373657473000000000000000000604482015260640161087d565b610a36610a25610970565b6001600160a01b03841690836123aa565b5050565b610a4261200c565b610a5e5760405162461bcd60e51b815260040161087d90613cb0565b6001600160a01b03811660009081526035602052604090205460ff16610abe5760405162461bcd60e51b815260206004820152601560248201527414dd1c985d1959de481b9bdd08185c1c1c9bdd9959605a1b604482015260640161087d565b60345460005b81811015610b7657826001600160a01b03166040600060348481548110610aed57610aed613fa4565b60009182526020808320909101546001600160a01b039081168452908301939093526040909101902054161415610b665760405162461bcd60e51b815260206004820181905260248201527f53747261746567792069732064656661756c7420666f7220616e206173736574604482015260640161087d565b610b6f81613f47565b9050610ac4565b506036548060005b82811015610bd657846001600160a01b031660368281548110610ba357610ba3613fa4565b6000918252602090912001546001600160a01b03161415610bc657809150610bd6565b610bcf81613f47565b9050610b7e565b5081811015610d35576036610bec600184613f04565b81548110610bfc57610bfc613fa4565b600091825260209091200154603680546001600160a01b039092169183908110610c2857610c28613fa4565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506036805480610c6757610c67613f8e565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b03861680835260359091526040808320805460ff19169055805163429c145b60e11b81529051879363853828b6926004808201939182900301818387803b158015610cde57600080fd5b505af1158015610cf2573d6000803e3d6000fd5b50506040516001600160a01b03881681527f09a1db4b80c32706328728508c941a6b954f31eb5affd32f236c1fd405f8fea49250602001905060405180910390a1505b50505050565b610d4361200c565b610d5f5760405162461bcd60e51b815260040161087d90613cb0565b604280546001600160a01b0319166001600160a01b0383169081179091556040519081527f1e4af5ac389e8cde1bdaa6830881b6c987c62a45cfb3b33d27d805cde3b5775090602001610965565b610db561200c565b610dd15760405162461bcd60e51b815260040161087d90613cb0565b604980546001600160a01b0319166001600160a01b0383169081179091556040517faf2910d9759321733de15af1827a49830692912adeb2b3646334861f2cd2eed490600090a250565b610e2361200c565b610e3f5760405162461bcd60e51b815260040161087d90613cb0565b610e4881612401565b50565b610e5361200c565b610e6f5760405162461bcd60e51b815260040161087d90613cb0565b603780546001600160a01b0319166001600160a01b0383169081179091556040519081527fb266add5f3044b17d27db796af992cecbe413921b4e8aaaee03c719e16b9806a90602001610965565b610ec561200c565b610ee15760405162461bcd60e51b815260040161087d90613cb0565b6001600160a01b03811660009081526035602052604090205460ff1615610f4a5760405162461bcd60e51b815260206004820152601960248201527f537472617465677920616c726561647920617070726f76656400000000000000604482015260640161087d565b6040805180820182526001808252600060208084018281526001600160a01b038716808452603583528684209551865460ff19169015151786559051948401949094556036805493840181559091527f4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b890910180546001600160a01b0319168317905591519081527f960dd94cbb79169f09a4e445d58b895df2d9bffa5b31055d0932d801724a20d19101610965565b603f546001600160a01b0316331480611016575061101661200c565b6110325760405162461bcd60e51b815260040161087d90613ce7565b6037805460ff60a81b1916600160a81b1790556040517f71f0e5b62f846a22e0b4d159e516e62fa9c2b8eb570be15f83e67d98a2ee51e090600090a1565b61107861200c565b6110945760405162461bcd60e51b815260040161087d90613cb0565b6001600160a01b03811660009081526033602052604090205460ff166110f25760405162461bcd60e51b8152602060048201526013602482015272105cdcd95d081b9bdd081cdd5c1c1bdc9d1959606a1b604482015260640161087d565b604051632fa8a91360e11b81526001600160a01b03821660048201526509184e72a000903090635f5152269060240160206040518083038186803b15801561113957600080fd5b505afa15801561114d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111719190613bcf565b11156111bf5760405162461bcd60e51b815260206004820152601760248201527f5661756c74207374696c6c20686f6c6473206173736574000000000000000000604482015260640161087d565b6034548060005b8281101561121e57836001600160a01b0316603482815481106111eb576111eb613fa4565b6000918252602090912001546001600160a01b0316141561120e5780915061121e565b61121781613f47565b90506111c6565b50603461122c600184613f04565b8154811061123c5761123c613fa4565b600091825260209091200154603480546001600160a01b03909216918390811061126857611268613fa4565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060348054806112a7576112a7613f8e565b60008281526020808220600019908401810180546001600160a01b031990811690915593019093556001600160a01b038616808252604080855280832080549094169093558251908152928301527fba58ce12801c949fa65f41c46ed108671c219baf945fa48d21026cea99ff252a910160405180910390a16001600160a01b038316600081815260336020908152604091829020805464ffffffffff1916905590519182527f37803e2125c48ee96c38ddf04e826daf335b0e1603579040fd275aba6d06b6fc910160405180910390a1505050565b7f53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac453580546000919060028114156113c55760405162461bcd60e51b815260040161087d90613d2f565b60028255603f546001600160a01b03163314806113e557506113e561200c565b6114015760405162461bcd60e51b815260040161087d90613ce7565b61140f898989898989612517565b600190925550979650505050505050565b603f546001600160a01b031633148061143c575061143c61200c565b6114585760405162461bcd60e51b815260040161087d90613ce7565b610e488161267d565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b0316146114fc5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b606482015260840161087d565b611505336126dc565b565b61150f61200c565b61152b5760405162461bcd60e51b815260040161087d90613cb0565b600060465560478190556040518181527fc29d6fedbc6bdf267a08166c2b976fbd72aca5d6a769528616f8b9224c8f197f90602001610965565b61156d61200c565b6115895760405162461bcd60e51b815260040161087d90613cb0565b60418190556040518181527f95201f9c21f26877223b1ff4073936a6484c35495649e60e55730497aeb60d9390602001610965565b6115c661200c565b6115e25760405162461bcd60e51b815260040161087d90613cb0565b6001600160a01b03821660009081526033602052604090205460ff161561164b5760405162461bcd60e51b815260206004820152601760248201527f417373657420616c726561647920737570706f72746564000000000000000000604482015260640161087d565b60405180608001604052806001151581526020018260ff16600181111561167457611674613f78565b600181111561168557611685613f78565b81526000602080830182905260409283018290526001600160a01b0386168252603381529190208251815490151560ff19821681178355928401519192839161ff001990911661ffff19909116176101008360018111156116e8576116e8613f78565b02179055506040820151815460609093015161ffff1663010000000264ffff0000001960ff90921662010000029190911664ffffff0000199093169290921791909117905561173682612401565b603480546001810182556000919091527f46bddb1178e94d7f2892ff5f366840eb658911794f2c3a44c450aa2c505186c10180546001600160a01b0319166001600160a01b038481169182179092556037546040516315d5220f60e31b815260048101929092529091169063aea910789060240160206040518083038186803b1580156117c257600080fd5b505afa1580156117d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117fa9190613bcf565b506040516001600160a01b03831681527f4f1ac48525e50059cc1cc6e0e1940ece0dd653a4db4841538d6aef036be2fb7b906020015b60405180910390a15050565b61184461200c565b6118605760405162461bcd60e51b815260040161087d90613cb0565b603f80546001600160a01b0319166001600160a01b0383169081179091556040519081527f869e0abd13cc3a975de7b93be3df1cb2255c802b1cead85963cc79d99f131bee90602001610965565b6118b661200c565b6118d25760405162461bcd60e51b815260040161087d90613cb0565b6001600160a01b03821660009081526033602052604090205460ff166119305760405162461bcd60e51b8152602060048201526013602482015272105cdcd95d081b9bdd081cdd5c1c1bdc9d1959606a1b604482015260640161087d565b6103e88161ffff16106119795760405162461bcd60e51b81526020600482015260116024820152700a6d8d2e0e0c2ceca40e8dede40d0d2ced607b1b604482015260640161087d565b6001600160a01b038216600081815260336020908152604091829020805464ffff0000001916630100000061ffff8716908102919091179091558251938452908301527f8d22e9d2cbe8bb65a3c4412bd8970743864512a1a0e004e8d00fb96277b78b949101611830565b603f546001600160a01b0316331480611a005750611a0061200c565b611a1c5760405162461bcd60e51b815260040161087d90613ce7565b7f53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac453580546002811415611a605760405162461bcd60e51b815260040161087d90613d2f565b60028255611a71878787878761279d565b50600190555050505050565b603f546001600160a01b0316331480611a995750611a9961200c565b611ab55760405162461bcd60e51b815260040161087d90613ce7565b670de0b6b3a7640000811115611afd5760405162461bcd60e51b815260206004820152600d60248201526c496e76616c69642076616c756560981b604482015260640161087d565b60398190556040518181527f41ecb23a0e7865b25f38c268b7c3012220d822929e9edff07326e89d5bb822b590602001610965565b603f546001600160a01b0316331480611b4e5750611b4e61200c565b611b6a5760405162461bcd60e51b815260040161087d90613ce7565b6037805460ff60a81b191690556040517f891ebab18da80ebeeea06b1b1cede098329c4c008906a98370c2ac7a80b571cb90600090a1565b611baa61200c565b611bc65760405162461bcd60e51b815260040161087d90613cb0565b604880546001600160a01b0319166001600160a01b0383169081179091556040519081527f7d7719313229e558c5a3893cad2eb86a86a049156d1d9ebd5c63a8eedefd1c0390602001610965565b603f546001600160a01b0316331480611c305750611c3061200c565b611c4c5760405162461bcd60e51b815260040161087d90613ce7565b7f53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac453580546002811415611c905760405162461bcd60e51b815260040161087d90613d2f565b60028255611a713088888888886129d5565b611caa61200c565b611cc65760405162461bcd60e51b815260040161087d90613cb0565b603a8190556040518181527f2ec5fb5a3d2703edc461252d92ccd2799c3c74f01d97212b20388207fa17ae4590602001610965565b611d0361200c565b611d1f5760405162461bcd60e51b815260040161087d90613cb0565b603b8190556040518181527f39367850377ac04920a9a670f2180e7a94d83b15ad302e59875ec58fd10bd37d90602001610965565b603f546001600160a01b0316331480611d705750611d7061200c565b611d8c5760405162461bcd60e51b815260040161087d90613ce7565b604080516001600160a01b038085168252831660208201527fba58ce12801c949fa65f41c46ed108671c219baf945fa48d21026cea99ff252a910160405180910390a16001600160a01b03811615611f68576001600160a01b03811660009081526035602052604090205460ff16611e3e5760405162461bcd60e51b815260206004820152601560248201527414dd1c985d1959de481b9bdd08185c1c1c9bdd9959605a1b604482015260640161087d565b6001600160a01b038216600090815260336020526040902054819060ff16611ea15760405162461bcd60e51b8152602060048201526016602482015275105cdcd95d081a5cc81b9bdd081cdd5c1c1bdc9d195960521b604482015260640161087d565b60405163551c457b60e11b81526001600160a01b03848116600483015282169063aa388af69060240160206040518083038186803b158015611ee257600080fd5b505afa158015611ef6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f1a9190613b79565b611f665760405162461bcd60e51b815260206004820152601f60248201527f4173736574206e6f7420737570706f7274656420627920537472617465677900604482015260640161087d565b505b6001600160a01b03918216600090815260406020819052902080546001600160a01b03191691909216179055565b603f546001600160a01b0316331480611fb25750611fb261200c565b611fce5760405162461bcd60e51b815260040161087d90613ce7565b6037805460ff60a01b1916600160a01b1790556040517f8cff26a5985614b3d30629cc4ab83824bf115aec971b718d8f2f99562032e97290600090a1565b6000612024600080516020613fca8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b603f546001600160a01b0316331480612059575061205961200c565b6120755760405162461bcd60e51b815260040161087d90613ce7565b611505612a3e565b61208561200c565b6120a15760405162461bcd60e51b815260040161087d90613cb0565b6120c9817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166120e9600080516020613fca8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b61212961200c565b6121455760405162461bcd60e51b815260040161087d90613cb0565b604580546001600160a01b0319166001600160a01b0383169081179091556040519081527fa12850fb726e0b2b7b3c9a9342031e1268a8148d0eb06b4bea8613204ffcd2b890602001610965565b61219b61200c565b6121b75760405162461bcd60e51b815260040161087d90613cb0565b6127118161ffff16106122035760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420626173697320706f696e747360601b604482015260640161087d565b6048805461ffff60a01b1916600160a01b61ffff8416908102919091179091556040519081527ff12c00256bee2b6facb111a88a9b1cff86e79132939b44f1353212d6f746955790602001610965565b61225b61200c565b6122775760405162461bcd60e51b815260040161087d90613cb0565b6103e88111156122d35760405162461bcd60e51b815260206004820152602160248201527f52656465656d206665652073686f756c64206e6f74206265206f7665722031306044820152602560f81b606482015260840161087d565b60388190556040518181527fd6c7508d6658ccee36b7b7d7fd72e5cbaeefb40c64eff24e9ae7470e846304ee90602001610965565b61231061200c565b61232c5760405162461bcd60e51b815260040161087d90613cb0565b803b6123865760405162461bcd60e51b8152602060048201526024808201527f6e657720696d706c656d656e746174696f6e206973206e6f74206120636f6e746044820152631c9858dd60e21b606482015260840161087d565b7fa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd955565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526123fc908490612a95565b505050565b6001600160a01b0381166000908152603360205260409020805462010000900460ff161561242d575050565b6000826001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b15801561246857600080fd5b505afa15801561247c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124a09190613be8565b905060068160ff16101580156124ba575060128160ff1611155b6124fd5760405162461bcd60e51b81526020600482015260146024820152732ab732bc3832b1ba32b210383932b1b4b9b4b7b760611b604482015260640161087d565b815460ff909116620100000262ff00001990911617905550565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316876001600160a01b0316141561259b5760405162461bcd60e51b815260206004820152601c60248201527f737761702066726f6d2057455448206e6f7420737570706f7274656400000000604482015260640161087d565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316866001600160a01b0316146126105760405162461bcd60e51b81526020600482015260116024820152700dedcd8f240e6eec2e040e8de40ae8aa89607b1b604482015260640161087d565b61261e878787878787612b67565b9050306001600160a01b031663b9b17f9f6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561265b57600080fd5b505af115801561266f573d6000803e3d6000fd5b505050509695505050505050565b612686816132d1565b306001600160a01b031663b9b17f9f6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156126c157600080fd5b505af11580156126d5573d6000803e3d6000fd5b5050505050565b6001600160a01b0381166127325760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f722069732061646472657373283029000000000000604482015260640161087d565b806001600160a01b0316612752600080516020613fca8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a3610e4881600080516020613fca83398151915255565b6001600160a01b03851660009081526035602052604090205460ff166127fb5760405162461bcd60e51b8152602060048201526013602482015272496e76616c696420746f20537472617465677960681b604482015260640161087d565b60018314801561280b5750600181145b801561286f57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168484600081811061284f5761284f613fa4565b90506020020160208101906128649190613979565b6001600160a01b0316145b6128b45760405162461bcd60e51b815260206004820152601660248201527513db9b1e4815d15512081a5cc81cdd5c1c1bdc9d195960521b604482015260640161087d565b6128bc613395565b828260008181106128cf576128cf613fa4565b9050602002013511156129245760405162461bcd60e51b815260206004820152601960248201527f4e6f7420656e6f756768205745544820617661696c61626c6500000000000000604482015260640161087d565b61297b858383600081811061293b5761293b613fa4565b905060200201357f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166123aa9092919063ffffffff16565b846001600160a01b031663de5f62686040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156129b657600080fd5b505af11580156129ca573d6000803e3d6000fd5b505050505050505050565b6129e38686868686866134e2565b306001600160a01b031663b9b17f9f6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612a1e57600080fd5b505af1158015612a32573d6000803e3d6000fd5b50505050505050505050565b612a46613670565b306001600160a01b031663b9b17f9f6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612a8157600080fd5b505af1158015610d35573d6000803e3d6000fd5b6000612aea826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166137029092919063ffffffff16565b8051909150156123fc5780806020019051810190612b089190613b79565b6123fc5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161087d565b6001600160a01b0386166000908152603360209081526040808320815160808101909252805460ff8082161515845285948401916101009004166001811115612bb257612bb2613f78565b6001811115612bc357612bc3613f78565b8152905462010000810460ff908116602080850191909152630100000090920461ffff166040938401526001600160a01b038b1660009081526033835283812084516080810190955280548084161515865295965090949092840191610100909104166001811115612c3757612c37613f78565b6001811115612c4857612c48613f78565b8152905462010000810460ff1660208301526301000000900461ffff166040909101528251909150612cbc5760405162461bcd60e51b815260206004820152601b60248201527f46726f6d206173736574206973206e6f7420737570706f727465640000000000604482015260640161087d565b8051612d0a5760405162461bcd60e51b815260206004820152601960248201527f546f206173736574206973206e6f7420737570706f7274656400000000000000604482015260640161087d565b6040805180820182526048546001600160a01b038082168352600160a01b90910461ffff16602083015291516370a0823160e01b81523060048201529091600091908b16906370a082319060240160206040518083038186803b158015612d7057600080fd5b505afa158015612d84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612da89190613bcf565b8251909150612dc2906001600160a01b038d16908b6123aa565b81516001600160a01b0316632506c0188c8c612ddf60018e613f04565b8c8c8c6040518763ffffffff1660e01b8152600401612e0396959493929190613c21565b602060405180830381600087803b158015612e1d57600080fd5b505af1158015612e31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e559190613bcf565b506040516370a0823160e01b815230600482015281906001600160a01b038c16906370a082319060240160206040518083038186803b158015612e9757600080fd5b505afa158015612eab573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ecf9190613bcf565b612ed99190613f04565b94505086841015612f2c5760405162461bcd60e51b815260206004820152601960248201527f5374726174656769737420736c697070616765206c696d697400000000000000604482015260640161087d565b60008260600151612710612f409190613d57565b6037546040516315d5220f60e31b81526001600160a01b038d8116600483015261ffff93909316929091169063aea910789060240160206040518083038186803b158015612f8d57600080fd5b505afa158015612fa1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fc59190613bcf565b612fcf9190613ea2565b6037546040516315d5220f60e31b81526001600160a01b038e811660048301529091169063aea910789060240160206040518083038186803b15801561301457600080fd5b505afa158015613028573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061304c9190613bcf565b606086015161305d90612710613ee9565b61306b9061ffff168c613ea2565b6130759190613ea2565b61307f9190613d95565b905061309e6012856040015160ff168361371b9092919063ffffffff16565b60408401516130b490879060129060ff1661371b565b10156131025760405162461bcd60e51b815260206004820152601e60248201527f4f7261636c6520736c697070616765206c696d69742065786365656465640000604482015260640161087d565b5061271081602001516127106131189190613ee9565b61ffff16603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561316a57600080fd5b505afa15801561317e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131a29190613bcf565b6131ac9190613ea2565b6131b69190613d95565b306001600160a01b031663d4c3eea06040518163ffffffff1660e01b815260040160206040518083038186803b1580156131ef57600080fd5b505afa158015613203573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132279190613bcf565b101561326e5760405162461bcd60e51b8152602060048201526016602482015275416c6c6f7765642076616c7565203c20737570706c7960501b604482015260640161087d565b886001600160a01b03168a6001600160a01b03167fa078c4190abe07940190effc1846be0ccf03ad6007bc9e93f9697d0b460befbb8a876040516132bc929190918252602082015260400190565b60405180910390a35050509695505050505050565b6001600160a01b03811660009081526035602052604090205460ff166133395760405162461bcd60e51b815260206004820152601960248201527f5374726174656779206973206e6f7420737570706f7274656400000000000000604482015260640161087d565b6000819050806001600160a01b031663853828b66040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561337957600080fd5b505af115801561338d573d6000803e3d6000fd5b505050505050565b60408051608081018252604a546001600160801b03808216808452600160801b92839004821660208501819052604b54808416968601969096529290940416606083015260009283916133e791613ec1565b6040516370a0823160e01b81523060048201526001600160801b039190911691506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a082319060240160206040518083038186803b15801561345757600080fd5b505afa15801561346b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061348f9190613bcf565b90506000836040015184602001516134a79190613ec1565b6001600160801b031690506134bc8184613d7d565b8211156134db57806134ce8484613f04565b6134d89190613f04565b94505b5050505090565b6001600160a01b03851660009081526035602052604090205460ff166135425760405162461bcd60e51b8152602060048201526015602482015274496e76616c69642066726f6d20537472617465677960581b604482015260640161087d565b8281146135915760405162461bcd60e51b815260206004820152601960248201527f506172616d65746572206c656e677468206d69736d6174636800000000000000604482015260640161087d565b8260005b8181101561366657866001600160a01b031663d9caed12898888858181106135bf576135bf613fa4565b90506020020160208101906135d49190613979565b8787868181106135e6576135e6613fa4565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b15801561363d57600080fd5b505af1158015613651573d6000803e3d6000fd5b505050508061365f90613f47565b9050613595565b5050505050505050565b60365460005b81811015610a36576036818154811061369157613691613fa4565b60009182526020822001546040805163429c145b60e11b815290516001600160a01b039092169263853828b69260048084019382900301818387803b1580156136d957600080fd5b505af11580156136ed573d6000803e3d6000fd5b50505050806136fb90613f47565b9050613676565b6060613711848460008561377d565b90505b9392505050565b60008183111561374b576137446137328385613f04565b61373d90600a613dfa565b85906138a5565b9350613775565b81831015613775576137726137608484613f04565b61376b90600a613dfa565b85906138ba565b93505b509192915050565b6060824710156137de5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161087d565b843b61382c5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161087d565b600080866001600160a01b031685876040516138489190613c05565b60006040518083038185875af1925050503d8060008114613885576040519150601f19603f3d011682016040523d82523d6000602084013e61388a565b606091505b509150915061389a8282866138c6565b979650505050505050565b60006138b18284613ea2565b90505b92915050565b60006138b18284613d95565b606083156138d5575081613714565b8251156138e55782518084602001fd5b8160405162461bcd60e51b815260040161087d9190613c7d565b80356001600160a01b038116811461391657600080fd5b919050565b60008083601f84011261392d57600080fd5b50813567ffffffffffffffff81111561394557600080fd5b6020830191508360208260051b850101111561396057600080fd5b9250929050565b803561ffff8116811461391657600080fd5b60006020828403121561398b57600080fd5b6138b1826138ff565b600080604083850312156139a757600080fd5b6139b0836138ff565b91506139be602084016138ff565b90509250929050565b60008060008060008060a087890312156139e057600080fd5b6139e9876138ff565b95506139f7602088016138ff565b94506040870135935060608701359250608087013567ffffffffffffffff80821115613a2257600080fd5b818901915089601f830112613a3657600080fd5b813581811115613a4557600080fd5b8a6020828501011115613a5757600080fd5b6020830194508093505050509295509295509295565b600080600080600060608688031215613a8557600080fd5b613a8e866138ff565b9450602086013567ffffffffffffffff80821115613aab57600080fd5b613ab789838a0161391b565b90965094506040880135915080821115613ad057600080fd5b50613add8882890161391b565b969995985093965092949392505050565b60008060408385031215613b0157600080fd5b613b0a836138ff565b91506139be60208401613967565b60008060408385031215613b2b57600080fd5b613b34836138ff565b946020939093013593505050565b60008060408385031215613b5557600080fd5b613b5e836138ff565b91506020830135613b6e81613fba565b809150509250929050565b600060208284031215613b8b57600080fd5b8151801515811461371457600080fd5b600060208284031215613bad57600080fd5b6138b182613967565b600060208284031215613bc857600080fd5b5035919050565b600060208284031215613be157600080fd5b5051919050565b600060208284031215613bfa57600080fd5b815161371481613fba565b60008251613c17818460208701613f1b565b9190910192915050565b6001600160a01b03878116825286166020820152604081018590526060810184905260a06080820181905281018290526000828460c0840137600060c0848401015260c0601f19601f8501168301019050979650505050505050565b6020815260008251806020840152613c9c816040850160208701613f1b565b601f01601f19169190910160400192915050565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60208082526028908201527f43616c6c6572206973206e6f74207468652053747261746567697374206f722060408201526723b7bb32b93737b960c11b606082015260800190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b600061ffff808316818516808303821115613d7457613d74613f62565b01949350505050565b60008219821115613d9057613d90613f62565b500190565b600082613db257634e487b7160e01b600052601260045260246000fd5b500490565b600181815b80851115613df2578160001904821115613dd857613dd8613f62565b80851615613de557918102915b93841c9390800290613dbc565b509250929050565b60006138b18383600082613e10575060016138b4565b81613e1d575060006138b4565b8160018114613e335760028114613e3d57613e59565b60019150506138b4565b60ff841115613e4e57613e4e613f62565b50506001821b6138b4565b5060208310610133831016604e8410600b8410161715613e7c575081810a6138b4565b613e868383613db7565b8060001904821115613e9a57613e9a613f62565b029392505050565b6000816000190483118215151615613ebc57613ebc613f62565b500290565b60006001600160801b0383811690831681811015613ee157613ee1613f62565b039392505050565b600061ffff83811690831681811015613ee157613ee1613f62565b600082821015613f1657613f16613f62565b500390565b60005b83811015613f36578181015183820152602001613f1e565b83811115610d355750506000910152565b6000600019821415613f5b57613f5b613f62565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b60ff81168114610e4857600080fdfe7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa26469706673582212204c349976718ffeea8451b6fc51a97a047f4b6a442f1c7d8cb4ff7a709c77e97e64736f6c63430008070033", "libraries": {}, "devdoc": { "author": "Origin Protocol Inc", @@ -1192,6 +1420,11 @@ "_strategyToAddress": "Address of the Strategy to deposit assets into." } }, + "removeAsset(address)": { + "params": { + "_asset": "Address of asset" + } + }, "removeStrategy(address)": { "params": { "_addr": "Address of the strategy to remove" @@ -1213,6 +1446,11 @@ "_threshold": "OToken amount with 18 fixed decimals." } }, + "setDripper(address)": { + "params": { + "_dripper": "Address of the Dripper contract." + } + }, "setNetOusdMintForStrategyThreshold(uint256)": { "params": { "_threshold": "OToken amount with 18 fixed decimals." @@ -1335,6 +1573,9 @@ "depositToStrategy(address,address[],uint256[])": { "notice": "Deposit multiple assets from the vault into the strategy." }, + "dripper()": { + "notice": "Address of the Dripper contract that streams harvested rewards to the Vault" + }, "governor()": { "notice": "Returns the address of the current Governor." }, @@ -1371,6 +1612,9 @@ "redeemFeeBps()": { "notice": "Redemption fee in basis points. eg 50 = 0.5%" }, + "removeAsset(address)": { + "notice": "Remove a supported asset from the Vault" + }, "removeStrategy(address)": { "notice": "Remove a strategy from the Vault." }, @@ -1383,6 +1627,9 @@ "setAutoAllocateThreshold(uint256)": { "notice": "Sets the minimum amount of OTokens in a mint to trigger an automatic allocation of funds afterwords." }, + "setDripper(address)": { + "notice": "Set the Dripper contract that streams harvested rewards to the vault." + }, "setMaxSupplyDiff(uint256)": { "notice": "Sets the maximum allowable difference between total supply and backing assets' value." }, @@ -1470,7 +1717,7 @@ "storageLayout": { "storage": [ { - "astId": 41419, + "astId": 24111, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "initialized", "offset": 0, @@ -1478,7 +1725,7 @@ "type": "t_bool" }, { - "astId": 41422, + "astId": 24114, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "initializing", "offset": 1, @@ -1486,7 +1733,7 @@ "type": "t_bool" }, { - "astId": 41462, + "astId": 24154, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "______gap", "offset": 0, @@ -1494,15 +1741,15 @@ "type": "t_array(t_uint256)50_storage" }, { - "astId": 46069, + "astId": 29745, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "assets", "offset": 0, "slot": "51", - "type": "t_mapping(t_address,t_struct(Asset)46063_storage)" + "type": "t_mapping(t_address,t_struct(Asset)29739_storage)" }, { - "astId": 46073, + "astId": 29749, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "allAssets", "offset": 0, @@ -1510,15 +1757,15 @@ "type": "t_array(t_address)dyn_storage" }, { - "astId": 46084, + "astId": 29760, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "strategies", "offset": 0, "slot": "53", - "type": "t_mapping(t_address,t_struct(Strategy)46078_storage)" + "type": "t_mapping(t_address,t_struct(Strategy)29754_storage)" }, { - "astId": 46088, + "astId": 29764, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "allStrategies", "offset": 0, @@ -1526,7 +1773,7 @@ "type": "t_array(t_address)dyn_storage" }, { - "astId": 46091, + "astId": 29767, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "priceProvider", "offset": 0, @@ -1534,7 +1781,7 @@ "type": "t_address" }, { - "astId": 46095, + "astId": 29771, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "rebasePaused", "offset": 20, @@ -1542,7 +1789,7 @@ "type": "t_bool" }, { - "astId": 46099, + "astId": 29775, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "capitalPaused", "offset": 21, @@ -1550,7 +1797,7 @@ "type": "t_bool" }, { - "astId": 46102, + "astId": 29778, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "redeemFeeBps", "offset": 0, @@ -1558,7 +1805,7 @@ "type": "t_uint256" }, { - "astId": 46105, + "astId": 29781, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "vaultBuffer", "offset": 0, @@ -1566,7 +1813,7 @@ "type": "t_uint256" }, { - "astId": 46108, + "astId": 29784, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "autoAllocateThreshold", "offset": 0, @@ -1574,7 +1821,7 @@ "type": "t_uint256" }, { - "astId": 46111, + "astId": 29787, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "rebaseThreshold", "offset": 0, @@ -1582,15 +1829,15 @@ "type": "t_uint256" }, { - "astId": 46115, + "astId": 29791, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "oUSD", "offset": 0, "slot": "60", - "type": "t_contract(OUSD)40245" + "type": "t_contract(OUSD)23477" }, { - "astId": 46124, + "astId": 29800, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "_deprecated_rebaseHooksAddr", "offset": 0, @@ -1598,7 +1845,7 @@ "type": "t_address" }, { - "astId": 46130, + "astId": 29806, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "_deprecated_uniswapAddr", "offset": 0, @@ -1606,7 +1853,7 @@ "type": "t_address" }, { - "astId": 46137, + "astId": 29813, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "strategistAddr", "offset": 0, @@ -1614,7 +1861,7 @@ "type": "t_address" }, { - "astId": 46142, + "astId": 29818, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "assetDefaultStrategies", "offset": 0, @@ -1622,7 +1869,7 @@ "type": "t_mapping(t_address,t_address)" }, { - "astId": 46145, + "astId": 29821, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "maxSupplyDiff", "offset": 0, @@ -1630,7 +1877,7 @@ "type": "t_uint256" }, { - "astId": 46148, + "astId": 29824, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "trusteeAddress", "offset": 0, @@ -1638,7 +1885,7 @@ "type": "t_address" }, { - "astId": 46151, + "astId": 29827, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "trusteeFeeBps", "offset": 0, @@ -1646,7 +1893,7 @@ "type": "t_uint256" }, { - "astId": 46155, + "astId": 29831, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "_deprecated_swapTokens", "offset": 0, @@ -1654,7 +1901,7 @@ "type": "t_array(t_address)dyn_storage" }, { - "astId": 46165, + "astId": 29841, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "ousdMetaStrategy", "offset": 0, @@ -1662,7 +1909,7 @@ "type": "t_address" }, { - "astId": 46169, + "astId": 29845, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "netOusdMintedForStrategy", "offset": 0, @@ -1670,7 +1917,7 @@ "type": "t_int256" }, { - "astId": 46173, + "astId": 29849, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "netOusdMintForStrategyThreshold", "offset": 0, @@ -1678,20 +1925,44 @@ "type": "t_uint256" }, { - "astId": 46194, + "astId": 29870, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "swapConfig", "offset": 0, "slot": "72", - "type": "t_struct(SwapConfig)46184_storage" + "type": "t_struct(SwapConfig)29860_storage" }, { - "astId": 46198, + "astId": 29873, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", - "label": "__gap", + "label": "dripper", "offset": 0, "slot": "73", - "type": "t_array(t_uint256)50_storage" + "type": "t_address" + }, + { + "astId": 29885, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "withdrawalQueueMetadata", + "offset": 0, + "slot": "74", + "type": "t_struct(WithdrawalQueueMetadata)29882_storage" + }, + { + "astId": 29899, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "withdrawalRequests", + "offset": 0, + "slot": "76", + "type": "t_mapping(t_uint256,t_struct(WithdrawalRequest)29894_storage)" + }, + { + "astId": 29903, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "__gap", + "offset": 0, + "slot": "77", + "type": "t_array(t_uint256)46_storage" } ], "types": { @@ -1706,6 +1977,12 @@ "label": "address[]", "numberOfBytes": "32" }, + "t_array(t_uint256)46_storage": { + "base": "t_uint256", + "encoding": "inplace", + "label": "uint256[46]", + "numberOfBytes": "1472" + }, "t_array(t_uint256)50_storage": { "base": "t_uint256", "encoding": "inplace", @@ -1717,12 +1994,12 @@ "label": "bool", "numberOfBytes": "1" }, - "t_contract(OUSD)40245": { + "t_contract(OUSD)23477": { "encoding": "inplace", "label": "contract OUSD", "numberOfBytes": "20" }, - "t_enum(UnitConversion)46053": { + "t_enum(UnitConversion)29729": { "encoding": "inplace", "label": "enum VaultStorage.UnitConversion", "numberOfBytes": "1" @@ -1739,26 +2016,33 @@ "numberOfBytes": "32", "value": "t_address" }, - "t_mapping(t_address,t_struct(Asset)46063_storage)": { + "t_mapping(t_address,t_struct(Asset)29739_storage)": { "encoding": "mapping", "key": "t_address", "label": "mapping(address => struct VaultStorage.Asset)", "numberOfBytes": "32", - "value": "t_struct(Asset)46063_storage" + "value": "t_struct(Asset)29739_storage" }, - "t_mapping(t_address,t_struct(Strategy)46078_storage)": { + "t_mapping(t_address,t_struct(Strategy)29754_storage)": { "encoding": "mapping", "key": "t_address", "label": "mapping(address => struct VaultStorage.Strategy)", "numberOfBytes": "32", - "value": "t_struct(Strategy)46078_storage" + "value": "t_struct(Strategy)29754_storage" }, - "t_struct(Asset)46063_storage": { + "t_mapping(t_uint256,t_struct(WithdrawalRequest)29894_storage)": { + "encoding": "mapping", + "key": "t_uint256", + "label": "mapping(uint256 => struct VaultStorage.WithdrawalRequest)", + "numberOfBytes": "32", + "value": "t_struct(WithdrawalRequest)29894_storage" + }, + "t_struct(Asset)29739_storage": { "encoding": "inplace", "label": "struct VaultStorage.Asset", "members": [ { - "astId": 46055, + "astId": 29731, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "isSupported", "offset": 0, @@ -1766,15 +2050,15 @@ "type": "t_bool" }, { - "astId": 46058, + "astId": 29734, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "unitConversion", "offset": 1, "slot": "0", - "type": "t_enum(UnitConversion)46053" + "type": "t_enum(UnitConversion)29729" }, { - "astId": 46060, + "astId": 29736, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "decimals", "offset": 2, @@ -1782,7 +2066,7 @@ "type": "t_uint8" }, { - "astId": 46062, + "astId": 29738, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "allowedOracleSlippageBps", "offset": 3, @@ -1792,12 +2076,12 @@ ], "numberOfBytes": "32" }, - "t_struct(Strategy)46078_storage": { + "t_struct(Strategy)29754_storage": { "encoding": "inplace", "label": "struct VaultStorage.Strategy", "members": [ { - "astId": 46075, + "astId": 29751, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "isSupported", "offset": 0, @@ -1805,7 +2089,7 @@ "type": "t_bool" }, { - "astId": 46077, + "astId": 29753, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "_deprecated", "offset": 0, @@ -1815,12 +2099,12 @@ ], "numberOfBytes": "64" }, - "t_struct(SwapConfig)46184_storage": { + "t_struct(SwapConfig)29860_storage": { "encoding": "inplace", "label": "struct VaultStorage.SwapConfig", "members": [ { - "astId": 46181, + "astId": 29857, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "swapper", "offset": 0, @@ -1828,7 +2112,7 @@ "type": "t_address" }, { - "astId": 46183, + "astId": 29859, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "allowedUndervalueBps", "offset": 20, @@ -1838,6 +2122,89 @@ ], "numberOfBytes": "32" }, + "t_struct(WithdrawalQueueMetadata)29882_storage": { + "encoding": "inplace", + "label": "struct VaultStorage.WithdrawalQueueMetadata", + "members": [ + { + "astId": 29875, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "queued", + "offset": 0, + "slot": "0", + "type": "t_uint128" + }, + { + "astId": 29877, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "claimable", + "offset": 16, + "slot": "0", + "type": "t_uint128" + }, + { + "astId": 29879, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "claimed", + "offset": 0, + "slot": "1", + "type": "t_uint128" + }, + { + "astId": 29881, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "nextWithdrawalIndex", + "offset": 16, + "slot": "1", + "type": "t_uint128" + } + ], + "numberOfBytes": "64" + }, + "t_struct(WithdrawalRequest)29894_storage": { + "encoding": "inplace", + "label": "struct VaultStorage.WithdrawalRequest", + "members": [ + { + "astId": 29887, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "withdrawer", + "offset": 0, + "slot": "0", + "type": "t_address" + }, + { + "astId": 29889, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "claimed", + "offset": 20, + "slot": "0", + "type": "t_bool" + }, + { + "astId": 29891, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "amount", + "offset": 0, + "slot": "1", + "type": "t_uint128" + }, + { + "astId": 29893, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "queued", + "offset": 16, + "slot": "1", + "type": "t_uint128" + } + ], + "numberOfBytes": "64" + }, + "t_uint128": { + "encoding": "inplace", + "label": "uint128", + "numberOfBytes": "16" + }, "t_uint16": { "encoding": "inplace", "label": "uint16", diff --git a/contracts/deployments/holesky/OETHVaultCore.json b/contracts/deployments/holesky/OETHVaultCore.json index d3580e13ac..97fc97998d 100644 --- a/contracts/deployments/holesky/OETHVaultCore.json +++ b/contracts/deployments/holesky/OETHVaultCore.json @@ -1,5 +1,5 @@ { - "address": "0xE92e25B81E44B8377Df1362f8fFBc426A00d6ef4", + "address": "0x89018e7e6994BBDDC0991743fd30fcEE18Ce4705", "abi": [ { "inputs": [ @@ -69,6 +69,19 @@ "name": "AssetDefaultStrategyUpdated", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_asset", + "type": "address" + } + ], + "name": "AssetRemoved", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -94,6 +107,19 @@ "name": "CapitalUnpaused", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_dripper", + "type": "address" + } + ], + "name": "DripperChanged", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -414,6 +440,81 @@ "name": "VaultBufferUpdated", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_claimable", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_newClaimable", + "type": "uint256" + } + ], + "name": "WithdrawalClaimable", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_withdrawer", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "_requestId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "WithdrawalClaimed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_withdrawer", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "_requestId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_queued", + "type": "uint256" + } + ], + "name": "WithdrawalRequested", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -443,6 +544,13 @@ "stateMutability": "nonpayable", "type": "fallback" }, + { + "inputs": [], + "name": "addWithdrawalQueueLiquidity", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [], "name": "allocate", @@ -560,6 +668,62 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "requestId", + "type": "uint256" + } + ], + "name": "claimWithdrawal", + "outputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[]", + "name": "requestIds", + "type": "uint256[]" + } + ], + "name": "claimWithdrawals", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "totalAmount", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "dripper", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "getAllAssets", @@ -932,6 +1096,30 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "requestWithdrawal", + "outputs": [ + { + "internalType": "uint256", + "name": "requestId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "queued", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -1048,52 +1236,117 @@ ], "stateMutability": "view", "type": "function" + }, + { + "inputs": [], + "name": "withdrawalQueueMetadata", + "outputs": [ + { + "internalType": "uint128", + "name": "queued", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "claimable", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "claimed", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "nextWithdrawalIndex", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "withdrawalRequests", + "outputs": [ + { + "internalType": "address", + "name": "withdrawer", + "type": "address" + }, + { + "internalType": "bool", + "name": "claimed", + "type": "bool" + }, + { + "internalType": "uint128", + "name": "amount", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "queued", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" } ], - "transactionHash": "0x9f75d36ce4de616c56e32c5f1e66ea8b705994a63d163d096f71d3e5c1eecdc1", + "transactionHash": "0xd28b24bfaa083ba1af8b408e526ed8dc917f6a372c757591c50fadfcf212d80c", "receipt": { "to": null, "from": "0x1b94CA50D3Ad9f8368851F8526132272d1a5028C", - "contractAddress": "0xE92e25B81E44B8377Df1362f8fFBc426A00d6ef4", - "transactionIndex": 68, - "gasUsed": "3024025", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000020000000000000000000800000000000000000000000000000000000004000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000010000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000080000000000000", - "blockHash": "0xf2aa29665c1af068ced76d7b539f3bcc67a7d534c1019c51316beecb731cbc01", - "transactionHash": "0x9f75d36ce4de616c56e32c5f1e66ea8b705994a63d163d096f71d3e5c1eecdc1", + "contractAddress": "0x89018e7e6994BBDDC0991743fd30fcEE18Ce4705", + "transactionIndex": 3, + "gasUsed": "3843460", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000020000100000000000000800000000000000000000000000000000000004000000000000002000000000000000000040000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000010000000000010000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x442c930bd060984abbdc0a15633fa1b620f25febac9df91a526e1c68e0bf25c7", + "transactionHash": "0xd28b24bfaa083ba1af8b408e526ed8dc917f6a372c757591c50fadfcf212d80c", "logs": [ { - "transactionIndex": 68, - "blockNumber": 1405063, - "transactionHash": "0x9f75d36ce4de616c56e32c5f1e66ea8b705994a63d163d096f71d3e5c1eecdc1", - "address": "0xE92e25B81E44B8377Df1362f8fFBc426A00d6ef4", + "transactionIndex": 3, + "blockNumber": 1860257, + "transactionHash": "0xd28b24bfaa083ba1af8b408e526ed8dc917f6a372c757591c50fadfcf212d80c", + "address": "0x89018e7e6994BBDDC0991743fd30fcEE18Ce4705", "topics": [ "0xc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000001b94ca50d3ad9f8368851f8526132272d1a5028c" ], "data": "0x", - "logIndex": 80, - "blockHash": "0xf2aa29665c1af068ced76d7b539f3bcc67a7d534c1019c51316beecb731cbc01" + "logIndex": 1, + "blockHash": "0x442c930bd060984abbdc0a15633fa1b620f25febac9df91a526e1c68e0bf25c7" } ], - "blockNumber": 1405063, - "cumulativeGasUsed": "14256235", + "blockNumber": 1860257, + "cumulativeGasUsed": "4298576", "status": 1, "byzantium": true }, "args": [ - "0x94373a4919b3240d86ea41593d5eba789fef3848" + "0x94373a4919B3240D86eA41593D5eBa789FEF3848" ], - "numDeployments": 1, - "solcInputHash": "da4c2bc4af0be4b969e54f8b43895033", - "metadata": "{\"compiler\":{\"version\":\"0.8.7+commit.e28d00a7\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_weth\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"AllocateThresholdUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_strategy\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"AssetAllocated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_strategy\",\"type\":\"address\"}],\"name\":\"AssetDefaultStrategyUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"AssetSupported\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"CapitalPaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"CapitalUnpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"GovernorshipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"maxSupplyDiff\",\"type\":\"uint256\"}],\"name\":\"MaxSupplyDiffChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"Mint\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"NetOusdMintForStrategyThresholdChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_ousdMetaStrategy\",\"type\":\"address\"}],\"name\":\"OusdMetaStrategyUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"PendingGovernorshipTransfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_priceProvider\",\"type\":\"address\"}],\"name\":\"PriceProviderUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"RebasePaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"RebaseThresholdUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"RebaseUnpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"Redeem\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_redeemFeeBps\",\"type\":\"uint256\"}],\"name\":\"RedeemFeeUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"StrategistUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"StrategyApproved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"StrategyRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_basis\",\"type\":\"uint256\"}],\"name\":\"SwapAllowedUndervalueChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_basis\",\"type\":\"uint256\"}],\"name\":\"SwapSlippageChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_fromAsset\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_toAsset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_fromAssetAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_toAssetAmount\",\"type\":\"uint256\"}],\"name\":\"Swapped\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"SwapperChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"TrusteeAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_basis\",\"type\":\"uint256\"}],\"name\":\"TrusteeFeeBpsChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_vaultBuffer\",\"type\":\"uint256\"}],\"name\":\"VaultBufferUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_yield\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_fee\",\"type\":\"uint256\"}],\"name\":\"YieldDistribution\",\"type\":\"event\"},{\"stateMutability\":\"nonpayable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"allocate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"assetDefaultStrategies\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"autoAllocateThreshold\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"burnForStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"cacheWETHAssetIndex\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"calculateRedeemOutputs\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"capitalPaused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"checkBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllAssets\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllStrategies\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"getAssetConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isSupported\",\"type\":\"bool\"},{\"internalType\":\"enum VaultStorage.UnitConversion\",\"name\":\"unitConversion\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"decimals\",\"type\":\"uint8\"},{\"internalType\":\"uint16\",\"name\":\"allowedOracleSlippageBps\",\"type\":\"uint16\"}],\"internalType\":\"struct VaultStorage.Asset\",\"name\":\"config\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAssetCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStrategyCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"governor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_priceProvider\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_oToken\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"isSupportedAsset\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maxSupplyDiff\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_minimumOusdAmount\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"mintForStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"netOusdMintForStrategyThreshold\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"netOusdMintedForStrategy\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"ousdMetaStrategy\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"priceProvider\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"asset\",\"type\":\"address\"}],\"name\":\"priceUnitMint\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"price\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"asset\",\"type\":\"address\"}],\"name\":\"priceUnitRedeem\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"price\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebase\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebasePaused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebaseThreshold\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_minimumUnitAmount\",\"type\":\"uint256\"}],\"name\":\"redeem\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_minimumUnitAmount\",\"type\":\"uint256\"}],\"name\":\"redeemAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"redeemFeeBps\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImpl\",\"type\":\"address\"}],\"name\":\"setAdminImpl\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"strategistAddr\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalValue\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newGovernor\",\"type\":\"address\"}],\"name\":\"transferGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"trusteeAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"trusteeFeeBps\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"vaultBuffer\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"weth\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wethAssetIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"Origin Protocol Inc\",\"kind\":\"dev\",\"methods\":{\"burnForStrategy(uint256)\":{\"details\":\"Notice: can't use `nonReentrant` modifier since the `redeem` function could require withdrawal on `ConvexOUSDMetaStrategy` and that one can call `burnForStrategy` while the execution of the `redeem` has not yet completed -> causing a `nonReentrant` collision. Also important to understand is that this is a limitation imposed by the test suite. Production / mainnet contracts should never be configured in a way where mint/redeem functions that are moving funds between the Vault and end user wallets can influence strategies utilizing this function.\",\"params\":{\"_amount\":\"Amount of OUSD to burn\"}},\"cacheWETHAssetIndex()\":{\"details\":\"Caches WETH's index in `allAssets` variable. Reduces gas usage by redeem by caching that.\"},\"checkBalance(address)\":{\"params\":{\"_asset\":\"Address of asset\"},\"returns\":{\"_0\":\"uint256 Balance of asset in decimals of asset\"}},\"isSupportedAsset(address)\":{\"params\":{\"_asset\":\"address of the asset\"},\"returns\":{\"_0\":\"true if supported\"}},\"mint(address,uint256,uint256)\":{\"params\":{\"_amount\":\"Amount of the asset being deposited\",\"_asset\":\"Address of the asset being deposited\",\"_minimumOusdAmount\":\"Minimum OTokens to mint\"}},\"mintForStrategy(uint256)\":{\"params\":{\"_amount\":\"Amount of the asset being deposited Notice: can't use `nonReentrant` modifier since the `mint` function can call `allocate`, and that can trigger `ConvexOUSDMetaStrategy` to call this function while the execution of the `mint` has not yet completed -> causing a `nonReentrant` collision. Also important to understand is that this is a limitation imposed by the test suite. Production / mainnet contracts should never be configured in a way where mint/redeem functions that are moving funds between the Vault and end user wallets can influence strategies utilizing this function.\"}},\"priceUnitMint(address)\":{\"params\":{\"asset\":\"address of the asset\"},\"returns\":{\"price\":\"uint256: unit (USD / ETH) price for 1 unit of the asset, in 18 decimal fixed\"}},\"priceUnitRedeem(address)\":{\"params\":{\"asset\":\"Address of the asset\"},\"returns\":{\"price\":\"uint256: unit (USD / ETH) price for 1 unit of the asset, in 18 decimal fixed\"}},\"redeem(uint256,uint256)\":{\"params\":{\"_amount\":\"Amount of OTokens to burn\",\"_minimumUnitAmount\":\"Minimum stablecoin units to receive in return\"}},\"redeemAll(uint256)\":{\"params\":{\"_minimumUnitAmount\":\"Minimum stablecoin units to receive in return\"}},\"setAdminImpl(address)\":{\"params\":{\"newImpl\":\"address of the implementation\"}},\"totalValue()\":{\"returns\":{\"value\":\"Total value in USD/ETH (1e18)\"}},\"transferGovernance(address)\":{\"params\":{\"_newGovernor\":\"Address of the new Governor\"}}},\"title\":\"OETH VaultCore Contract\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"allocate()\":{\"notice\":\"Allocate unallocated funds on Vault to strategies.*\"},\"assetDefaultStrategies(address)\":{\"notice\":\"Mapping of asset address to the Strategy that they should automatically\"},\"autoAllocateThreshold()\":{\"notice\":\"OToken mints over this amount automatically allocate funds. 18 decimals.\"},\"burnForStrategy(uint256)\":{\"notice\":\"Burn OTokens for Metapool Strategy\"},\"calculateRedeemOutputs(uint256)\":{\"notice\":\"Calculate the outputs for a redeem function, i.e. the mix of coins that will be returned\"},\"capitalPaused()\":{\"notice\":\"pause operations that change the OToken supply. eg mint, redeem, allocate, mint/burn for strategy\"},\"checkBalance(address)\":{\"notice\":\"Get the balance of an asset held in Vault and all strategies.\"},\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"getAllAssets()\":{\"notice\":\"Return all vault asset addresses in order\"},\"getAllStrategies()\":{\"notice\":\"Return the array of all strategies\"},\"getAssetConfig(address)\":{\"notice\":\"Gets the vault configuration of a supported asset.\"},\"getAssetCount()\":{\"notice\":\"Return the number of assets supported by the Vault.\"},\"getStrategyCount()\":{\"notice\":\"Return the number of strategies active on the Vault.\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"isSupportedAsset(address)\":{\"notice\":\"Returns whether the vault supports the asset\"},\"maxSupplyDiff()\":{\"notice\":\"Max difference between total supply and total value of assets. 18 decimals.\"},\"mint(address,uint256,uint256)\":{\"notice\":\"Deposit a supported asset and mint OTokens.\"},\"mintForStrategy(uint256)\":{\"notice\":\"Mint OTokens for a Metapool Strategy\"},\"netOusdMintForStrategyThreshold()\":{\"notice\":\"How much net total OTokens are allowed to be minted by all strategies\"},\"netOusdMintedForStrategy()\":{\"notice\":\"How much OTokens are currently minted by the strategy\"},\"ousdMetaStrategy()\":{\"notice\":\"Metapool strategy that is allowed to mint/burn OTokens without changing collateral\"},\"priceProvider()\":{\"notice\":\"Address of the Oracle price provider contract\"},\"priceUnitMint(address)\":{\"notice\":\"Returns the total price in 18 digit units for a given asset. Never goes above 1, since that is how we price mints.\"},\"priceUnitRedeem(address)\":{\"notice\":\"Returns the total price in 18 digit unit for a given asset. Never goes below 1, since that is how we price redeems\"},\"rebase()\":{\"notice\":\"Calculate the total value of assets held by the Vault and all strategies and update the supply of OTokens.\"},\"rebasePaused()\":{\"notice\":\"pause rebasing if true\"},\"rebaseThreshold()\":{\"notice\":\"OToken mints over this amount automatically rebase. 18 decimals.\"},\"redeem(uint256,uint256)\":{\"notice\":\"Withdraw a supported asset and burn OTokens.\"},\"redeemAll(uint256)\":{\"notice\":\"Withdraw a supported asset and burn all OTokens.\"},\"redeemFeeBps()\":{\"notice\":\"Redemption fee in basis points. eg 50 = 0.5%\"},\"setAdminImpl(address)\":{\"notice\":\"set the implementation for the admin, this needs to be in a base class else we cannot set it\"},\"strategistAddr()\":{\"notice\":\"Address of the Strategist\"},\"totalValue()\":{\"notice\":\"Determine the total value of assets held by the vault and its strategies.\"},\"transferGovernance(address)\":{\"notice\":\"Transfers Governance of the contract to a new account (`newGovernor`). Can only be called by the current Governor. Must be claimed for this to complete\"},\"trusteeAddress()\":{\"notice\":\"Trustee contract that can collect a percentage of yield\"},\"trusteeFeeBps()\":{\"notice\":\"Amount of yield collected in basis points. eg 2000 = 20%\"},\"vaultBuffer()\":{\"notice\":\"Percentage of assets to keep in Vault to handle (most) withdrawals. 100% = 1e18.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/vault/OETHVaultCore.sol\":\"OETHVaultCore\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address recipient, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address sender,\\n address recipient,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0x61437cb513a887a1bbad006e7b1c8b414478427d33de47c5600af3c748f108da\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Address.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize, which returns 0 for contracts in\\n // construction, since the code is only stored at the end of the\\n // constructor execution.\\n\\n uint256 size;\\n assembly {\\n size := extcodesize(account)\\n }\\n return size > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x51b758a8815ecc9596c66c37d56b1d33883a444631a3f916b9fe65cb863ef7c4\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/math/SafeMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\\n\\npragma solidity ^0.8.0;\\n\\n// CAUTION\\n// This version of SafeMath should only be used with Solidity 0.8 or later,\\n// because it relies on the compiler's built in overflow checks.\\n\\n/**\\n * @dev Wrappers over Solidity's arithmetic operations.\\n *\\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\\n * now has built in overflow checking.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n uint256 c = a + b;\\n if (c < a) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b > a) return (false, 0);\\n return (true, a - b);\\n }\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) return (true, 0);\\n uint256 c = a * b;\\n if (c / a != b) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a / b);\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a % b);\\n }\\n }\\n\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n *\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a + b;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n *\\n * - Subtraction cannot overflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a - b;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n *\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a * b;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator.\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a / b;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a % b;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\\n * overflow (when the result is negative).\\n *\\n * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {trySub}.\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n *\\n * - Subtraction cannot overflow.\\n */\\n function sub(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b <= a, errorMessage);\\n return a - b;\\n }\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function div(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a / b;\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting with custom message when dividing by zero.\\n *\\n * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {tryMod}.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function mod(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a % b;\\n }\\n }\\n}\\n\",\"keccak256\":\"0xa2f576be637946f767aa56601c26d717f48a0aff44f82e46f13807eea1009a21\",\"license\":\"MIT\"},\"contracts/governance/Governable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Base for contracts that are managed by the Origin Protocol's Governor.\\n * @dev Copy of the openzeppelin Ownable.sol contract with nomenclature change\\n * from owner to governor and renounce methods removed. Does not use\\n * Context.sol like Ownable.sol does for simplification.\\n * @author Origin Protocol Inc\\n */\\ncontract Governable {\\n // Storage position of the owner and pendingOwner of the contract\\n // keccak256(\\\"OUSD.governor\\\");\\n bytes32 private constant governorPosition =\\n 0x7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a;\\n\\n // keccak256(\\\"OUSD.pending.governor\\\");\\n bytes32 private constant pendingGovernorPosition =\\n 0x44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db;\\n\\n // keccak256(\\\"OUSD.reentry.status\\\");\\n bytes32 private constant reentryStatusPosition =\\n 0x53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac4535;\\n\\n // See OpenZeppelin ReentrancyGuard implementation\\n uint256 constant _NOT_ENTERED = 1;\\n uint256 constant _ENTERED = 2;\\n\\n event PendingGovernorshipTransfer(\\n address indexed previousGovernor,\\n address indexed newGovernor\\n );\\n\\n event GovernorshipTransferred(\\n address indexed previousGovernor,\\n address indexed newGovernor\\n );\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial Governor.\\n */\\n constructor() {\\n _setGovernor(msg.sender);\\n emit GovernorshipTransferred(address(0), _governor());\\n }\\n\\n /**\\n * @notice Returns the address of the current Governor.\\n */\\n function governor() public view returns (address) {\\n return _governor();\\n }\\n\\n /**\\n * @dev Returns the address of the current Governor.\\n */\\n function _governor() internal view returns (address governorOut) {\\n bytes32 position = governorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n governorOut := sload(position)\\n }\\n }\\n\\n /**\\n * @dev Returns the address of the pending Governor.\\n */\\n function _pendingGovernor()\\n internal\\n view\\n returns (address pendingGovernor)\\n {\\n bytes32 position = pendingGovernorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n pendingGovernor := sload(position)\\n }\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the Governor.\\n */\\n modifier onlyGovernor() {\\n require(isGovernor(), \\\"Caller is not the Governor\\\");\\n _;\\n }\\n\\n /**\\n * @notice Returns true if the caller is the current Governor.\\n */\\n function isGovernor() public view returns (bool) {\\n return msg.sender == _governor();\\n }\\n\\n function _setGovernor(address newGovernor) internal {\\n bytes32 position = governorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, newGovernor)\\n }\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a `nonReentrant` function from another `nonReentrant`\\n * function is not supported. It is possible to prevent this from happening\\n * by making the `nonReentrant` function external, and make it call a\\n * `private` function that does the actual work.\\n */\\n modifier nonReentrant() {\\n bytes32 position = reentryStatusPosition;\\n uint256 _reentry_status;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n _reentry_status := sload(position)\\n }\\n\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_reentry_status != _ENTERED, \\\"Reentrant call\\\");\\n\\n // Any calls to nonReentrant after this point will fail\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, _ENTERED)\\n }\\n\\n _;\\n\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, _NOT_ENTERED)\\n }\\n }\\n\\n function _setPendingGovernor(address newGovernor) internal {\\n bytes32 position = pendingGovernorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, newGovernor)\\n }\\n }\\n\\n /**\\n * @notice Transfers Governance of the contract to a new account (`newGovernor`).\\n * Can only be called by the current Governor. Must be claimed for this to complete\\n * @param _newGovernor Address of the new Governor\\n */\\n function transferGovernance(address _newGovernor) external onlyGovernor {\\n _setPendingGovernor(_newGovernor);\\n emit PendingGovernorshipTransfer(_governor(), _newGovernor);\\n }\\n\\n /**\\n * @notice Claim Governance of the contract to a new account (`newGovernor`).\\n * Can only be called by the new Governor.\\n */\\n function claimGovernance() external {\\n require(\\n msg.sender == _pendingGovernor(),\\n \\\"Only the pending Governor can complete the claim\\\"\\n );\\n _changeGovernor(msg.sender);\\n }\\n\\n /**\\n * @dev Change Governance of the contract to a new account (`newGovernor`).\\n * @param _newGovernor Address of the new Governor\\n */\\n function _changeGovernor(address _newGovernor) internal {\\n require(_newGovernor != address(0), \\\"New Governor is address(0)\\\");\\n emit GovernorshipTransferred(_governor(), _newGovernor);\\n _setGovernor(_newGovernor);\\n }\\n}\\n\",\"keccak256\":\"0xb7133d6ce7a9e673ff79fcedb3fd41ae6e58e251f94915bb65731abe524270b4\",\"license\":\"MIT\"},\"contracts/interfaces/IBasicToken.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IBasicToken {\\n function symbol() external view returns (string memory);\\n\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0xa562062698aa12572123b36dfd2072f1a39e44fed2031cc19c2c9fd522f96ec2\",\"license\":\"MIT\"},\"contracts/interfaces/IGetExchangeRateToken.sol\":{\"content\":\"pragma solidity ^0.8.0;\\n\\ninterface IGetExchangeRateToken {\\n function getExchangeRate() external view returns (uint256 _exchangeRate);\\n}\\n\",\"keccak256\":\"0x641d5892d570f3f9e256d39a9571e58b02c39368726b01c4cdf7d91f45e349d8\"},\"contracts/interfaces/IOracle.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IOracle {\\n /**\\n * @dev returns the asset price in USD, in 8 decimal digits.\\n *\\n * The version of priceProvider deployed for OETH has 18 decimal digits\\n */\\n function price(address asset) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0x9eabf152389f145c9c23ed71972af73fb1708cbc4b26e524a9ba29a557b7cfe5\",\"license\":\"MIT\"},\"contracts/interfaces/IStrategy.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Platform interface to integrate with lending platform like Compound, AAVE etc.\\n */\\ninterface IStrategy {\\n /**\\n * @dev Deposit the given asset to platform\\n * @param _asset asset address\\n * @param _amount Amount to deposit\\n */\\n function deposit(address _asset, uint256 _amount) external;\\n\\n /**\\n * @dev Deposit the entire balance of all supported assets in the Strategy\\n * to the platform\\n */\\n function depositAll() external;\\n\\n /**\\n * @dev Withdraw given asset from Lending platform\\n */\\n function withdraw(\\n address _recipient,\\n address _asset,\\n uint256 _amount\\n ) external;\\n\\n /**\\n * @dev Liquidate all assets in strategy and return them to Vault.\\n */\\n function withdrawAll() external;\\n\\n /**\\n * @dev Returns the current balance of the given asset.\\n */\\n function checkBalance(address _asset)\\n external\\n view\\n returns (uint256 balance);\\n\\n /**\\n * @dev Returns bool indicating whether strategy supports asset.\\n */\\n function supportsAsset(address _asset) external view returns (bool);\\n\\n /**\\n * @dev Collect reward tokens from the Strategy.\\n */\\n function collectRewardTokens() external;\\n\\n /**\\n * @dev The address array of the reward tokens for the Strategy.\\n */\\n function getRewardTokenAddresses() external view returns (address[] memory);\\n}\\n\",\"keccak256\":\"0xb291e409a9b95527f9ed19cd6bff8eeb9921a21c1f5194a48c0bb9ce6613959a\",\"license\":\"MIT\"},\"contracts/token/OUSD.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OUSD Token Contract\\n * @dev ERC20 compatible contract for OUSD\\n * @dev Implements an elastic supply\\n * @author Origin Protocol Inc\\n */\\nimport { SafeMath } from \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\nimport { Address } from \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport { Initializable } from \\\"../utils/Initializable.sol\\\";\\nimport { InitializableERC20Detailed } from \\\"../utils/InitializableERC20Detailed.sol\\\";\\nimport { StableMath } from \\\"../utils/StableMath.sol\\\";\\nimport { Governable } from \\\"../governance/Governable.sol\\\";\\n\\n/**\\n * NOTE that this is an ERC20 token but the invariant that the sum of\\n * balanceOf(x) for all x is not >= totalSupply(). This is a consequence of the\\n * rebasing design. Any integrations with OUSD should be aware.\\n */\\n\\ncontract OUSD is Initializable, InitializableERC20Detailed, Governable {\\n using SafeMath for uint256;\\n using StableMath for uint256;\\n\\n event TotalSupplyUpdatedHighres(\\n uint256 totalSupply,\\n uint256 rebasingCredits,\\n uint256 rebasingCreditsPerToken\\n );\\n event AccountRebasingEnabled(address account);\\n event AccountRebasingDisabled(address account);\\n\\n enum RebaseOptions {\\n NotSet,\\n OptOut,\\n OptIn\\n }\\n\\n uint256 private constant MAX_SUPPLY = ~uint128(0); // (2^128) - 1\\n uint256 public _totalSupply;\\n mapping(address => mapping(address => uint256)) private _allowances;\\n address public vaultAddress = address(0);\\n mapping(address => uint256) private _creditBalances;\\n uint256 private _rebasingCredits;\\n uint256 private _rebasingCreditsPerToken;\\n // Frozen address/credits are non rebasing (value is held in contracts which\\n // do not receive yield unless they explicitly opt in)\\n uint256 public nonRebasingSupply;\\n mapping(address => uint256) public nonRebasingCreditsPerToken;\\n mapping(address => RebaseOptions) public rebaseState;\\n mapping(address => uint256) public isUpgraded;\\n\\n uint256 private constant RESOLUTION_INCREASE = 1e9;\\n\\n function initialize(\\n string calldata _nameArg,\\n string calldata _symbolArg,\\n address _vaultAddress,\\n uint256 _initialCreditsPerToken\\n ) external onlyGovernor initializer {\\n InitializableERC20Detailed._initialize(_nameArg, _symbolArg, 18);\\n _rebasingCreditsPerToken = _initialCreditsPerToken;\\n vaultAddress = _vaultAddress;\\n }\\n\\n /**\\n * @dev Verifies that the caller is the Vault contract\\n */\\n modifier onlyVault() {\\n require(vaultAddress == msg.sender, \\\"Caller is not the Vault\\\");\\n _;\\n }\\n\\n /**\\n * @return The total supply of OUSD.\\n */\\n function totalSupply() public view override returns (uint256) {\\n return _totalSupply;\\n }\\n\\n /**\\n * @return Low resolution rebasingCreditsPerToken\\n */\\n function rebasingCreditsPerToken() public view returns (uint256) {\\n return _rebasingCreditsPerToken / RESOLUTION_INCREASE;\\n }\\n\\n /**\\n * @return Low resolution total number of rebasing credits\\n */\\n function rebasingCredits() public view returns (uint256) {\\n return _rebasingCredits / RESOLUTION_INCREASE;\\n }\\n\\n /**\\n * @return High resolution rebasingCreditsPerToken\\n */\\n function rebasingCreditsPerTokenHighres() public view returns (uint256) {\\n return _rebasingCreditsPerToken;\\n }\\n\\n /**\\n * @return High resolution total number of rebasing credits\\n */\\n function rebasingCreditsHighres() public view returns (uint256) {\\n return _rebasingCredits;\\n }\\n\\n /**\\n * @dev Gets the balance of the specified address.\\n * @param _account Address to query the balance of.\\n * @return A uint256 representing the amount of base units owned by the\\n * specified address.\\n */\\n function balanceOf(address _account)\\n public\\n view\\n override\\n returns (uint256)\\n {\\n if (_creditBalances[_account] == 0) return 0;\\n return\\n _creditBalances[_account].divPrecisely(_creditsPerToken(_account));\\n }\\n\\n /**\\n * @dev Gets the credits balance of the specified address.\\n * @dev Backwards compatible with old low res credits per token.\\n * @param _account The address to query the balance of.\\n * @return (uint256, uint256) Credit balance and credits per token of the\\n * address\\n */\\n function creditsBalanceOf(address _account)\\n public\\n view\\n returns (uint256, uint256)\\n {\\n uint256 cpt = _creditsPerToken(_account);\\n if (cpt == 1e27) {\\n // For a period before the resolution upgrade, we created all new\\n // contract accounts at high resolution. Since they are not changing\\n // as a result of this upgrade, we will return their true values\\n return (_creditBalances[_account], cpt);\\n } else {\\n return (\\n _creditBalances[_account] / RESOLUTION_INCREASE,\\n cpt / RESOLUTION_INCREASE\\n );\\n }\\n }\\n\\n /**\\n * @dev Gets the credits balance of the specified address.\\n * @param _account The address to query the balance of.\\n * @return (uint256, uint256, bool) Credit balance, credits per token of the\\n * address, and isUpgraded\\n */\\n function creditsBalanceOfHighres(address _account)\\n public\\n view\\n returns (\\n uint256,\\n uint256,\\n bool\\n )\\n {\\n return (\\n _creditBalances[_account],\\n _creditsPerToken(_account),\\n isUpgraded[_account] == 1\\n );\\n }\\n\\n /**\\n * @dev Transfer tokens to a specified address.\\n * @param _to the address to transfer to.\\n * @param _value the amount to be transferred.\\n * @return true on success.\\n */\\n function transfer(address _to, uint256 _value)\\n public\\n override\\n returns (bool)\\n {\\n require(_to != address(0), \\\"Transfer to zero address\\\");\\n require(\\n _value <= balanceOf(msg.sender),\\n \\\"Transfer greater than balance\\\"\\n );\\n\\n _executeTransfer(msg.sender, _to, _value);\\n\\n emit Transfer(msg.sender, _to, _value);\\n\\n return true;\\n }\\n\\n /**\\n * @dev Transfer tokens from one address to another.\\n * @param _from The address you want to send tokens from.\\n * @param _to The address you want to transfer to.\\n * @param _value The amount of tokens to be transferred.\\n */\\n function transferFrom(\\n address _from,\\n address _to,\\n uint256 _value\\n ) public override returns (bool) {\\n require(_to != address(0), \\\"Transfer to zero address\\\");\\n require(_value <= balanceOf(_from), \\\"Transfer greater than balance\\\");\\n\\n _allowances[_from][msg.sender] = _allowances[_from][msg.sender].sub(\\n _value\\n );\\n\\n _executeTransfer(_from, _to, _value);\\n\\n emit Transfer(_from, _to, _value);\\n\\n return true;\\n }\\n\\n /**\\n * @dev Update the count of non rebasing credits in response to a transfer\\n * @param _from The address you want to send tokens from.\\n * @param _to The address you want to transfer to.\\n * @param _value Amount of OUSD to transfer\\n */\\n function _executeTransfer(\\n address _from,\\n address _to,\\n uint256 _value\\n ) internal {\\n bool isNonRebasingTo = _isNonRebasingAccount(_to);\\n bool isNonRebasingFrom = _isNonRebasingAccount(_from);\\n\\n // Credits deducted and credited might be different due to the\\n // differing creditsPerToken used by each account\\n uint256 creditsCredited = _value.mulTruncate(_creditsPerToken(_to));\\n uint256 creditsDeducted = _value.mulTruncate(_creditsPerToken(_from));\\n\\n _creditBalances[_from] = _creditBalances[_from].sub(\\n creditsDeducted,\\n \\\"Transfer amount exceeds balance\\\"\\n );\\n _creditBalances[_to] = _creditBalances[_to].add(creditsCredited);\\n\\n if (isNonRebasingTo && !isNonRebasingFrom) {\\n // Transfer to non-rebasing account from rebasing account, credits\\n // are removed from the non rebasing tally\\n nonRebasingSupply = nonRebasingSupply.add(_value);\\n // Update rebasingCredits by subtracting the deducted amount\\n _rebasingCredits = _rebasingCredits.sub(creditsDeducted);\\n } else if (!isNonRebasingTo && isNonRebasingFrom) {\\n // Transfer to rebasing account from non-rebasing account\\n // Decreasing non-rebasing credits by the amount that was sent\\n nonRebasingSupply = nonRebasingSupply.sub(_value);\\n // Update rebasingCredits by adding the credited amount\\n _rebasingCredits = _rebasingCredits.add(creditsCredited);\\n }\\n }\\n\\n /**\\n * @dev Function to check the amount of tokens that _owner has allowed to\\n * `_spender`.\\n * @param _owner The address which owns the funds.\\n * @param _spender The address which will spend the funds.\\n * @return The number of tokens still available for the _spender.\\n */\\n function allowance(address _owner, address _spender)\\n public\\n view\\n override\\n returns (uint256)\\n {\\n return _allowances[_owner][_spender];\\n }\\n\\n /**\\n * @dev Approve the passed address to spend the specified amount of tokens\\n * on behalf of msg.sender. This method is included for ERC20\\n * compatibility. `increaseAllowance` and `decreaseAllowance` should be\\n * used instead.\\n *\\n * Changing an allowance with this method brings the risk that someone\\n * may transfer both the old and the new allowance - if they are both\\n * greater than zero - if a transfer transaction is mined before the\\n * later approve() call is mined.\\n * @param _spender The address which will spend the funds.\\n * @param _value The amount of tokens to be spent.\\n */\\n function approve(address _spender, uint256 _value)\\n public\\n override\\n returns (bool)\\n {\\n _allowances[msg.sender][_spender] = _value;\\n emit Approval(msg.sender, _spender, _value);\\n return true;\\n }\\n\\n /**\\n * @dev Increase the amount of tokens that an owner has allowed to\\n * `_spender`.\\n * This method should be used instead of approve() to avoid the double\\n * approval vulnerability described above.\\n * @param _spender The address which will spend the funds.\\n * @param _addedValue The amount of tokens to increase the allowance by.\\n */\\n function increaseAllowance(address _spender, uint256 _addedValue)\\n public\\n returns (bool)\\n {\\n _allowances[msg.sender][_spender] = _allowances[msg.sender][_spender]\\n .add(_addedValue);\\n emit Approval(msg.sender, _spender, _allowances[msg.sender][_spender]);\\n return true;\\n }\\n\\n /**\\n * @dev Decrease the amount of tokens that an owner has allowed to\\n `_spender`.\\n * @param _spender The address which will spend the funds.\\n * @param _subtractedValue The amount of tokens to decrease the allowance\\n * by.\\n */\\n function decreaseAllowance(address _spender, uint256 _subtractedValue)\\n public\\n returns (bool)\\n {\\n uint256 oldValue = _allowances[msg.sender][_spender];\\n if (_subtractedValue >= oldValue) {\\n _allowances[msg.sender][_spender] = 0;\\n } else {\\n _allowances[msg.sender][_spender] = oldValue.sub(_subtractedValue);\\n }\\n emit Approval(msg.sender, _spender, _allowances[msg.sender][_spender]);\\n return true;\\n }\\n\\n /**\\n * @dev Mints new tokens, increasing totalSupply.\\n */\\n function mint(address _account, uint256 _amount) external onlyVault {\\n _mint(_account, _amount);\\n }\\n\\n /**\\n * @dev Creates `_amount` tokens and assigns them to `_account`, increasing\\n * the total supply.\\n *\\n * Emits a {Transfer} event with `from` set to the zero address.\\n *\\n * Requirements\\n *\\n * - `to` cannot be the zero address.\\n */\\n function _mint(address _account, uint256 _amount) internal nonReentrant {\\n require(_account != address(0), \\\"Mint to the zero address\\\");\\n\\n bool isNonRebasingAccount = _isNonRebasingAccount(_account);\\n\\n uint256 creditAmount = _amount.mulTruncate(_creditsPerToken(_account));\\n _creditBalances[_account] = _creditBalances[_account].add(creditAmount);\\n\\n // If the account is non rebasing and doesn't have a set creditsPerToken\\n // then set it i.e. this is a mint from a fresh contract\\n if (isNonRebasingAccount) {\\n nonRebasingSupply = nonRebasingSupply.add(_amount);\\n } else {\\n _rebasingCredits = _rebasingCredits.add(creditAmount);\\n }\\n\\n _totalSupply = _totalSupply.add(_amount);\\n\\n require(_totalSupply < MAX_SUPPLY, \\\"Max supply\\\");\\n\\n emit Transfer(address(0), _account, _amount);\\n }\\n\\n /**\\n * @dev Burns tokens, decreasing totalSupply.\\n */\\n function burn(address account, uint256 amount) external onlyVault {\\n _burn(account, amount);\\n }\\n\\n /**\\n * @dev Destroys `_amount` tokens from `_account`, reducing the\\n * total supply.\\n *\\n * Emits a {Transfer} event with `to` set to the zero address.\\n *\\n * Requirements\\n *\\n * - `_account` cannot be the zero address.\\n * - `_account` must have at least `_amount` tokens.\\n */\\n function _burn(address _account, uint256 _amount) internal nonReentrant {\\n require(_account != address(0), \\\"Burn from the zero address\\\");\\n if (_amount == 0) {\\n return;\\n }\\n\\n bool isNonRebasingAccount = _isNonRebasingAccount(_account);\\n uint256 creditAmount = _amount.mulTruncate(_creditsPerToken(_account));\\n uint256 currentCredits = _creditBalances[_account];\\n\\n // Remove the credits, burning rounding errors\\n if (\\n currentCredits == creditAmount || currentCredits - 1 == creditAmount\\n ) {\\n // Handle dust from rounding\\n _creditBalances[_account] = 0;\\n } else if (currentCredits > creditAmount) {\\n _creditBalances[_account] = _creditBalances[_account].sub(\\n creditAmount\\n );\\n } else {\\n revert(\\\"Remove exceeds balance\\\");\\n }\\n\\n // Remove from the credit tallies and non-rebasing supply\\n if (isNonRebasingAccount) {\\n nonRebasingSupply = nonRebasingSupply.sub(_amount);\\n } else {\\n _rebasingCredits = _rebasingCredits.sub(creditAmount);\\n }\\n\\n _totalSupply = _totalSupply.sub(_amount);\\n\\n emit Transfer(_account, address(0), _amount);\\n }\\n\\n /**\\n * @dev Get the credits per token for an account. Returns a fixed amount\\n * if the account is non-rebasing.\\n * @param _account Address of the account.\\n */\\n function _creditsPerToken(address _account)\\n internal\\n view\\n returns (uint256)\\n {\\n if (nonRebasingCreditsPerToken[_account] != 0) {\\n return nonRebasingCreditsPerToken[_account];\\n } else {\\n return _rebasingCreditsPerToken;\\n }\\n }\\n\\n /**\\n * @dev Is an account using rebasing accounting or non-rebasing accounting?\\n * Also, ensure contracts are non-rebasing if they have not opted in.\\n * @param _account Address of the account.\\n */\\n function _isNonRebasingAccount(address _account) internal returns (bool) {\\n bool isContract = Address.isContract(_account);\\n if (isContract && rebaseState[_account] == RebaseOptions.NotSet) {\\n _ensureRebasingMigration(_account);\\n }\\n return nonRebasingCreditsPerToken[_account] > 0;\\n }\\n\\n /**\\n * @dev Ensures internal account for rebasing and non-rebasing credits and\\n * supply is updated following deployment of frozen yield change.\\n */\\n function _ensureRebasingMigration(address _account) internal {\\n if (nonRebasingCreditsPerToken[_account] == 0) {\\n emit AccountRebasingDisabled(_account);\\n if (_creditBalances[_account] == 0) {\\n // Since there is no existing balance, we can directly set to\\n // high resolution, and do not have to do any other bookkeeping\\n nonRebasingCreditsPerToken[_account] = 1e27;\\n } else {\\n // Migrate an existing account:\\n\\n // Set fixed credits per token for this account\\n nonRebasingCreditsPerToken[_account] = _rebasingCreditsPerToken;\\n // Update non rebasing supply\\n nonRebasingSupply = nonRebasingSupply.add(balanceOf(_account));\\n // Update credit tallies\\n _rebasingCredits = _rebasingCredits.sub(\\n _creditBalances[_account]\\n );\\n }\\n }\\n }\\n\\n /**\\n * @notice Enable rebasing for an account.\\n * @dev Add a contract address to the non-rebasing exception list. The\\n * address's balance will be part of rebases and the account will be exposed\\n * to upside and downside.\\n * @param _account Address of the account.\\n */\\n function governanceRebaseOptIn(address _account)\\n public\\n nonReentrant\\n onlyGovernor\\n {\\n _rebaseOptIn(_account);\\n }\\n\\n /**\\n * @dev Add a contract address to the non-rebasing exception list. The\\n * address's balance will be part of rebases and the account will be exposed\\n * to upside and downside.\\n */\\n function rebaseOptIn() public nonReentrant {\\n _rebaseOptIn(msg.sender);\\n }\\n\\n function _rebaseOptIn(address _account) internal {\\n require(_isNonRebasingAccount(_account), \\\"Account has not opted out\\\");\\n\\n // Convert balance into the same amount at the current exchange rate\\n uint256 newCreditBalance = _creditBalances[_account]\\n .mul(_rebasingCreditsPerToken)\\n .div(_creditsPerToken(_account));\\n\\n // Decreasing non rebasing supply\\n nonRebasingSupply = nonRebasingSupply.sub(balanceOf(_account));\\n\\n _creditBalances[_account] = newCreditBalance;\\n\\n // Increase rebasing credits, totalSupply remains unchanged so no\\n // adjustment necessary\\n _rebasingCredits = _rebasingCredits.add(_creditBalances[_account]);\\n\\n rebaseState[_account] = RebaseOptions.OptIn;\\n\\n // Delete any fixed credits per token\\n delete nonRebasingCreditsPerToken[_account];\\n emit AccountRebasingEnabled(_account);\\n }\\n\\n /**\\n * @dev Explicitly mark that an address is non-rebasing.\\n */\\n function rebaseOptOut() public nonReentrant {\\n require(!_isNonRebasingAccount(msg.sender), \\\"Account has not opted in\\\");\\n\\n // Increase non rebasing supply\\n nonRebasingSupply = nonRebasingSupply.add(balanceOf(msg.sender));\\n // Set fixed credits per token\\n nonRebasingCreditsPerToken[msg.sender] = _rebasingCreditsPerToken;\\n\\n // Decrease rebasing credits, total supply remains unchanged so no\\n // adjustment necessary\\n _rebasingCredits = _rebasingCredits.sub(_creditBalances[msg.sender]);\\n\\n // Mark explicitly opted out of rebasing\\n rebaseState[msg.sender] = RebaseOptions.OptOut;\\n emit AccountRebasingDisabled(msg.sender);\\n }\\n\\n /**\\n * @dev Modify the supply without minting new tokens. This uses a change in\\n * the exchange rate between \\\"credits\\\" and OUSD tokens to change balances.\\n * @param _newTotalSupply New total supply of OUSD.\\n */\\n function changeSupply(uint256 _newTotalSupply)\\n external\\n onlyVault\\n nonReentrant\\n {\\n require(_totalSupply > 0, \\\"Cannot increase 0 supply\\\");\\n\\n if (_totalSupply == _newTotalSupply) {\\n emit TotalSupplyUpdatedHighres(\\n _totalSupply,\\n _rebasingCredits,\\n _rebasingCreditsPerToken\\n );\\n return;\\n }\\n\\n _totalSupply = _newTotalSupply > MAX_SUPPLY\\n ? MAX_SUPPLY\\n : _newTotalSupply;\\n\\n _rebasingCreditsPerToken = _rebasingCredits.divPrecisely(\\n _totalSupply.sub(nonRebasingSupply)\\n );\\n\\n require(_rebasingCreditsPerToken > 0, \\\"Invalid change in supply\\\");\\n\\n _totalSupply = _rebasingCredits\\n .divPrecisely(_rebasingCreditsPerToken)\\n .add(nonRebasingSupply);\\n\\n emit TotalSupplyUpdatedHighres(\\n _totalSupply,\\n _rebasingCredits,\\n _rebasingCreditsPerToken\\n );\\n }\\n}\\n\",\"keccak256\":\"0x2dc66b1ba02716d64eb47dd9117fda62650d8b57669e6c351437e0ad29ad5f19\",\"license\":\"MIT\"},\"contracts/utils/Helpers.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { IBasicToken } from \\\"../interfaces/IBasicToken.sol\\\";\\n\\nlibrary Helpers {\\n /**\\n * @notice Fetch the `symbol()` from an ERC20 token\\n * @dev Grabs the `symbol()` from a contract\\n * @param _token Address of the ERC20 token\\n * @return string Symbol of the ERC20 token\\n */\\n function getSymbol(address _token) internal view returns (string memory) {\\n string memory symbol = IBasicToken(_token).symbol();\\n return symbol;\\n }\\n\\n /**\\n * @notice Fetch the `decimals()` from an ERC20 token\\n * @dev Grabs the `decimals()` from a contract and fails if\\n * the decimal value does not live within a certain range\\n * @param _token Address of the ERC20 token\\n * @return uint256 Decimals of the ERC20 token\\n */\\n function getDecimals(address _token) internal view returns (uint256) {\\n uint256 decimals = IBasicToken(_token).decimals();\\n require(\\n decimals >= 4 && decimals <= 18,\\n \\\"Token must have sufficient decimal places\\\"\\n );\\n\\n return decimals;\\n }\\n}\\n\",\"keccak256\":\"0x108b7a69e0140da0072ca18f90a03a3340574400f81aa6076cd2cccdf13699c2\",\"license\":\"MIT\"},\"contracts/utils/Initializable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Base contract any contracts that need to initialize state after deployment.\\n * @author Origin Protocol Inc\\n */\\nabstract contract Initializable {\\n /**\\n * @dev Indicates that the contract has been initialized.\\n */\\n bool private initialized;\\n\\n /**\\n * @dev Indicates that the contract is in the process of being initialized.\\n */\\n bool private initializing;\\n\\n /**\\n * @dev Modifier to protect an initializer function from being invoked twice.\\n */\\n modifier initializer() {\\n require(\\n initializing || !initialized,\\n \\\"Initializable: contract is already initialized\\\"\\n );\\n\\n bool isTopLevelCall = !initializing;\\n if (isTopLevelCall) {\\n initializing = true;\\n initialized = true;\\n }\\n\\n _;\\n\\n if (isTopLevelCall) {\\n initializing = false;\\n }\\n }\\n\\n uint256[50] private ______gap;\\n}\\n\",\"keccak256\":\"0xaadbcc138114afed4af4f353c2ced2916e6ee14be91434789187f192caf0d786\",\"license\":\"MIT\"},\"contracts/utils/InitializableERC20Detailed.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { IERC20 } from \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @dev Optional functions from the ERC20 standard.\\n * Converted from openzeppelin/contracts/token/ERC20/ERC20Detailed.sol\\n * @author Origin Protocol Inc\\n */\\nabstract contract InitializableERC20Detailed is IERC20 {\\n // Storage gap to skip storage from prior to OUSD reset\\n uint256[100] private _____gap;\\n\\n string private _name;\\n string private _symbol;\\n uint8 private _decimals;\\n\\n /**\\n * @dev Sets the values for `name`, `symbol`, and `decimals`. All three of\\n * these values are immutable: they can only be set once during\\n * construction.\\n * @notice To avoid variable shadowing appended `Arg` after arguments name.\\n */\\n function _initialize(\\n string memory nameArg,\\n string memory symbolArg,\\n uint8 decimalsArg\\n ) internal {\\n _name = nameArg;\\n _symbol = symbolArg;\\n _decimals = decimalsArg;\\n }\\n\\n /**\\n * @notice Returns the name of the token.\\n */\\n function name() public view returns (string memory) {\\n return _name;\\n }\\n\\n /**\\n * @notice Returns the symbol of the token, usually a shorter version of the\\n * name.\\n */\\n function symbol() public view returns (string memory) {\\n return _symbol;\\n }\\n\\n /**\\n * @notice Returns the number of decimals used to get its user representation.\\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\\n * be displayed to a user as `5,05` (`505 / 10 ** 2`).\\n *\\n * Tokens usually opt for a value of 18, imitating the relationship between\\n * Ether and Wei.\\n *\\n * NOTE: This information is only used for _display_ purposes: it in\\n * no way affects any of the arithmetic of the contract, including\\n * {IERC20-balanceOf} and {IERC20-transfer}.\\n */\\n function decimals() public view returns (uint8) {\\n return _decimals;\\n }\\n}\\n\",\"keccak256\":\"0xe35ac2d813a30d845a3b52bba72588d7e936c2b3f3373d15568c14db46aeed60\",\"license\":\"MIT\"},\"contracts/utils/StableMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { SafeMath } from \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\n\\n// Based on StableMath from Stability Labs Pty. Ltd.\\n// https://github.com/mstable/mStable-contracts/blob/master/contracts/shared/StableMath.sol\\n\\nlibrary StableMath {\\n using SafeMath for uint256;\\n\\n /**\\n * @dev Scaling unit for use in specific calculations,\\n * where 1 * 10**18, or 1e18 represents a unit '1'\\n */\\n uint256 private constant FULL_SCALE = 1e18;\\n\\n /***************************************\\n Helpers\\n ****************************************/\\n\\n /**\\n * @dev Adjust the scale of an integer\\n * @param to Decimals to scale to\\n * @param from Decimals to scale from\\n */\\n function scaleBy(\\n uint256 x,\\n uint256 to,\\n uint256 from\\n ) internal pure returns (uint256) {\\n if (to > from) {\\n x = x.mul(10**(to - from));\\n } else if (to < from) {\\n // slither-disable-next-line divide-before-multiply\\n x = x.div(10**(from - to));\\n }\\n return x;\\n }\\n\\n /***************************************\\n Precise Arithmetic\\n ****************************************/\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the full scale\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit\\n */\\n function mulTruncate(uint256 x, uint256 y) internal pure returns (uint256) {\\n return mulTruncateScale(x, y, FULL_SCALE);\\n }\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the given scale. For example,\\n * when calculating 90% of 10e18, (10e18 * 9e17) / 1e18 = (9e36) / 1e18 = 9e18\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @param scale Scale unit\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit\\n */\\n function mulTruncateScale(\\n uint256 x,\\n uint256 y,\\n uint256 scale\\n ) internal pure returns (uint256) {\\n // e.g. assume scale = fullScale\\n // z = 10e18 * 9e17 = 9e36\\n uint256 z = x.mul(y);\\n // return 9e36 / 1e18 = 9e18\\n return z.div(scale);\\n }\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the full scale, rounding up the result\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit, rounded up to the closest base unit.\\n */\\n function mulTruncateCeil(uint256 x, uint256 y)\\n internal\\n pure\\n returns (uint256)\\n {\\n // e.g. 8e17 * 17268172638 = 138145381104e17\\n uint256 scaled = x.mul(y);\\n // e.g. 138145381104e17 + 9.99...e17 = 138145381113.99...e17\\n uint256 ceil = scaled.add(FULL_SCALE.sub(1));\\n // e.g. 13814538111.399...e18 / 1e18 = 13814538111\\n return ceil.div(FULL_SCALE);\\n }\\n\\n /**\\n * @dev Precisely divides two units, by first scaling the left hand operand. Useful\\n * for finding percentage weightings, i.e. 8e18/10e18 = 80% (or 8e17)\\n * @param x Left hand input to division\\n * @param y Right hand input to division\\n * @return Result after multiplying the left operand by the scale, and\\n * executing the division on the right hand input.\\n */\\n function divPrecisely(uint256 x, uint256 y)\\n internal\\n pure\\n returns (uint256)\\n {\\n // e.g. 8e18 * 1e18 = 8e36\\n uint256 z = x.mul(FULL_SCALE);\\n // e.g. 8e36 / 10e18 = 8e17\\n return z.div(y);\\n }\\n}\\n\",\"keccak256\":\"0x1eb49f6f79045d9e0a8e1dced8e01d9e559e5fac554dcbb53e43140b601b04e7\",\"license\":\"MIT\"},\"contracts/vault/OETHVaultCore.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { StableMath } from \\\"../utils/StableMath.sol\\\";\\nimport { VaultCore } from \\\"./VaultCore.sol\\\";\\n\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport { IERC20 } from \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport { IStrategy } from \\\"../interfaces/IStrategy.sol\\\";\\n\\n/**\\n * @title OETH VaultCore Contract\\n * @author Origin Protocol Inc\\n */\\ncontract OETHVaultCore is VaultCore {\\n using SafeERC20 for IERC20;\\n using StableMath for uint256;\\n\\n address public immutable weth;\\n uint256 public wethAssetIndex;\\n\\n constructor(address _weth) {\\n weth = _weth;\\n }\\n\\n /**\\n * @dev Caches WETH's index in `allAssets` variable.\\n * Reduces gas usage by redeem by caching that.\\n */\\n function cacheWETHAssetIndex() external onlyGovernor {\\n uint256 assetCount = allAssets.length;\\n for (uint256 i = 0; i < assetCount; ++i) {\\n if (allAssets[i] == weth) {\\n wethAssetIndex = i;\\n break;\\n }\\n }\\n\\n require(allAssets[wethAssetIndex] == weth, \\\"Invalid WETH Asset Index\\\");\\n }\\n\\n // @inheritdoc VaultCore\\n function _mint(\\n address _asset,\\n uint256 _amount,\\n uint256 _minimumOusdAmount\\n ) internal virtual override {\\n require(_asset == weth, \\\"Unsupported asset for minting\\\");\\n require(_amount > 0, \\\"Amount must be greater than 0\\\");\\n require(\\n _amount >= _minimumOusdAmount,\\n \\\"Mint amount lower than minimum\\\"\\n );\\n\\n emit Mint(msg.sender, _amount);\\n\\n // Rebase must happen before any transfers occur.\\n if (!rebasePaused && _amount >= rebaseThreshold) {\\n _rebase();\\n }\\n\\n // Mint oTokens\\n oUSD.mint(msg.sender, _amount);\\n\\n // Transfer the deposited coins to the vault\\n IERC20(_asset).safeTransferFrom(msg.sender, address(this), _amount);\\n\\n // Auto-allocate if necessary\\n if (_amount >= autoAllocateThreshold) {\\n _allocate();\\n }\\n }\\n\\n // @inheritdoc VaultCore\\n function _calculateRedeemOutputs(uint256 _amount)\\n internal\\n view\\n virtual\\n override\\n returns (uint256[] memory outputs)\\n {\\n // Overrides `VaultCore._calculateRedeemOutputs` to redeem with only\\n // WETH instead of LST-mix. Doesn't change the function signature\\n // for backward compatibility\\n\\n // Calculate redeem fee\\n if (redeemFeeBps > 0) {\\n uint256 redeemFee = _amount.mulTruncateScale(redeemFeeBps, 1e4);\\n _amount = _amount - redeemFee;\\n }\\n\\n // Ensure that the WETH index is cached\\n uint256 _wethAssetIndex = wethAssetIndex;\\n require(\\n allAssets[_wethAssetIndex] == weth,\\n \\\"WETH Asset index not cached\\\"\\n );\\n\\n outputs = new uint256[](allAssets.length);\\n outputs[_wethAssetIndex] = _amount;\\n }\\n\\n // @inheritdoc VaultCore\\n function _redeem(uint256 _amount, uint256 _minimumUnitAmount)\\n internal\\n virtual\\n override\\n {\\n // Override `VaultCore._redeem` to simplify it. Gets rid of oracle\\n // usage and looping through all assets for LST-mix redeem. Instead\\n // does a simple WETH-only redeem.\\n emit Redeem(msg.sender, _amount);\\n\\n if (_amount == 0) {\\n return;\\n }\\n\\n // Amount excluding fees\\n uint256 amountMinusFee = _calculateRedeemOutputs(_amount)[\\n wethAssetIndex\\n ];\\n\\n require(\\n amountMinusFee >= _minimumUnitAmount,\\n \\\"Redeem amount lower than minimum\\\"\\n );\\n\\n if (IERC20(weth).balanceOf(address(this)) >= amountMinusFee) {\\n // Use Vault funds first if sufficient\\n IERC20(weth).safeTransfer(msg.sender, amountMinusFee);\\n } else {\\n address strategyAddr = assetDefaultStrategies[weth];\\n if (strategyAddr != address(0)) {\\n // Nothing in Vault, but something in Strategy, send from there\\n IStrategy strategy = IStrategy(strategyAddr);\\n strategy.withdraw(msg.sender, weth, amountMinusFee);\\n } else {\\n // Cant find funds anywhere\\n revert(\\\"Liquidity error\\\");\\n }\\n }\\n\\n // Burn OETH from user (including fees)\\n oUSD.burn(msg.sender, _amount);\\n\\n _postRedeem(_amount);\\n }\\n}\\n\",\"keccak256\":\"0x8ae6aada28f768745991b7e6610e325e1331da8fd7e9de045d03f1bc12d65f1e\",\"license\":\"MIT\"},\"contracts/vault/VaultCore.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OToken VaultCore contract\\n * @notice The Vault contract stores assets. On a deposit, OTokens will be minted\\n and sent to the depositor. On a withdrawal, OTokens will be burned and\\n assets will be sent to the withdrawer. The Vault accepts deposits of\\n interest from yield bearing strategies which will modify the supply\\n of OTokens.\\n * @author Origin Protocol Inc\\n */\\n\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\nimport { StableMath } from \\\"../utils/StableMath.sol\\\";\\nimport { IOracle } from \\\"../interfaces/IOracle.sol\\\";\\nimport { IGetExchangeRateToken } from \\\"../interfaces/IGetExchangeRateToken.sol\\\";\\n\\nimport \\\"./VaultInitializer.sol\\\";\\n\\ncontract VaultCore is VaultInitializer {\\n using SafeERC20 for IERC20;\\n using StableMath for uint256;\\n // max signed int\\n uint256 internal constant MAX_INT = 2**255 - 1;\\n // max un-signed int\\n uint256 internal constant MAX_UINT =\\n 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;\\n\\n /**\\n * @dev Verifies that the rebasing is not paused.\\n */\\n modifier whenNotRebasePaused() {\\n require(!rebasePaused, \\\"Rebasing paused\\\");\\n _;\\n }\\n\\n /**\\n * @dev Verifies that the deposits are not paused.\\n */\\n modifier whenNotCapitalPaused() {\\n require(!capitalPaused, \\\"Capital paused\\\");\\n _;\\n }\\n\\n modifier onlyOusdMetaStrategy() {\\n require(\\n msg.sender == ousdMetaStrategy,\\n \\\"Caller is not the OUSD meta strategy\\\"\\n );\\n _;\\n }\\n\\n /**\\n * @notice Deposit a supported asset and mint OTokens.\\n * @param _asset Address of the asset being deposited\\n * @param _amount Amount of the asset being deposited\\n * @param _minimumOusdAmount Minimum OTokens to mint\\n */\\n function mint(\\n address _asset,\\n uint256 _amount,\\n uint256 _minimumOusdAmount\\n ) external whenNotCapitalPaused nonReentrant {\\n _mint(_asset, _amount, _minimumOusdAmount);\\n }\\n\\n function _mint(\\n address _asset,\\n uint256 _amount,\\n uint256 _minimumOusdAmount\\n ) internal virtual {\\n require(assets[_asset].isSupported, \\\"Asset is not supported\\\");\\n require(_amount > 0, \\\"Amount must be greater than 0\\\");\\n\\n uint256 units = _toUnits(_amount, _asset);\\n uint256 unitPrice = _toUnitPrice(_asset, true);\\n uint256 priceAdjustedDeposit = (units * unitPrice) / 1e18;\\n\\n if (_minimumOusdAmount > 0) {\\n require(\\n priceAdjustedDeposit >= _minimumOusdAmount,\\n \\\"Mint amount lower than minimum\\\"\\n );\\n }\\n\\n emit Mint(msg.sender, priceAdjustedDeposit);\\n\\n // Rebase must happen before any transfers occur.\\n if (priceAdjustedDeposit >= rebaseThreshold && !rebasePaused) {\\n _rebase();\\n }\\n\\n // Mint matching amount of OTokens\\n oUSD.mint(msg.sender, priceAdjustedDeposit);\\n\\n // Transfer the deposited coins to the vault\\n IERC20 asset = IERC20(_asset);\\n asset.safeTransferFrom(msg.sender, address(this), _amount);\\n\\n if (priceAdjustedDeposit >= autoAllocateThreshold) {\\n _allocate();\\n }\\n }\\n\\n /**\\n * @notice Mint OTokens for a Metapool Strategy\\n * @param _amount Amount of the asset being deposited\\n *\\n * Notice: can't use `nonReentrant` modifier since the `mint` function can\\n * call `allocate`, and that can trigger `ConvexOUSDMetaStrategy` to call this function\\n * while the execution of the `mint` has not yet completed -> causing a `nonReentrant` collision.\\n *\\n * Also important to understand is that this is a limitation imposed by the test suite.\\n * Production / mainnet contracts should never be configured in a way where mint/redeem functions\\n * that are moving funds between the Vault and end user wallets can influence strategies\\n * utilizing this function.\\n */\\n function mintForStrategy(uint256 _amount)\\n external\\n whenNotCapitalPaused\\n onlyOusdMetaStrategy\\n {\\n require(_amount < MAX_INT, \\\"Amount too high\\\");\\n\\n emit Mint(msg.sender, _amount);\\n\\n // safe to cast because of the require check at the beginning of the function\\n netOusdMintedForStrategy += int256(_amount);\\n\\n require(\\n abs(netOusdMintedForStrategy) < netOusdMintForStrategyThreshold,\\n \\\"Minted ousd surpassed netOusdMintForStrategyThreshold.\\\"\\n );\\n\\n // Mint matching amount of OTokens\\n oUSD.mint(msg.sender, _amount);\\n }\\n\\n // In memoriam\\n\\n /**\\n * @notice Withdraw a supported asset and burn OTokens.\\n * @param _amount Amount of OTokens to burn\\n * @param _minimumUnitAmount Minimum stablecoin units to receive in return\\n */\\n function redeem(uint256 _amount, uint256 _minimumUnitAmount)\\n external\\n whenNotCapitalPaused\\n nonReentrant\\n {\\n _redeem(_amount, _minimumUnitAmount);\\n }\\n\\n /**\\n * @notice Withdraw a supported asset and burn OTokens.\\n * @param _amount Amount of OTokens to burn\\n * @param _minimumUnitAmount Minimum stablecoin units to receive in return\\n */\\n function _redeem(uint256 _amount, uint256 _minimumUnitAmount)\\n internal\\n virtual\\n {\\n // Calculate redemption outputs\\n uint256[] memory outputs = _calculateRedeemOutputs(_amount);\\n\\n emit Redeem(msg.sender, _amount);\\n\\n // Send outputs\\n uint256 assetCount = allAssets.length;\\n for (uint256 i = 0; i < assetCount; ++i) {\\n if (outputs[i] == 0) continue;\\n\\n address assetAddr = allAssets[i];\\n\\n if (IERC20(assetAddr).balanceOf(address(this)) >= outputs[i]) {\\n // Use Vault funds first if sufficient\\n IERC20(assetAddr).safeTransfer(msg.sender, outputs[i]);\\n } else {\\n address strategyAddr = assetDefaultStrategies[assetAddr];\\n if (strategyAddr != address(0)) {\\n // Nothing in Vault, but something in Strategy, send from there\\n IStrategy strategy = IStrategy(strategyAddr);\\n strategy.withdraw(msg.sender, assetAddr, outputs[i]);\\n } else {\\n // Cant find funds anywhere\\n revert(\\\"Liquidity error\\\");\\n }\\n }\\n }\\n\\n if (_minimumUnitAmount > 0) {\\n uint256 unitTotal = 0;\\n for (uint256 i = 0; i < outputs.length; ++i) {\\n unitTotal += _toUnits(outputs[i], allAssets[i]);\\n }\\n require(\\n unitTotal >= _minimumUnitAmount,\\n \\\"Redeem amount lower than minimum\\\"\\n );\\n }\\n\\n oUSD.burn(msg.sender, _amount);\\n\\n _postRedeem(_amount);\\n }\\n\\n function _postRedeem(uint256 _amount) internal {\\n // Until we can prove that we won't affect the prices of our assets\\n // by withdrawing them, this should be here.\\n // It's possible that a strategy was off on its asset total, perhaps\\n // a reward token sold for more or for less than anticipated.\\n uint256 totalUnits = 0;\\n if (_amount >= rebaseThreshold && !rebasePaused) {\\n totalUnits = _rebase();\\n } else {\\n totalUnits = _totalValue();\\n }\\n\\n // Check that the OTokens are backed by enough assets\\n if (maxSupplyDiff > 0) {\\n // Allow a max difference of maxSupplyDiff% between\\n // backing assets value and OUSD total supply\\n uint256 diff = oUSD.totalSupply().divPrecisely(totalUnits);\\n require(\\n (diff > 1e18 ? diff - 1e18 : 1e18 - diff) <= maxSupplyDiff,\\n \\\"Backing supply liquidity error\\\"\\n );\\n }\\n }\\n\\n /**\\n * @notice Burn OTokens for Metapool Strategy\\n * @param _amount Amount of OUSD to burn\\n *\\n * @dev Notice: can't use `nonReentrant` modifier since the `redeem` function could\\n * require withdrawal on `ConvexOUSDMetaStrategy` and that one can call `burnForStrategy`\\n * while the execution of the `redeem` has not yet completed -> causing a `nonReentrant` collision.\\n *\\n * Also important to understand is that this is a limitation imposed by the test suite.\\n * Production / mainnet contracts should never be configured in a way where mint/redeem functions\\n * that are moving funds between the Vault and end user wallets can influence strategies\\n * utilizing this function.\\n */\\n function burnForStrategy(uint256 _amount)\\n external\\n whenNotCapitalPaused\\n onlyOusdMetaStrategy\\n {\\n require(_amount < MAX_INT, \\\"Amount too high\\\");\\n\\n emit Redeem(msg.sender, _amount);\\n\\n // safe to cast because of the require check at the beginning of the function\\n netOusdMintedForStrategy -= int256(_amount);\\n\\n require(\\n abs(netOusdMintedForStrategy) < netOusdMintForStrategyThreshold,\\n \\\"Attempting to burn too much OUSD.\\\"\\n );\\n\\n // Burn OTokens\\n oUSD.burn(msg.sender, _amount);\\n }\\n\\n /**\\n * @notice Withdraw a supported asset and burn all OTokens.\\n * @param _minimumUnitAmount Minimum stablecoin units to receive in return\\n */\\n function redeemAll(uint256 _minimumUnitAmount)\\n external\\n whenNotCapitalPaused\\n nonReentrant\\n {\\n _redeem(oUSD.balanceOf(msg.sender), _minimumUnitAmount);\\n }\\n\\n /**\\n * @notice Allocate unallocated funds on Vault to strategies.\\n **/\\n function allocate() external whenNotCapitalPaused nonReentrant {\\n _allocate();\\n }\\n\\n /**\\n * @dev Allocate unallocated funds on Vault to strategies.\\n **/\\n function _allocate() internal {\\n uint256 vaultValue = _totalValueInVault();\\n // Nothing in vault to allocate\\n if (vaultValue == 0) return;\\n uint256 strategiesValue = _totalValueInStrategies();\\n // We have a method that does the same as this, gas optimisation\\n uint256 calculatedTotalValue = vaultValue + strategiesValue;\\n\\n // We want to maintain a buffer on the Vault so calculate a percentage\\n // modifier to multiply each amount being allocated by to enforce the\\n // vault buffer\\n uint256 vaultBufferModifier;\\n if (strategiesValue == 0) {\\n // Nothing in Strategies, allocate 100% minus the vault buffer to\\n // strategies\\n vaultBufferModifier = uint256(1e18) - vaultBuffer;\\n } else {\\n vaultBufferModifier =\\n (vaultBuffer * calculatedTotalValue) /\\n vaultValue;\\n if (1e18 > vaultBufferModifier) {\\n // E.g. 1e18 - (1e17 * 10e18)/5e18 = 8e17\\n // (5e18 * 8e17) / 1e18 = 4e18 allocated from Vault\\n vaultBufferModifier = uint256(1e18) - vaultBufferModifier;\\n } else {\\n // We need to let the buffer fill\\n return;\\n }\\n }\\n if (vaultBufferModifier == 0) return;\\n\\n // Iterate over all assets in the Vault and allocate to the appropriate\\n // strategy\\n uint256 assetCount = allAssets.length;\\n for (uint256 i = 0; i < assetCount; ++i) {\\n IERC20 asset = IERC20(allAssets[i]);\\n uint256 assetBalance = asset.balanceOf(address(this));\\n // No balance, nothing to do here\\n if (assetBalance == 0) continue;\\n\\n // Multiply the balance by the vault buffer modifier and truncate\\n // to the scale of the asset decimals\\n uint256 allocateAmount = assetBalance.mulTruncate(\\n vaultBufferModifier\\n );\\n\\n address depositStrategyAddr = assetDefaultStrategies[\\n address(asset)\\n ];\\n\\n if (depositStrategyAddr != address(0) && allocateAmount > 0) {\\n IStrategy strategy = IStrategy(depositStrategyAddr);\\n // Transfer asset to Strategy and call deposit method to\\n // mint or take required action\\n asset.safeTransfer(address(strategy), allocateAmount);\\n strategy.deposit(address(asset), allocateAmount);\\n emit AssetAllocated(\\n address(asset),\\n depositStrategyAddr,\\n allocateAmount\\n );\\n }\\n }\\n }\\n\\n /**\\n * @notice Calculate the total value of assets held by the Vault and all\\n * strategies and update the supply of OTokens.\\n */\\n function rebase() external virtual nonReentrant {\\n _rebase();\\n }\\n\\n /**\\n * @dev Calculate the total value of assets held by the Vault and all\\n * strategies and update the supply of OTokens, optionally sending a\\n * portion of the yield to the trustee.\\n * @return totalUnits Total balance of Vault in units\\n */\\n function _rebase() internal whenNotRebasePaused returns (uint256) {\\n uint256 ousdSupply = oUSD.totalSupply();\\n uint256 vaultValue = _totalValue();\\n if (ousdSupply == 0) {\\n return vaultValue;\\n }\\n\\n // Yield fee collection\\n address _trusteeAddress = trusteeAddress; // gas savings\\n if (_trusteeAddress != address(0) && (vaultValue > ousdSupply)) {\\n uint256 yield = vaultValue - ousdSupply;\\n uint256 fee = yield.mulTruncateScale(trusteeFeeBps, 1e4);\\n require(yield > fee, \\\"Fee must not be greater than yield\\\");\\n if (fee > 0) {\\n oUSD.mint(_trusteeAddress, fee);\\n }\\n emit YieldDistribution(_trusteeAddress, yield, fee);\\n }\\n\\n // Only rachet OToken supply upwards\\n ousdSupply = oUSD.totalSupply(); // Final check should use latest value\\n if (vaultValue > ousdSupply) {\\n oUSD.changeSupply(vaultValue);\\n }\\n return vaultValue;\\n }\\n\\n /**\\n * @notice Determine the total value of assets held by the vault and its\\n * strategies.\\n * @return value Total value in USD/ETH (1e18)\\n */\\n function totalValue() external view virtual returns (uint256 value) {\\n value = _totalValue();\\n }\\n\\n /**\\n * @dev Internal Calculate the total value of the assets held by the\\n * vault and its strategies.\\n * @return value Total value in USD/ETH (1e18)\\n */\\n function _totalValue() internal view virtual returns (uint256 value) {\\n return _totalValueInVault() + _totalValueInStrategies();\\n }\\n\\n /**\\n * @dev Internal to calculate total value of all assets held in Vault.\\n * @return value Total value in USD/ETH (1e18)\\n */\\n function _totalValueInVault() internal view returns (uint256 value) {\\n uint256 assetCount = allAssets.length;\\n for (uint256 y = 0; y < assetCount; ++y) {\\n address assetAddr = allAssets[y];\\n uint256 balance = IERC20(assetAddr).balanceOf(address(this));\\n if (balance > 0) {\\n value += _toUnits(balance, assetAddr);\\n }\\n }\\n }\\n\\n /**\\n * @dev Internal to calculate total value of all assets held in Strategies.\\n * @return value Total value in USD/ETH (1e18)\\n */\\n function _totalValueInStrategies() internal view returns (uint256 value) {\\n uint256 stratCount = allStrategies.length;\\n for (uint256 i = 0; i < stratCount; ++i) {\\n value = value + _totalValueInStrategy(allStrategies[i]);\\n }\\n }\\n\\n /**\\n * @dev Internal to calculate total value of all assets held by strategy.\\n * @param _strategyAddr Address of the strategy\\n * @return value Total value in USD/ETH (1e18)\\n */\\n function _totalValueInStrategy(address _strategyAddr)\\n internal\\n view\\n returns (uint256 value)\\n {\\n IStrategy strategy = IStrategy(_strategyAddr);\\n uint256 assetCount = allAssets.length;\\n for (uint256 y = 0; y < assetCount; ++y) {\\n address assetAddr = allAssets[y];\\n if (strategy.supportsAsset(assetAddr)) {\\n uint256 balance = strategy.checkBalance(assetAddr);\\n if (balance > 0) {\\n value += _toUnits(balance, assetAddr);\\n }\\n }\\n }\\n }\\n\\n /**\\n * @notice Get the balance of an asset held in Vault and all strategies.\\n * @param _asset Address of asset\\n * @return uint256 Balance of asset in decimals of asset\\n */\\n function checkBalance(address _asset) external view returns (uint256) {\\n return _checkBalance(_asset);\\n }\\n\\n /**\\n * @notice Get the balance of an asset held in Vault and all strategies.\\n * @param _asset Address of asset\\n * @return balance Balance of asset in decimals of asset\\n */\\n function _checkBalance(address _asset)\\n internal\\n view\\n virtual\\n returns (uint256 balance)\\n {\\n IERC20 asset = IERC20(_asset);\\n balance = asset.balanceOf(address(this));\\n uint256 stratCount = allStrategies.length;\\n for (uint256 i = 0; i < stratCount; ++i) {\\n IStrategy strategy = IStrategy(allStrategies[i]);\\n if (strategy.supportsAsset(_asset)) {\\n balance = balance + strategy.checkBalance(_asset);\\n }\\n }\\n }\\n\\n /**\\n * @notice Calculate the outputs for a redeem function, i.e. the mix of\\n * coins that will be returned\\n */\\n function calculateRedeemOutputs(uint256 _amount)\\n external\\n view\\n returns (uint256[] memory)\\n {\\n return _calculateRedeemOutputs(_amount);\\n }\\n\\n /**\\n * @dev Calculate the outputs for a redeem function, i.e. the mix of\\n * coins that will be returned.\\n * @return outputs Array of amounts respective to the supported assets\\n */\\n function _calculateRedeemOutputs(uint256 _amount)\\n internal\\n view\\n virtual\\n returns (uint256[] memory outputs)\\n {\\n // We always give out coins in proportion to how many we have,\\n // Now if all coins were the same value, this math would easy,\\n // just take the percentage of each coin, and multiply by the\\n // value to be given out. But if coins are worth more than $1,\\n // then we would end up handing out too many coins. We need to\\n // adjust by the total value of coins.\\n //\\n // To do this, we total up the value of our coins, by their\\n // percentages. Then divide what we would otherwise give out by\\n // this number.\\n //\\n // Let say we have 100 DAI at $1.06 and 200 USDT at $1.00.\\n // So for every 1 DAI we give out, we'll be handing out 2 USDT\\n // Our total output ratio is: 33% * 1.06 + 66% * 1.00 = 1.02\\n //\\n // So when calculating the output, we take the percentage of\\n // each coin, times the desired output value, divided by the\\n // totalOutputRatio.\\n //\\n // For example, withdrawing: 30 OUSD:\\n // DAI 33% * 30 / 1.02 = 9.80 DAI\\n // USDT = 66 % * 30 / 1.02 = 19.60 USDT\\n //\\n // Checking these numbers:\\n // 9.80 DAI * 1.06 = $10.40\\n // 19.60 USDT * 1.00 = $19.60\\n //\\n // And so the user gets $10.40 + $19.60 = $30 worth of value.\\n\\n uint256 assetCount = allAssets.length;\\n uint256[] memory assetUnits = new uint256[](assetCount);\\n uint256[] memory assetBalances = new uint256[](assetCount);\\n outputs = new uint256[](assetCount);\\n\\n // Calculate redeem fee\\n if (redeemFeeBps > 0) {\\n uint256 redeemFee = _amount.mulTruncateScale(redeemFeeBps, 1e4);\\n _amount = _amount - redeemFee;\\n }\\n\\n // Calculate assets balances and decimals once,\\n // for a large gas savings.\\n uint256 totalUnits = 0;\\n for (uint256 i = 0; i < assetCount; ++i) {\\n address assetAddr = allAssets[i];\\n uint256 balance = _checkBalance(assetAddr);\\n assetBalances[i] = balance;\\n assetUnits[i] = _toUnits(balance, assetAddr);\\n totalUnits = totalUnits + assetUnits[i];\\n }\\n // Calculate totalOutputRatio\\n uint256 totalOutputRatio = 0;\\n for (uint256 i = 0; i < assetCount; ++i) {\\n uint256 unitPrice = _toUnitPrice(allAssets[i], false);\\n uint256 ratio = (assetUnits[i] * unitPrice) / totalUnits;\\n totalOutputRatio = totalOutputRatio + ratio;\\n }\\n // Calculate final outputs\\n uint256 factor = _amount.divPrecisely(totalOutputRatio);\\n for (uint256 i = 0; i < assetCount; ++i) {\\n outputs[i] = (assetBalances[i] * factor) / totalUnits;\\n }\\n }\\n\\n /***************************************\\n Pricing\\n ****************************************/\\n\\n /**\\n * @notice Returns the total price in 18 digit units for a given asset.\\n * Never goes above 1, since that is how we price mints.\\n * @param asset address of the asset\\n * @return price uint256: unit (USD / ETH) price for 1 unit of the asset, in 18 decimal fixed\\n */\\n function priceUnitMint(address asset)\\n external\\n view\\n returns (uint256 price)\\n {\\n /* need to supply 1 asset unit in asset's decimals and can not just hard-code\\n * to 1e18 and ignore calling `_toUnits` since we need to consider assets\\n * with the exchange rate\\n */\\n uint256 units = _toUnits(\\n uint256(1e18).scaleBy(_getDecimals(asset), 18),\\n asset\\n );\\n price = (_toUnitPrice(asset, true) * units) / 1e18;\\n }\\n\\n /**\\n * @notice Returns the total price in 18 digit unit for a given asset.\\n * Never goes below 1, since that is how we price redeems\\n * @param asset Address of the asset\\n * @return price uint256: unit (USD / ETH) price for 1 unit of the asset, in 18 decimal fixed\\n */\\n function priceUnitRedeem(address asset)\\n external\\n view\\n returns (uint256 price)\\n {\\n /* need to supply 1 asset unit in asset's decimals and can not just hard-code\\n * to 1e18 and ignore calling `_toUnits` since we need to consider assets\\n * with the exchange rate\\n */\\n uint256 units = _toUnits(\\n uint256(1e18).scaleBy(_getDecimals(asset), 18),\\n asset\\n );\\n price = (_toUnitPrice(asset, false) * units) / 1e18;\\n }\\n\\n /***************************************\\n Utils\\n ****************************************/\\n\\n /**\\n * @dev Convert a quantity of a token into 1e18 fixed decimal \\\"units\\\"\\n * in the underlying base (USD/ETH) used by the vault.\\n * Price is not taken into account, only quantity.\\n *\\n * Examples of this conversion:\\n *\\n * - 1e18 DAI becomes 1e18 units (same decimals)\\n * - 1e6 USDC becomes 1e18 units (decimal conversion)\\n * - 1e18 rETH becomes 1.2e18 units (exchange rate conversion)\\n *\\n * @param _raw Quantity of asset\\n * @param _asset Core Asset address\\n * @return value 1e18 normalized quantity of units\\n */\\n function _toUnits(uint256 _raw, address _asset)\\n internal\\n view\\n returns (uint256)\\n {\\n UnitConversion conversion = assets[_asset].unitConversion;\\n if (conversion == UnitConversion.DECIMALS) {\\n return _raw.scaleBy(18, _getDecimals(_asset));\\n } else if (conversion == UnitConversion.GETEXCHANGERATE) {\\n uint256 exchangeRate = IGetExchangeRateToken(_asset)\\n .getExchangeRate();\\n return (_raw * exchangeRate) / 1e18;\\n } else {\\n revert(\\\"Unsupported conversion type\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns asset's unit price accounting for different asset types\\n * and takes into account the context in which that price exists -\\n * - mint or redeem.\\n *\\n * Note: since we are returning the price of the unit and not the one of the\\n * asset (see comment above how 1 rETH exchanges for 1.2 units) we need\\n * to make the Oracle price adjustment as well since we are pricing the\\n * units and not the assets.\\n *\\n * The price also snaps to a \\\"full unit price\\\" in case a mint or redeem\\n * action would be unfavourable to the protocol.\\n *\\n */\\n function _toUnitPrice(address _asset, bool isMint)\\n internal\\n view\\n returns (uint256 price)\\n {\\n UnitConversion conversion = assets[_asset].unitConversion;\\n price = IOracle(priceProvider).price(_asset);\\n\\n if (conversion == UnitConversion.GETEXCHANGERATE) {\\n uint256 exchangeRate = IGetExchangeRateToken(_asset)\\n .getExchangeRate();\\n price = (price * 1e18) / exchangeRate;\\n } else if (conversion != UnitConversion.DECIMALS) {\\n revert(\\\"Unsupported conversion type\\\");\\n }\\n\\n /* At this stage the price is already adjusted to the unit\\n * so the price checks are agnostic to underlying asset being\\n * pegged to a USD or to an ETH or having a custom exchange rate.\\n */\\n require(price <= MAX_UNIT_PRICE_DRIFT, \\\"Vault: Price exceeds max\\\");\\n require(price >= MIN_UNIT_PRICE_DRIFT, \\\"Vault: Price under min\\\");\\n\\n if (isMint) {\\n /* Never price a normalized unit price for more than one\\n * unit of OETH/OUSD when minting.\\n */\\n if (price > 1e18) {\\n price = 1e18;\\n }\\n require(price >= MINT_MINIMUM_UNIT_PRICE, \\\"Asset price below peg\\\");\\n } else {\\n /* Never give out more than 1 normalized unit amount of assets\\n * for one unit of OETH/OUSD when redeeming.\\n */\\n if (price < 1e18) {\\n price = 1e18;\\n }\\n }\\n }\\n\\n function _getDecimals(address _asset)\\n internal\\n view\\n returns (uint256 decimals)\\n {\\n decimals = assets[_asset].decimals;\\n require(decimals > 0, \\\"Decimals not cached\\\");\\n }\\n\\n /**\\n * @notice Return the number of assets supported by the Vault.\\n */\\n function getAssetCount() public view returns (uint256) {\\n return allAssets.length;\\n }\\n\\n /**\\n * @notice Gets the vault configuration of a supported asset.\\n */\\n function getAssetConfig(address _asset)\\n public\\n view\\n returns (Asset memory config)\\n {\\n config = assets[_asset];\\n }\\n\\n /**\\n * @notice Return all vault asset addresses in order\\n */\\n function getAllAssets() external view returns (address[] memory) {\\n return allAssets;\\n }\\n\\n /**\\n * @notice Return the number of strategies active on the Vault.\\n */\\n function getStrategyCount() external view returns (uint256) {\\n return allStrategies.length;\\n }\\n\\n /**\\n * @notice Return the array of all strategies\\n */\\n function getAllStrategies() external view returns (address[] memory) {\\n return allStrategies;\\n }\\n\\n /**\\n * @notice Returns whether the vault supports the asset\\n * @param _asset address of the asset\\n * @return true if supported\\n */\\n function isSupportedAsset(address _asset) external view returns (bool) {\\n return assets[_asset].isSupported;\\n }\\n\\n /**\\n * @dev Falldown to the admin implementation\\n * @notice This is a catch all for all functions not declared in core\\n */\\n // solhint-disable-next-line no-complex-fallback\\n fallback() external {\\n bytes32 slot = adminImplPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n // Copy msg.data. We take full control of memory in this inline assembly\\n // block because it will not return to Solidity code. We overwrite the\\n // Solidity scratch pad at memory position 0.\\n calldatacopy(0, 0, calldatasize())\\n\\n // Call the implementation.\\n // out and outsize are 0 because we don't know the size yet.\\n let result := delegatecall(\\n gas(),\\n sload(slot),\\n 0,\\n calldatasize(),\\n 0,\\n 0\\n )\\n\\n // Copy the returned data.\\n returndatacopy(0, 0, returndatasize())\\n\\n switch result\\n // delegatecall returns 0 on error.\\n case 0 {\\n revert(0, returndatasize())\\n }\\n default {\\n return(0, returndatasize())\\n }\\n }\\n }\\n\\n function abs(int256 x) private pure returns (uint256) {\\n require(x < int256(MAX_INT), \\\"Amount too high\\\");\\n return x >= 0 ? uint256(x) : uint256(-x);\\n }\\n}\\n\",\"keccak256\":\"0x5af4c0464b3728750231edf3bec62181c9eb734b5a3b3f7379789c84c0411ef0\",\"license\":\"MIT\"},\"contracts/vault/VaultInitializer.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OToken VaultInitializer contract\\n * @notice The Vault contract initializes the vault.\\n * @author Origin Protocol Inc\\n */\\n\\nimport \\\"./VaultStorage.sol\\\";\\n\\ncontract VaultInitializer is VaultStorage {\\n function initialize(address _priceProvider, address _oToken)\\n external\\n onlyGovernor\\n initializer\\n {\\n require(_priceProvider != address(0), \\\"PriceProvider address is zero\\\");\\n require(_oToken != address(0), \\\"oToken address is zero\\\");\\n\\n oUSD = OUSD(_oToken);\\n\\n priceProvider = _priceProvider;\\n\\n rebasePaused = false;\\n capitalPaused = true;\\n\\n // Initial redeem fee of 0 basis points\\n redeemFeeBps = 0;\\n // Initial Vault buffer of 0%\\n vaultBuffer = 0;\\n // Initial allocate threshold of 25,000 OUSD\\n autoAllocateThreshold = 25000e18;\\n // Threshold for rebasing\\n rebaseThreshold = 1000e18;\\n // Initialize all strategies\\n allStrategies = new address[](0);\\n }\\n}\\n\",\"keccak256\":\"0x5b9676307bbabe14b5278f00ec7edc557b84debbfa1391902d78100cb9cd467e\",\"license\":\"MIT\"},\"contracts/vault/VaultStorage.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OToken VaultStorage contract\\n * @notice The VaultStorage contract defines the storage for the Vault contracts\\n * @author Origin Protocol Inc\\n */\\n\\nimport { IERC20 } from \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport { Address } from \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport { IStrategy } from \\\"../interfaces/IStrategy.sol\\\";\\nimport { Governable } from \\\"../governance/Governable.sol\\\";\\nimport { OUSD } from \\\"../token/OUSD.sol\\\";\\nimport { Initializable } from \\\"../utils/Initializable.sol\\\";\\nimport \\\"../utils/Helpers.sol\\\";\\n\\ncontract VaultStorage is Initializable, Governable {\\n using SafeERC20 for IERC20;\\n\\n event AssetSupported(address _asset);\\n event AssetDefaultStrategyUpdated(address _asset, address _strategy);\\n event AssetAllocated(address _asset, address _strategy, uint256 _amount);\\n event StrategyApproved(address _addr);\\n event StrategyRemoved(address _addr);\\n event Mint(address _addr, uint256 _value);\\n event Redeem(address _addr, uint256 _value);\\n event CapitalPaused();\\n event CapitalUnpaused();\\n event RebasePaused();\\n event RebaseUnpaused();\\n event VaultBufferUpdated(uint256 _vaultBuffer);\\n event OusdMetaStrategyUpdated(address _ousdMetaStrategy);\\n event RedeemFeeUpdated(uint256 _redeemFeeBps);\\n event PriceProviderUpdated(address _priceProvider);\\n event AllocateThresholdUpdated(uint256 _threshold);\\n event RebaseThresholdUpdated(uint256 _threshold);\\n event StrategistUpdated(address _address);\\n event MaxSupplyDiffChanged(uint256 maxSupplyDiff);\\n event YieldDistribution(address _to, uint256 _yield, uint256 _fee);\\n event TrusteeFeeBpsChanged(uint256 _basis);\\n event TrusteeAddressChanged(address _address);\\n event NetOusdMintForStrategyThresholdChanged(uint256 _threshold);\\n event SwapperChanged(address _address);\\n event SwapAllowedUndervalueChanged(uint256 _basis);\\n event SwapSlippageChanged(address _asset, uint256 _basis);\\n event Swapped(\\n address indexed _fromAsset,\\n address indexed _toAsset,\\n uint256 _fromAssetAmount,\\n uint256 _toAssetAmount\\n );\\n\\n // Assets supported by the Vault, i.e. Stablecoins\\n enum UnitConversion {\\n DECIMALS,\\n GETEXCHANGERATE\\n }\\n // Changed to fit into a single storage slot so the decimals needs to be recached\\n struct Asset {\\n // Note: OETHVaultCore doesn't use `isSupported` when minting,\\n // redeeming or checking balance of assets.\\n bool isSupported;\\n UnitConversion unitConversion;\\n uint8 decimals;\\n // Max allowed slippage from the Oracle price when swapping collateral assets in basis points.\\n // For example 40 == 0.4% slippage\\n uint16 allowedOracleSlippageBps;\\n }\\n\\n /// @dev mapping of supported vault assets to their configuration\\n // slither-disable-next-line uninitialized-state\\n mapping(address => Asset) internal assets;\\n /// @dev list of all assets supported by the vault.\\n // slither-disable-next-line uninitialized-state\\n address[] internal allAssets;\\n\\n // Strategies approved for use by the Vault\\n struct Strategy {\\n bool isSupported;\\n uint256 _deprecated; // Deprecated storage slot\\n }\\n /// @dev mapping of strategy contracts to their configiration\\n mapping(address => Strategy) internal strategies;\\n /// @dev list of all vault strategies\\n address[] internal allStrategies;\\n\\n /// @notice Address of the Oracle price provider contract\\n // slither-disable-next-line uninitialized-state\\n address public priceProvider;\\n /// @notice pause rebasing if true\\n bool public rebasePaused = false;\\n /// @notice pause operations that change the OToken supply.\\n /// eg mint, redeem, allocate, mint/burn for strategy\\n bool public capitalPaused = true;\\n /// @notice Redemption fee in basis points. eg 50 = 0.5%\\n uint256 public redeemFeeBps;\\n /// @notice Percentage of assets to keep in Vault to handle (most) withdrawals. 100% = 1e18.\\n uint256 public vaultBuffer;\\n /// @notice OToken mints over this amount automatically allocate funds. 18 decimals.\\n uint256 public autoAllocateThreshold;\\n /// @notice OToken mints over this amount automatically rebase. 18 decimals.\\n uint256 public rebaseThreshold;\\n\\n /// @dev Address of the OToken token. eg OUSD or OETH.\\n // slither-disable-next-line uninitialized-state\\n OUSD internal oUSD;\\n\\n //keccak256(\\\"OUSD.vault.governor.admin.impl\\\");\\n bytes32 constant adminImplPosition =\\n 0xa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd9;\\n\\n // Address of the contract responsible for post rebase syncs with AMMs\\n address private _deprecated_rebaseHooksAddr = address(0);\\n\\n // Deprecated: Address of Uniswap\\n // slither-disable-next-line constable-states\\n address private _deprecated_uniswapAddr = address(0);\\n\\n /// @notice Address of the Strategist\\n address public strategistAddr = address(0);\\n\\n /// @notice Mapping of asset address to the Strategy that they should automatically\\n // be allocated to\\n // slither-disable-next-line uninitialized-state\\n mapping(address => address) public assetDefaultStrategies;\\n\\n /// @notice Max difference between total supply and total value of assets. 18 decimals.\\n // slither-disable-next-line uninitialized-state\\n uint256 public maxSupplyDiff;\\n\\n /// @notice Trustee contract that can collect a percentage of yield\\n address public trusteeAddress;\\n\\n /// @notice Amount of yield collected in basis points. eg 2000 = 20%\\n uint256 public trusteeFeeBps;\\n\\n /// @dev Deprecated: Tokens that should be swapped for stablecoins\\n address[] private _deprecated_swapTokens;\\n\\n uint256 constant MINT_MINIMUM_UNIT_PRICE = 0.998e18;\\n\\n /// @notice Metapool strategy that is allowed to mint/burn OTokens without changing collateral\\n address public ousdMetaStrategy = address(0);\\n\\n /// @notice How much OTokens are currently minted by the strategy\\n int256 public netOusdMintedForStrategy = 0;\\n\\n /// @notice How much net total OTokens are allowed to be minted by all strategies\\n uint256 public netOusdMintForStrategyThreshold = 0;\\n\\n uint256 constant MIN_UNIT_PRICE_DRIFT = 0.7e18;\\n uint256 constant MAX_UNIT_PRICE_DRIFT = 1.3e18;\\n\\n /// @notice Collateral swap configuration.\\n /// @dev is packed into a single storage slot to save gas.\\n struct SwapConfig {\\n // Contract that swaps the vault's collateral assets\\n address swapper;\\n // Max allowed percentage the total value can drop below the total supply in basis points.\\n // For example 100 == 1%\\n uint16 allowedUndervalueBps;\\n }\\n SwapConfig internal swapConfig = SwapConfig(address(0), 0);\\n\\n // For future use\\n uint256[50] private __gap;\\n\\n /**\\n * @notice set the implementation for the admin, this needs to be in a base class else we cannot set it\\n * @param newImpl address of the implementation\\n */\\n function setAdminImpl(address newImpl) external onlyGovernor {\\n require(\\n Address.isContract(newImpl),\\n \\\"new implementation is not a contract\\\"\\n );\\n bytes32 position = adminImplPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, newImpl)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xbcefeb5e2b88d99a54dbe6542dc25d0a68eeaf3adfe6e12fb70049cc024b1a79\",\"license\":\"MIT\"}},\"version\":1}", - "bytecode": "0x6037805461ffff60a01b1916600160a81b179055603d80546001600160a01b0319908116909155603e805482169055603f80548216905560458054909116905560006046819055604781905560e060405260a081905260c052604880546001600160b01b03191690553480156200007557600080fd5b50604051620036453803806200364583398101604081905262000098916200010e565b620000b0336000805160206200362583398151915255565b60008051602062003625833981519152546040516001600160a01b03909116906000907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a360601b6001600160601b03191660805262000140565b6000602082840312156200012157600080fd5b81516001600160a01b03811681146200013957600080fd5b9392505050565b60805160601c61348e620001976000396000818161034f0152818161072401528181610797015281816112d001528181611d0301528181611edd01528181611f7101528181611fa70152611ffb015261348e6000f3fe608060405234801561001057600080fd5b506004361061025e5760003560e01c806367bd7ba311610146578063ab80dafb116100c3578063c7af335211610087578063c7af335214610545578063d38bfff41461054d578063d4c3eea014610560578063e45cc9f014610568578063e6cc543214610571578063fc0cfeee146105855761025e565b8063ab80dafb14610507578063abaa99161461051a578063af14052c14610522578063b888879e1461052a578063c3b288641461053d5761025e565b80638e510b521161010a5780638e510b52146104985780639be918e6146104a15780639fa1826e146104cd578063a0aead4d146104d6578063a403e4d5146104de5761025e565b806367bd7ba3146104295780636ec3ab67146104495780637136a7a6146104695780637a2202f31461047c5780637cbc2373146104855761025e565b806344c54707116101df57806354c6d858116101a357806354c6d858146103cc578063570d8e1d146103d55780635b60f9fc146103e85780635d36b190146103fb5780635f515226146104035780636217f3ea146104165761025e565b806344c5470714610371578063485cc9551461037957806349c1d54d1461038c57806352d38e5d1461039f57806353ca9f24146103a85761025e565b8063207134b011610226578063207134b0146103115780632acada4d1461031a57806331e19cfa1461032f5780633b8fe28d146103375780633fc8cef31461034a5761025e565b806309f6442c146102a45780630c340a24146102c0578063156e29f6146102e057806318ce56bd146102f55780631edfe3da14610308575b7fa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd9366000803760008036600084545af43d6000803e80801561029f573d6000f35b3d6000fd5b6102ad60385481565b6040519081526020015b60405180910390f35b6102c8610598565b6040516001600160a01b0390911681526020016102b7565b6102f36102ee366004612ea1565b6105b5565b005b6045546102c8906001600160a01b031681565b6102ad60395481565b6102ad60435481565b610322610633565b6040516102b79190612f7f565b6036546102ad565b6102ad610345366004612e53565b610695565b6102c87f000000000000000000000000000000000000000000000000000000000000000081565b6102f36106f0565b6102f3610387366004612e6e565b610839565b6042546102c8906001600160a01b031681565b6102ad603b5481565b6037546103bc90600160a01b900460ff1681565b60405190151581526020016102b7565b6102ad607b5481565b603f546102c8906001600160a01b031681565b6102ad6103f6366004612e53565b610a3b565b6102f3610a64565b6102ad610411366004612e53565b610b0a565b6102f3610424366004612ef6565b610b1b565b61043c610437366004612ef6565b610cb2565b6040516102b79190612fcc565b61045c610457366004612e53565b610cbd565b6040516102b7919061312b565b6102f3610477366004612ef6565b610d63565b6102ad60475481565b6102f3610493366004612f28565b610e4e565b6102ad60415481565b6103bc6104af366004612e53565b6001600160a01b031660009081526033602052604090205460ff1690565b6102ad603a5481565b6034546102ad565b6102c86104ec366004612e53565b6040602081905260009182529020546001600160a01b031681565b6102f3610515366004612ef6565b610ec1565b6102f3611038565b6102f36110a7565b6037546102c8906001600160a01b031681565b6103226110ed565b6103bc61114d565b6102f361055b366004612e53565b61117e565b6102ad611222565b6102ad60465481565b6037546103bc90600160a81b900460ff1681565b6102f3610593366004612e53565b61122c565b60006105b06000805160206134398339815191525490565b905090565b603754600160a81b900460ff16156105e85760405162461bcd60e51b81526004016105df906130db565b60405180910390fd5b6000805160206134198339815191528054600281141561061a5760405162461bcd60e51b81526004016105df90613103565b600282556106298585856112ce565b5060019055505050565b6060603480548060200260200160405190810160405280929190818152602001828054801561068b57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161066d575b5050505050905090565b6000806106be6106b86106a7856114de565b670de0b6b3a7640000906012611548565b846115aa565b9050670de0b6b3a7640000816106d5856001611706565b6106df91906132e7565b6106e991906131da565b9392505050565b6106f861114d565b6107145760405162461bcd60e51b81526004016105df9061307b565b60345460005b81811015610794577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166034828154811061075f5761075f6133ec565b6000918252602090912001546001600160a01b0316141561078457607b819055610794565b61078d81613388565b905061071a565b507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166034607b54815481106107d4576107d46133ec565b6000918252602090912001546001600160a01b0316146108365760405162461bcd60e51b815260206004820152601860248201527f496e76616c6964205745544820417373657420496e646578000000000000000060448201526064016105df565b50565b61084161114d565b61085d5760405162461bcd60e51b81526004016105df9061307b565b600054610100900460ff1680610876575060005460ff16155b6108d95760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016105df565b600054610100900460ff161580156108fb576000805461ffff19166101011790555b6001600160a01b0383166109515760405162461bcd60e51b815260206004820152601d60248201527f507269636550726f76696465722061646472657373206973207a65726f00000060448201526064016105df565b6001600160a01b0382166109a05760405162461bcd60e51b81526020600482015260166024820152756f546f6b656e2061646472657373206973207a65726f60501b60448201526064016105df565b603c80546001600160a01b038481166001600160a01b031990921691909117909155603780546001600160b01b03191691851691909117600160a81b17905560006038819055603981905569054b40b1f852bda00000603a55683635c9adc5dea00000603b556040805191825260208201908190529051610a2391603691612dcb565b508015610a36576000805461ff00191690555b505050565b600080610a4d6106b86106a7856114de565b9050670de0b6b3a7640000816106d5856000611706565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614610aff5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b60648201526084016105df565b610b08336119f8565b565b6000610b1582611ab9565b92915050565b603754600160a81b900460ff1615610b455760405162461bcd60e51b81526004016105df906130db565b6045546001600160a01b03163314610b6f5760405162461bcd60e51b81526004016105df90613037565b6001600160ff1b038110610b955760405162461bcd60e51b81526004016105df906130b2565b7f222838db2794d11532d940e8dec38ae307ed0b63cd97c233322e221f998767a63382604051610bc6929190612f66565b60405180910390a18060466000828254610be09190613306565b9091555050604754604654610bf490611c88565b10610c4b5760405162461bcd60e51b815260206004820152602160248201527f417474656d7074696e6720746f206275726e20746f6f206d756368204f5553446044820152601760f91b60648201526084016105df565b603c54604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac90610c7d9033908590600401612f66565b600060405180830381600087803b158015610c9757600080fd5b505af1158015610cab573d6000803e3d6000fd5b5050505050565b6060610b1582611ccb565b604080516080808201835260008083526020808401829052838501829052606084018290526001600160a01b038616825260338152908490208451928301909452835460ff808216151584529394929391840191610100909104166001811115610d2957610d296133d6565b6001811115610d3a57610d3a6133d6565b8152905462010000810460ff1660208301526301000000900461ffff1660409091015292915050565b603754600160a81b900460ff1615610d8d5760405162461bcd60e51b81526004016105df906130db565b60008051602061341983398151915280546002811415610dbf5760405162461bcd60e51b81526004016105df90613103565b60028255603c546040516370a0823160e01b8152336004820152610e46916001600160a01b0316906370a082319060240160206040518083038186803b158015610e0857600080fd5b505afa158015610e1c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e409190612f0f565b84611e0c565b506001905550565b603754600160a81b900460ff1615610e785760405162461bcd60e51b81526004016105df906130db565b60008051602061341983398151915280546002811415610eaa5760405162461bcd60e51b81526004016105df90613103565b60028255610eb88484611e0c565b50600190555050565b603754600160a81b900460ff1615610eeb5760405162461bcd60e51b81526004016105df906130db565b6045546001600160a01b03163314610f155760405162461bcd60e51b81526004016105df90613037565b6001600160ff1b038110610f3b5760405162461bcd60e51b81526004016105df906130b2565b7f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d41213968853382604051610f6c929190612f66565b60405180910390a18060466000828254610f869190613181565b9091555050604754604654610f9a90611c88565b106110065760405162461bcd60e51b815260206004820152603660248201527f4d696e746564206f75736420737572706173736564206e65744f7573644d696e6044820152753a2337b929ba3930ba32b3bcaa343932b9b437b6321760511b60648201526084016105df565b603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990610c7d9033908590600401612f66565b603754600160a81b900460ff16156110625760405162461bcd60e51b81526004016105df906130db565b600080516020613419833981519152805460028114156110945760405162461bcd60e51b81526004016105df90613103565b600282556110a0612118565b5060019055565b600080516020613419833981519152805460028114156110d95760405162461bcd60e51b81526004016105df90613103565b600282556110e561238c565b505060019055565b6060603680548060200260200160405190810160405280929190818152602001828054801561068b576020028201919060005260206000209081546001600160a01b0316815260019091019060200180831161066d575050505050905090565b60006111656000805160206134398339815191525490565b6001600160a01b0316336001600160a01b031614905090565b61118661114d565b6111a25760405162461bcd60e51b81526004016105df9061307b565b6111ca817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166111ea6000805160206134398339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b60006105b06126c7565b61123461114d565b6112505760405162461bcd60e51b81526004016105df9061307b565b803b6112aa5760405162461bcd60e51b8152602060048201526024808201527f6e657720696d706c656d656e746174696f6e206973206e6f74206120636f6e746044820152631c9858dd60e21b60648201526084016105df565b7fa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd955565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b03161461134f5760405162461bcd60e51b815260206004820152601d60248201527f556e737570706f7274656420617373657420666f72206d696e74696e6700000060448201526064016105df565b6000821161139f5760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e203000000060448201526064016105df565b808210156113ef5760405162461bcd60e51b815260206004820152601e60248201527f4d696e7420616d6f756e74206c6f776572207468616e206d696e696d756d000060448201526064016105df565b7f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d41213968853383604051611420929190612f66565b60405180910390a1603754600160a01b900460ff161580156114445750603b548210155b156114535761145161238c565b505b603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f19906114859033908690600401612f66565b600060405180830381600087803b15801561149f57600080fd5b505af11580156114b3573d6000803e3d6000fd5b506114cd925050506001600160a01b0384163330856126e3565b603a548210610a3657610a36612118565b6001600160a01b03811660009081526033602052604090205462010000900460ff16806115435760405162461bcd60e51b8152602060048201526013602482015272111958da5b585b1cc81b9bdd0818d858da1959606a1b60448201526064016105df565b919050565b6000818311156115785761157161155f8385613345565b61156a90600a61323f565b859061274e565b93506115a2565b818310156115a25761159f61158d8484613345565b61159890600a61323f565b859061275a565b93505b509192915050565b6001600160a01b038116600090815260336020526040812054610100900460ff16818160018111156115de576115de6133d6565b1415611602576115fa60126115f2856114de565b869190611548565b915050610b15565b6001816001811115611616576116166133d6565b14156116b7576000836001600160a01b031663e6aa216c6040518163ffffffff1660e01b815260040160206040518083038186803b15801561165757600080fd5b505afa15801561166b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061168f9190612f0f565b9050670de0b6b3a76400006116a482876132e7565b6116ae91906131da565b92505050610b15565b60405162461bcd60e51b815260206004820152601b60248201527f556e737570706f7274656420636f6e76657273696f6e2074797065000000000060448201526064016105df565b5092915050565b6001600160a01b038281166000818152603360205260408082205460375491516315d5220f60e31b81526004810194909452919361010090920460ff169291169063aea910789060240160206040518083038186803b15801561176857600080fd5b505afa15801561177c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117a09190612f0f565b915060018160018111156117b6576117b66133d6565b1415611856576000846001600160a01b031663e6aa216c6040518163ffffffff1660e01b815260040160206040518083038186803b1580156117f757600080fd5b505afa15801561180b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061182f9190612f0f565b90508061184484670de0b6b3a76400006132e7565b61184e91906131da565b9250506118b7565b600081600181111561186a5761186a6133d6565b146118b75760405162461bcd60e51b815260206004820152601b60248201527f556e737570706f7274656420636f6e76657273696f6e2074797065000000000060448201526064016105df565b67120a871cc002000082111561190f5760405162461bcd60e51b815260206004820152601860248201527f5661756c743a2050726963652065786365656473206d6178000000000000000060448201526064016105df565b6709b6e64a8ec600008210156119605760405162461bcd60e51b81526020600482015260166024820152752b30bab63a1d10283934b1b2903ab73232b91036b4b760511b60448201526064016105df565b82156119d757670de0b6b3a764000082111561198257670de0b6b3a764000091505b670dd99bb65dd700008210156119d25760405162461bcd60e51b815260206004820152601560248201527441737365742070726963652062656c6f772070656760581b60448201526064016105df565b6116ff565b670de0b6b3a76400008210156116ff5750670de0b6b3a76400009392505050565b6001600160a01b038116611a4e5760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f72206973206164647265737328302900000000000060448201526064016105df565b806001600160a01b0316611a6e6000805160206134398339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36108368160008051602061343983398151915255565b6040516370a0823160e01b815230600482015260009082906001600160a01b038216906370a082319060240160206040518083038186803b158015611afd57600080fd5b505afa158015611b11573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b359190612f0f565b60365490925060005b81811015611c8057600060368281548110611b5b57611b5b6133ec565b60009182526020909120015460405163551c457b60e11b81526001600160a01b0388811660048301529091169150819063aa388af69060240160206040518083038186803b158015611bac57600080fd5b505afa158015611bc0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611be49190612ed4565b15611c6f57604051632fa8a91360e11b81526001600160a01b038781166004830152821690635f5152269060240160206040518083038186803b158015611c2a57600080fd5b505afa158015611c3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c629190612f0f565b611c6c90866131c2565b94505b50611c7981613388565b9050611b3e565b505050919050565b60006001600160ff1b038212611cb05760405162461bcd60e51b81526004016105df906130b2565b6000821215611cc757611cc2826133a3565b610b15565b5090565b60385460609015611cfa57603854600090611cea908490612710612766565b9050611cf68184613345565b9250505b6000607b5490507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031660348281548110611d3e57611d3e6133ec565b6000918252602090912001546001600160a01b031614611da05760405162461bcd60e51b815260206004820152601b60248201527f5745544820417373657420696e646578206e6f7420636163686564000000000060448201526064016105df565b60345467ffffffffffffffff811115611dbb57611dbb613402565b604051908082528060200260200182016040528015611de4578160200160208202803683370190505b50915082828281518110611dfa57611dfa6133ec565b60200260200101818152505050919050565b7f222838db2794d11532d940e8dec38ae307ed0b63cd97c233322e221f998767a63383604051611e3d929190612f66565b60405180910390a181611e4e575050565b6000611e5983611ccb565b607b5481518110611e6c57611e6c6133ec565b6020026020010151905081811015611ec65760405162461bcd60e51b815260206004820181905260248201527f52656465656d20616d6f756e74206c6f776572207468616e206d696e696d756d60448201526064016105df565b6040516370a0823160e01b815230600482015281907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015611f2757600080fd5b505afa158015611f3b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f5f9190612f0f565b10611f9d57611f986001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163383612788565b6120ab565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660009081526040602081905290205416801561206f57604051636ce5768960e11b81523360048201526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660248301526044820184905282919082169063d9caed1290606401600060405180830381600087803b15801561205157600080fd5b505af1158015612065573d6000803e3d6000fd5b50505050506120a9565b60405162461bcd60e51b815260206004820152600f60248201526e2634b8bab4b234ba3c9032b93937b960891b60448201526064016105df565b505b603c54604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac906120dd9033908790600401612f66565b600060405180830381600087803b1580156120f757600080fd5b505af115801561210b573d6000803e3d6000fd5b50505050610a36836127a7565b600061212261290d565b90508061212c5750565b60006121366129ef565b9050600061214482846131c2565b90506000826121695760395461216290670de0b6b3a7640000613345565b90506121ac565b838260395461217891906132e7565b61218291906131da565b905080670de0b6b3a764000011156121a65761216281670de0b6b3a7640000613345565b50505050565b806121b75750505050565b60345460005b81811015612384576000603482815481106121da576121da6133ec565b60009182526020822001546040516370a0823160e01b81523060048201526001600160a01b03909116925082906370a082319060240160206040518083038186803b15801561222857600080fd5b505afa15801561223c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122609190612f0f565b90508061226e575050612374565b600061227a8287612a4b565b6001600160a01b038085166000908152604060208190529020549192501680158015906122a75750600082115b1561236f57806122c16001600160a01b0386168285612788565b6040516311f9fbc960e21b81526001600160a01b038216906347e7ef24906122ef9088908790600401612f66565b600060405180830381600087803b15801561230957600080fd5b505af115801561231d573d6000803e3d6000fd5b5050604080516001600160a01b03808a168252861660208201529081018690527f41b99659f6ba0803f444aff29e5bf6e26dd86a3219aff92119d69710a956ba8d9250606001905060405180910390a1505b505050505b61237d81613388565b90506121bd565b505050505050565b603754600090600160a01b900460ff16156123db5760405162461bcd60e51b815260206004820152600f60248201526e149958985cda5b99c81c185d5cd959608a1b60448201526064016105df565b603c54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd916004808301926020929190829003018186803b15801561242057600080fd5b505afa158015612434573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124589190612f0f565b905060006124646126c7565b9050816124745791506126c49050565b6042546001600160a01b0316801580159061248e57508282115b156125d057600061249f8484613345565b905060006124bc604354612710846127669092919063ffffffff16565b90508082116125185760405162461bcd60e51b815260206004820152602260248201527f466565206d757374206e6f742062652067726561746572207468616e207969656044820152611b1960f21b60648201526084016105df565b801561258357603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f19906125509086908590600401612f66565b600060405180830381600087803b15801561256a57600080fd5b505af115801561257e573d6000803e3d6000fd5b505050505b604080516001600160a01b0385168152602081018490529081018290527f09516ecf4a8a86e59780a9befc6dee948bc9e60a36e3be68d31ea817ee8d2c809060600160405180910390a150505b603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561261e57600080fd5b505afa158015612632573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126569190612f0f565b9250828211156126bf57603c546040516339a7919f60e01b8152600481018490526001600160a01b03909116906339a7919f90602401600060405180830381600087803b1580156126a657600080fd5b505af11580156126ba573d6000803e3d6000fd5b505050505b509150505b90565b60006126d16129ef565b6126d961290d565b6105b091906131c2565b6040516001600160a01b03808516602483015283166044820152606481018290526121a69085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612a60565b60006106e982846132e7565b60006106e982846131da565b600080612773858561274e565b905061277f818461275a565b95945050505050565b610a368363a9059cbb60e01b8484604051602401612717929190612f66565b6000603b5482101580156127c55750603754600160a01b900460ff16155b156127d9576127d261238c565b90506127e4565b6127e16126c7565b90505b6041541561290957600061287e82603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561284057600080fd5b505afa158015612854573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128789190612f0f565b90612b32565b9050604154670de0b6b3a764000082116128a9576128a482670de0b6b3a7640000613345565b6128bb565b6128bb670de0b6b3a764000083613345565b1115610a365760405162461bcd60e51b815260206004820152601e60248201527f4261636b696e6720737570706c79206c6971756964697479206572726f72000060448201526064016105df565b5050565b603454600090815b818110156129ea57600060348281548110612932576129326133ec565b60009182526020822001546040516370a0823160e01b81523060048201526001600160a01b03909116925082906370a082319060240160206040518083038186803b15801561298057600080fd5b505afa158015612994573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129b89190612f0f565b905080156129d7576129ca81836115aa565b6129d490866131c2565b94505b5050806129e390613388565b9050612915565b505090565b603654600090815b818110156129ea57612a2f60368281548110612a1557612a156133ec565b6000918252602090912001546001600160a01b0316612b5b565b612a3990846131c2565b9250612a4481613388565b90506129f7565b60006106e98383670de0b6b3a7640000612766565b6000612ab5826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316612cc09092919063ffffffff16565b805190915015610a365780806020019051810190612ad39190612ed4565b610a365760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016105df565b600080612b4784670de0b6b3a764000061274e565b9050612b53818461275a565b949350505050565b6034546000908290825b81811015611c8057600060348281548110612b8257612b826133ec565b60009182526020909120015460405163551c457b60e11b81526001600160a01b039182166004820181905292509085169063aa388af69060240160206040518083038186803b158015612bd457600080fd5b505afa158015612be8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c0c9190612ed4565b15612caf57604051632fa8a91360e11b81526001600160a01b03828116600483015260009190861690635f5152269060240160206040518083038186803b158015612c5657600080fd5b505afa158015612c6a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c8e9190612f0f565b90508015612cad57612ca081836115aa565b612caa90876131c2565b95505b505b50612cb981613388565b9050612b65565b6060612b53848460008585843b612d195760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016105df565b600080866001600160a01b03168587604051612d359190612f4a565b60006040518083038185875af1925050503d8060008114612d72576040519150601f19603f3d011682016040523d82523d6000602084013e612d77565b606091505b5091509150612d87828286612d92565b979650505050505050565b60608315612da15750816106e9565b825115612db15782518084602001fd5b8160405162461bcd60e51b81526004016105df9190613004565b828054828255906000526020600020908101928215612e20579160200282015b82811115612e2057825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190612deb565b50611cc79291505b80821115611cc75760008155600101612e28565b80356001600160a01b038116811461154357600080fd5b600060208284031215612e6557600080fd5b6106e982612e3c565b60008060408385031215612e8157600080fd5b612e8a83612e3c565b9150612e9860208401612e3c565b90509250929050565b600080600060608486031215612eb657600080fd5b612ebf84612e3c565b95602085013595506040909401359392505050565b600060208284031215612ee657600080fd5b815180151581146106e957600080fd5b600060208284031215612f0857600080fd5b5035919050565b600060208284031215612f2157600080fd5b5051919050565b60008060408385031215612f3b57600080fd5b50508035926020909101359150565b60008251612f5c81846020870161335c565b9190910192915050565b6001600160a01b03929092168252602082015260400190565b6020808252825182820181905260009190848201906040850190845b81811015612fc05783516001600160a01b031683529284019291840191600101612f9b565b50909695505050505050565b6020808252825182820181905260009190848201906040850190845b81811015612fc057835183529284019291840191600101612fe8565b602081526000825180602084015261302381604085016020870161335c565b601f01601f19169190910160400192915050565b60208082526024908201527f43616c6c6572206973206e6f7420746865204f555344206d65746120737472616040820152637465677960e01b606082015260800190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b6020808252600f908201526e082dadeeadce840e8dede40d0d2ced608b1b604082015260600190565b6020808252600e908201526d10d85c1a5d185b081c185d5cd95960921b604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b815115158152602082015160808201906002811061315957634e487b7160e01b600052602160045260246000fd5b8060208401525060ff604084015116604083015261ffff606084015116606083015292915050565b600080821280156001600160ff1b03849003851316156131a3576131a36133c0565b600160ff1b83900384128116156131bc576131bc6133c0565b50500190565b600082198211156131d5576131d56133c0565b500190565b6000826131f757634e487b7160e01b600052601260045260246000fd5b500490565b600181815b8085111561323757816000190482111561321d5761321d6133c0565b8085161561322a57918102915b93841c9390800290613201565b509250929050565b60006106e9838360008261325557506001610b15565b8161326257506000610b15565b816001811461327857600281146132825761329e565b6001915050610b15565b60ff841115613293576132936133c0565b50506001821b610b15565b5060208310610133831016604e8410600b84101617156132c1575081810a610b15565b6132cb83836131fc565b80600019048211156132df576132df6133c0565b029392505050565b6000816000190483118215151615613301576133016133c0565b500290565b60008083128015600160ff1b850184121615613324576133246133c0565b6001600160ff1b038401831381161561333f5761333f6133c0565b50500390565b600082821015613357576133576133c0565b500390565b60005b8381101561337757818101518382015260200161335f565b838111156121a65750506000910152565b600060001982141561339c5761339c6133c0565b5060010190565b6000600160ff1b8214156133b9576133b96133c0565b5060000390565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fdfe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa26469706673582212204e8e456474cb6e24f080768f1c492c792431f05e2e92233405d5b9337a2458fb64736f6c634300080700337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", - "deployedBytecode": "0x608060405234801561001057600080fd5b506004361061025e5760003560e01c806367bd7ba311610146578063ab80dafb116100c3578063c7af335211610087578063c7af335214610545578063d38bfff41461054d578063d4c3eea014610560578063e45cc9f014610568578063e6cc543214610571578063fc0cfeee146105855761025e565b8063ab80dafb14610507578063abaa99161461051a578063af14052c14610522578063b888879e1461052a578063c3b288641461053d5761025e565b80638e510b521161010a5780638e510b52146104985780639be918e6146104a15780639fa1826e146104cd578063a0aead4d146104d6578063a403e4d5146104de5761025e565b806367bd7ba3146104295780636ec3ab67146104495780637136a7a6146104695780637a2202f31461047c5780637cbc2373146104855761025e565b806344c54707116101df57806354c6d858116101a357806354c6d858146103cc578063570d8e1d146103d55780635b60f9fc146103e85780635d36b190146103fb5780635f515226146104035780636217f3ea146104165761025e565b806344c5470714610371578063485cc9551461037957806349c1d54d1461038c57806352d38e5d1461039f57806353ca9f24146103a85761025e565b8063207134b011610226578063207134b0146103115780632acada4d1461031a57806331e19cfa1461032f5780633b8fe28d146103375780633fc8cef31461034a5761025e565b806309f6442c146102a45780630c340a24146102c0578063156e29f6146102e057806318ce56bd146102f55780631edfe3da14610308575b7fa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd9366000803760008036600084545af43d6000803e80801561029f573d6000f35b3d6000fd5b6102ad60385481565b6040519081526020015b60405180910390f35b6102c8610598565b6040516001600160a01b0390911681526020016102b7565b6102f36102ee366004612ea1565b6105b5565b005b6045546102c8906001600160a01b031681565b6102ad60395481565b6102ad60435481565b610322610633565b6040516102b79190612f7f565b6036546102ad565b6102ad610345366004612e53565b610695565b6102c87f000000000000000000000000000000000000000000000000000000000000000081565b6102f36106f0565b6102f3610387366004612e6e565b610839565b6042546102c8906001600160a01b031681565b6102ad603b5481565b6037546103bc90600160a01b900460ff1681565b60405190151581526020016102b7565b6102ad607b5481565b603f546102c8906001600160a01b031681565b6102ad6103f6366004612e53565b610a3b565b6102f3610a64565b6102ad610411366004612e53565b610b0a565b6102f3610424366004612ef6565b610b1b565b61043c610437366004612ef6565b610cb2565b6040516102b79190612fcc565b61045c610457366004612e53565b610cbd565b6040516102b7919061312b565b6102f3610477366004612ef6565b610d63565b6102ad60475481565b6102f3610493366004612f28565b610e4e565b6102ad60415481565b6103bc6104af366004612e53565b6001600160a01b031660009081526033602052604090205460ff1690565b6102ad603a5481565b6034546102ad565b6102c86104ec366004612e53565b6040602081905260009182529020546001600160a01b031681565b6102f3610515366004612ef6565b610ec1565b6102f3611038565b6102f36110a7565b6037546102c8906001600160a01b031681565b6103226110ed565b6103bc61114d565b6102f361055b366004612e53565b61117e565b6102ad611222565b6102ad60465481565b6037546103bc90600160a81b900460ff1681565b6102f3610593366004612e53565b61122c565b60006105b06000805160206134398339815191525490565b905090565b603754600160a81b900460ff16156105e85760405162461bcd60e51b81526004016105df906130db565b60405180910390fd5b6000805160206134198339815191528054600281141561061a5760405162461bcd60e51b81526004016105df90613103565b600282556106298585856112ce565b5060019055505050565b6060603480548060200260200160405190810160405280929190818152602001828054801561068b57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161066d575b5050505050905090565b6000806106be6106b86106a7856114de565b670de0b6b3a7640000906012611548565b846115aa565b9050670de0b6b3a7640000816106d5856001611706565b6106df91906132e7565b6106e991906131da565b9392505050565b6106f861114d565b6107145760405162461bcd60e51b81526004016105df9061307b565b60345460005b81811015610794577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166034828154811061075f5761075f6133ec565b6000918252602090912001546001600160a01b0316141561078457607b819055610794565b61078d81613388565b905061071a565b507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166034607b54815481106107d4576107d46133ec565b6000918252602090912001546001600160a01b0316146108365760405162461bcd60e51b815260206004820152601860248201527f496e76616c6964205745544820417373657420496e646578000000000000000060448201526064016105df565b50565b61084161114d565b61085d5760405162461bcd60e51b81526004016105df9061307b565b600054610100900460ff1680610876575060005460ff16155b6108d95760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016105df565b600054610100900460ff161580156108fb576000805461ffff19166101011790555b6001600160a01b0383166109515760405162461bcd60e51b815260206004820152601d60248201527f507269636550726f76696465722061646472657373206973207a65726f00000060448201526064016105df565b6001600160a01b0382166109a05760405162461bcd60e51b81526020600482015260166024820152756f546f6b656e2061646472657373206973207a65726f60501b60448201526064016105df565b603c80546001600160a01b038481166001600160a01b031990921691909117909155603780546001600160b01b03191691851691909117600160a81b17905560006038819055603981905569054b40b1f852bda00000603a55683635c9adc5dea00000603b556040805191825260208201908190529051610a2391603691612dcb565b508015610a36576000805461ff00191690555b505050565b600080610a4d6106b86106a7856114de565b9050670de0b6b3a7640000816106d5856000611706565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614610aff5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b60648201526084016105df565b610b08336119f8565b565b6000610b1582611ab9565b92915050565b603754600160a81b900460ff1615610b455760405162461bcd60e51b81526004016105df906130db565b6045546001600160a01b03163314610b6f5760405162461bcd60e51b81526004016105df90613037565b6001600160ff1b038110610b955760405162461bcd60e51b81526004016105df906130b2565b7f222838db2794d11532d940e8dec38ae307ed0b63cd97c233322e221f998767a63382604051610bc6929190612f66565b60405180910390a18060466000828254610be09190613306565b9091555050604754604654610bf490611c88565b10610c4b5760405162461bcd60e51b815260206004820152602160248201527f417474656d7074696e6720746f206275726e20746f6f206d756368204f5553446044820152601760f91b60648201526084016105df565b603c54604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac90610c7d9033908590600401612f66565b600060405180830381600087803b158015610c9757600080fd5b505af1158015610cab573d6000803e3d6000fd5b5050505050565b6060610b1582611ccb565b604080516080808201835260008083526020808401829052838501829052606084018290526001600160a01b038616825260338152908490208451928301909452835460ff808216151584529394929391840191610100909104166001811115610d2957610d296133d6565b6001811115610d3a57610d3a6133d6565b8152905462010000810460ff1660208301526301000000900461ffff1660409091015292915050565b603754600160a81b900460ff1615610d8d5760405162461bcd60e51b81526004016105df906130db565b60008051602061341983398151915280546002811415610dbf5760405162461bcd60e51b81526004016105df90613103565b60028255603c546040516370a0823160e01b8152336004820152610e46916001600160a01b0316906370a082319060240160206040518083038186803b158015610e0857600080fd5b505afa158015610e1c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e409190612f0f565b84611e0c565b506001905550565b603754600160a81b900460ff1615610e785760405162461bcd60e51b81526004016105df906130db565b60008051602061341983398151915280546002811415610eaa5760405162461bcd60e51b81526004016105df90613103565b60028255610eb88484611e0c565b50600190555050565b603754600160a81b900460ff1615610eeb5760405162461bcd60e51b81526004016105df906130db565b6045546001600160a01b03163314610f155760405162461bcd60e51b81526004016105df90613037565b6001600160ff1b038110610f3b5760405162461bcd60e51b81526004016105df906130b2565b7f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d41213968853382604051610f6c929190612f66565b60405180910390a18060466000828254610f869190613181565b9091555050604754604654610f9a90611c88565b106110065760405162461bcd60e51b815260206004820152603660248201527f4d696e746564206f75736420737572706173736564206e65744f7573644d696e6044820152753a2337b929ba3930ba32b3bcaa343932b9b437b6321760511b60648201526084016105df565b603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990610c7d9033908590600401612f66565b603754600160a81b900460ff16156110625760405162461bcd60e51b81526004016105df906130db565b600080516020613419833981519152805460028114156110945760405162461bcd60e51b81526004016105df90613103565b600282556110a0612118565b5060019055565b600080516020613419833981519152805460028114156110d95760405162461bcd60e51b81526004016105df90613103565b600282556110e561238c565b505060019055565b6060603680548060200260200160405190810160405280929190818152602001828054801561068b576020028201919060005260206000209081546001600160a01b0316815260019091019060200180831161066d575050505050905090565b60006111656000805160206134398339815191525490565b6001600160a01b0316336001600160a01b031614905090565b61118661114d565b6111a25760405162461bcd60e51b81526004016105df9061307b565b6111ca817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166111ea6000805160206134398339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b60006105b06126c7565b61123461114d565b6112505760405162461bcd60e51b81526004016105df9061307b565b803b6112aa5760405162461bcd60e51b8152602060048201526024808201527f6e657720696d706c656d656e746174696f6e206973206e6f74206120636f6e746044820152631c9858dd60e21b60648201526084016105df565b7fa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd955565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b03161461134f5760405162461bcd60e51b815260206004820152601d60248201527f556e737570706f7274656420617373657420666f72206d696e74696e6700000060448201526064016105df565b6000821161139f5760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e203000000060448201526064016105df565b808210156113ef5760405162461bcd60e51b815260206004820152601e60248201527f4d696e7420616d6f756e74206c6f776572207468616e206d696e696d756d000060448201526064016105df565b7f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d41213968853383604051611420929190612f66565b60405180910390a1603754600160a01b900460ff161580156114445750603b548210155b156114535761145161238c565b505b603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f19906114859033908690600401612f66565b600060405180830381600087803b15801561149f57600080fd5b505af11580156114b3573d6000803e3d6000fd5b506114cd925050506001600160a01b0384163330856126e3565b603a548210610a3657610a36612118565b6001600160a01b03811660009081526033602052604090205462010000900460ff16806115435760405162461bcd60e51b8152602060048201526013602482015272111958da5b585b1cc81b9bdd0818d858da1959606a1b60448201526064016105df565b919050565b6000818311156115785761157161155f8385613345565b61156a90600a61323f565b859061274e565b93506115a2565b818310156115a25761159f61158d8484613345565b61159890600a61323f565b859061275a565b93505b509192915050565b6001600160a01b038116600090815260336020526040812054610100900460ff16818160018111156115de576115de6133d6565b1415611602576115fa60126115f2856114de565b869190611548565b915050610b15565b6001816001811115611616576116166133d6565b14156116b7576000836001600160a01b031663e6aa216c6040518163ffffffff1660e01b815260040160206040518083038186803b15801561165757600080fd5b505afa15801561166b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061168f9190612f0f565b9050670de0b6b3a76400006116a482876132e7565b6116ae91906131da565b92505050610b15565b60405162461bcd60e51b815260206004820152601b60248201527f556e737570706f7274656420636f6e76657273696f6e2074797065000000000060448201526064016105df565b5092915050565b6001600160a01b038281166000818152603360205260408082205460375491516315d5220f60e31b81526004810194909452919361010090920460ff169291169063aea910789060240160206040518083038186803b15801561176857600080fd5b505afa15801561177c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117a09190612f0f565b915060018160018111156117b6576117b66133d6565b1415611856576000846001600160a01b031663e6aa216c6040518163ffffffff1660e01b815260040160206040518083038186803b1580156117f757600080fd5b505afa15801561180b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061182f9190612f0f565b90508061184484670de0b6b3a76400006132e7565b61184e91906131da565b9250506118b7565b600081600181111561186a5761186a6133d6565b146118b75760405162461bcd60e51b815260206004820152601b60248201527f556e737570706f7274656420636f6e76657273696f6e2074797065000000000060448201526064016105df565b67120a871cc002000082111561190f5760405162461bcd60e51b815260206004820152601860248201527f5661756c743a2050726963652065786365656473206d6178000000000000000060448201526064016105df565b6709b6e64a8ec600008210156119605760405162461bcd60e51b81526020600482015260166024820152752b30bab63a1d10283934b1b2903ab73232b91036b4b760511b60448201526064016105df565b82156119d757670de0b6b3a764000082111561198257670de0b6b3a764000091505b670dd99bb65dd700008210156119d25760405162461bcd60e51b815260206004820152601560248201527441737365742070726963652062656c6f772070656760581b60448201526064016105df565b6116ff565b670de0b6b3a76400008210156116ff5750670de0b6b3a76400009392505050565b6001600160a01b038116611a4e5760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f72206973206164647265737328302900000000000060448201526064016105df565b806001600160a01b0316611a6e6000805160206134398339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36108368160008051602061343983398151915255565b6040516370a0823160e01b815230600482015260009082906001600160a01b038216906370a082319060240160206040518083038186803b158015611afd57600080fd5b505afa158015611b11573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b359190612f0f565b60365490925060005b81811015611c8057600060368281548110611b5b57611b5b6133ec565b60009182526020909120015460405163551c457b60e11b81526001600160a01b0388811660048301529091169150819063aa388af69060240160206040518083038186803b158015611bac57600080fd5b505afa158015611bc0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611be49190612ed4565b15611c6f57604051632fa8a91360e11b81526001600160a01b038781166004830152821690635f5152269060240160206040518083038186803b158015611c2a57600080fd5b505afa158015611c3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c629190612f0f565b611c6c90866131c2565b94505b50611c7981613388565b9050611b3e565b505050919050565b60006001600160ff1b038212611cb05760405162461bcd60e51b81526004016105df906130b2565b6000821215611cc757611cc2826133a3565b610b15565b5090565b60385460609015611cfa57603854600090611cea908490612710612766565b9050611cf68184613345565b9250505b6000607b5490507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031660348281548110611d3e57611d3e6133ec565b6000918252602090912001546001600160a01b031614611da05760405162461bcd60e51b815260206004820152601b60248201527f5745544820417373657420696e646578206e6f7420636163686564000000000060448201526064016105df565b60345467ffffffffffffffff811115611dbb57611dbb613402565b604051908082528060200260200182016040528015611de4578160200160208202803683370190505b50915082828281518110611dfa57611dfa6133ec565b60200260200101818152505050919050565b7f222838db2794d11532d940e8dec38ae307ed0b63cd97c233322e221f998767a63383604051611e3d929190612f66565b60405180910390a181611e4e575050565b6000611e5983611ccb565b607b5481518110611e6c57611e6c6133ec565b6020026020010151905081811015611ec65760405162461bcd60e51b815260206004820181905260248201527f52656465656d20616d6f756e74206c6f776572207468616e206d696e696d756d60448201526064016105df565b6040516370a0823160e01b815230600482015281907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015611f2757600080fd5b505afa158015611f3b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f5f9190612f0f565b10611f9d57611f986001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163383612788565b6120ab565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660009081526040602081905290205416801561206f57604051636ce5768960e11b81523360048201526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660248301526044820184905282919082169063d9caed1290606401600060405180830381600087803b15801561205157600080fd5b505af1158015612065573d6000803e3d6000fd5b50505050506120a9565b60405162461bcd60e51b815260206004820152600f60248201526e2634b8bab4b234ba3c9032b93937b960891b60448201526064016105df565b505b603c54604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac906120dd9033908790600401612f66565b600060405180830381600087803b1580156120f757600080fd5b505af115801561210b573d6000803e3d6000fd5b50505050610a36836127a7565b600061212261290d565b90508061212c5750565b60006121366129ef565b9050600061214482846131c2565b90506000826121695760395461216290670de0b6b3a7640000613345565b90506121ac565b838260395461217891906132e7565b61218291906131da565b905080670de0b6b3a764000011156121a65761216281670de0b6b3a7640000613345565b50505050565b806121b75750505050565b60345460005b81811015612384576000603482815481106121da576121da6133ec565b60009182526020822001546040516370a0823160e01b81523060048201526001600160a01b03909116925082906370a082319060240160206040518083038186803b15801561222857600080fd5b505afa15801561223c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122609190612f0f565b90508061226e575050612374565b600061227a8287612a4b565b6001600160a01b038085166000908152604060208190529020549192501680158015906122a75750600082115b1561236f57806122c16001600160a01b0386168285612788565b6040516311f9fbc960e21b81526001600160a01b038216906347e7ef24906122ef9088908790600401612f66565b600060405180830381600087803b15801561230957600080fd5b505af115801561231d573d6000803e3d6000fd5b5050604080516001600160a01b03808a168252861660208201529081018690527f41b99659f6ba0803f444aff29e5bf6e26dd86a3219aff92119d69710a956ba8d9250606001905060405180910390a1505b505050505b61237d81613388565b90506121bd565b505050505050565b603754600090600160a01b900460ff16156123db5760405162461bcd60e51b815260206004820152600f60248201526e149958985cda5b99c81c185d5cd959608a1b60448201526064016105df565b603c54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd916004808301926020929190829003018186803b15801561242057600080fd5b505afa158015612434573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124589190612f0f565b905060006124646126c7565b9050816124745791506126c49050565b6042546001600160a01b0316801580159061248e57508282115b156125d057600061249f8484613345565b905060006124bc604354612710846127669092919063ffffffff16565b90508082116125185760405162461bcd60e51b815260206004820152602260248201527f466565206d757374206e6f742062652067726561746572207468616e207969656044820152611b1960f21b60648201526084016105df565b801561258357603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f19906125509086908590600401612f66565b600060405180830381600087803b15801561256a57600080fd5b505af115801561257e573d6000803e3d6000fd5b505050505b604080516001600160a01b0385168152602081018490529081018290527f09516ecf4a8a86e59780a9befc6dee948bc9e60a36e3be68d31ea817ee8d2c809060600160405180910390a150505b603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561261e57600080fd5b505afa158015612632573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126569190612f0f565b9250828211156126bf57603c546040516339a7919f60e01b8152600481018490526001600160a01b03909116906339a7919f90602401600060405180830381600087803b1580156126a657600080fd5b505af11580156126ba573d6000803e3d6000fd5b505050505b509150505b90565b60006126d16129ef565b6126d961290d565b6105b091906131c2565b6040516001600160a01b03808516602483015283166044820152606481018290526121a69085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612a60565b60006106e982846132e7565b60006106e982846131da565b600080612773858561274e565b905061277f818461275a565b95945050505050565b610a368363a9059cbb60e01b8484604051602401612717929190612f66565b6000603b5482101580156127c55750603754600160a01b900460ff16155b156127d9576127d261238c565b90506127e4565b6127e16126c7565b90505b6041541561290957600061287e82603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561284057600080fd5b505afa158015612854573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128789190612f0f565b90612b32565b9050604154670de0b6b3a764000082116128a9576128a482670de0b6b3a7640000613345565b6128bb565b6128bb670de0b6b3a764000083613345565b1115610a365760405162461bcd60e51b815260206004820152601e60248201527f4261636b696e6720737570706c79206c6971756964697479206572726f72000060448201526064016105df565b5050565b603454600090815b818110156129ea57600060348281548110612932576129326133ec565b60009182526020822001546040516370a0823160e01b81523060048201526001600160a01b03909116925082906370a082319060240160206040518083038186803b15801561298057600080fd5b505afa158015612994573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129b89190612f0f565b905080156129d7576129ca81836115aa565b6129d490866131c2565b94505b5050806129e390613388565b9050612915565b505090565b603654600090815b818110156129ea57612a2f60368281548110612a1557612a156133ec565b6000918252602090912001546001600160a01b0316612b5b565b612a3990846131c2565b9250612a4481613388565b90506129f7565b60006106e98383670de0b6b3a7640000612766565b6000612ab5826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316612cc09092919063ffffffff16565b805190915015610a365780806020019051810190612ad39190612ed4565b610a365760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016105df565b600080612b4784670de0b6b3a764000061274e565b9050612b53818461275a565b949350505050565b6034546000908290825b81811015611c8057600060348281548110612b8257612b826133ec565b60009182526020909120015460405163551c457b60e11b81526001600160a01b039182166004820181905292509085169063aa388af69060240160206040518083038186803b158015612bd457600080fd5b505afa158015612be8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c0c9190612ed4565b15612caf57604051632fa8a91360e11b81526001600160a01b03828116600483015260009190861690635f5152269060240160206040518083038186803b158015612c5657600080fd5b505afa158015612c6a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c8e9190612f0f565b90508015612cad57612ca081836115aa565b612caa90876131c2565b95505b505b50612cb981613388565b9050612b65565b6060612b53848460008585843b612d195760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016105df565b600080866001600160a01b03168587604051612d359190612f4a565b60006040518083038185875af1925050503d8060008114612d72576040519150601f19603f3d011682016040523d82523d6000602084013e612d77565b606091505b5091509150612d87828286612d92565b979650505050505050565b60608315612da15750816106e9565b825115612db15782518084602001fd5b8160405162461bcd60e51b81526004016105df9190613004565b828054828255906000526020600020908101928215612e20579160200282015b82811115612e2057825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190612deb565b50611cc79291505b80821115611cc75760008155600101612e28565b80356001600160a01b038116811461154357600080fd5b600060208284031215612e6557600080fd5b6106e982612e3c565b60008060408385031215612e8157600080fd5b612e8a83612e3c565b9150612e9860208401612e3c565b90509250929050565b600080600060608486031215612eb657600080fd5b612ebf84612e3c565b95602085013595506040909401359392505050565b600060208284031215612ee657600080fd5b815180151581146106e957600080fd5b600060208284031215612f0857600080fd5b5035919050565b600060208284031215612f2157600080fd5b5051919050565b60008060408385031215612f3b57600080fd5b50508035926020909101359150565b60008251612f5c81846020870161335c565b9190910192915050565b6001600160a01b03929092168252602082015260400190565b6020808252825182820181905260009190848201906040850190845b81811015612fc05783516001600160a01b031683529284019291840191600101612f9b565b50909695505050505050565b6020808252825182820181905260009190848201906040850190845b81811015612fc057835183529284019291840191600101612fe8565b602081526000825180602084015261302381604085016020870161335c565b601f01601f19169190910160400192915050565b60208082526024908201527f43616c6c6572206973206e6f7420746865204f555344206d65746120737472616040820152637465677960e01b606082015260800190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b6020808252600f908201526e082dadeeadce840e8dede40d0d2ced608b1b604082015260600190565b6020808252600e908201526d10d85c1a5d185b081c185d5cd95960921b604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b815115158152602082015160808201906002811061315957634e487b7160e01b600052602160045260246000fd5b8060208401525060ff604084015116604083015261ffff606084015116606083015292915050565b600080821280156001600160ff1b03849003851316156131a3576131a36133c0565b600160ff1b83900384128116156131bc576131bc6133c0565b50500190565b600082198211156131d5576131d56133c0565b500190565b6000826131f757634e487b7160e01b600052601260045260246000fd5b500490565b600181815b8085111561323757816000190482111561321d5761321d6133c0565b8085161561322a57918102915b93841c9390800290613201565b509250929050565b60006106e9838360008261325557506001610b15565b8161326257506000610b15565b816001811461327857600281146132825761329e565b6001915050610b15565b60ff841115613293576132936133c0565b50506001821b610b15565b5060208310610133831016604e8410600b84101617156132c1575081810a610b15565b6132cb83836131fc565b80600019048211156132df576132df6133c0565b029392505050565b6000816000190483118215151615613301576133016133c0565b500290565b60008083128015600160ff1b850184121615613324576133246133c0565b6001600160ff1b038401831381161561333f5761333f6133c0565b50500390565b600082821015613357576133576133c0565b500390565b60005b8381101561337757818101518382015260200161335f565b838111156121a65750506000910152565b600060001982141561339c5761339c6133c0565b5060010190565b6000600160ff1b8214156133b9576133b96133c0565b5060000390565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fdfe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa26469706673582212204e8e456474cb6e24f080768f1c492c792431f05e2e92233405d5b9337a2458fb64736f6c63430008070033", + "numDeployments": 2, + "solcInputHash": "9b811e7a632431f9f724307daee2b897", + "metadata": "{\"compiler\":{\"version\":\"0.8.7+commit.e28d00a7\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_weth\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"AllocateThresholdUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_strategy\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"AssetAllocated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_strategy\",\"type\":\"address\"}],\"name\":\"AssetDefaultStrategyUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"AssetRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"AssetSupported\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"CapitalPaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"CapitalUnpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_dripper\",\"type\":\"address\"}],\"name\":\"DripperChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"GovernorshipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"maxSupplyDiff\",\"type\":\"uint256\"}],\"name\":\"MaxSupplyDiffChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"Mint\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"NetOusdMintForStrategyThresholdChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_ousdMetaStrategy\",\"type\":\"address\"}],\"name\":\"OusdMetaStrategyUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"PendingGovernorshipTransfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_priceProvider\",\"type\":\"address\"}],\"name\":\"PriceProviderUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"RebasePaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"RebaseThresholdUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"RebaseUnpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"Redeem\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_redeemFeeBps\",\"type\":\"uint256\"}],\"name\":\"RedeemFeeUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"StrategistUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"StrategyApproved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"StrategyRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_basis\",\"type\":\"uint256\"}],\"name\":\"SwapAllowedUndervalueChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_basis\",\"type\":\"uint256\"}],\"name\":\"SwapSlippageChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_fromAsset\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_toAsset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_fromAssetAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_toAssetAmount\",\"type\":\"uint256\"}],\"name\":\"Swapped\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"SwapperChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"TrusteeAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_basis\",\"type\":\"uint256\"}],\"name\":\"TrusteeFeeBpsChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_vaultBuffer\",\"type\":\"uint256\"}],\"name\":\"VaultBufferUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_claimable\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_newClaimable\",\"type\":\"uint256\"}],\"name\":\"WithdrawalClaimable\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_withdrawer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"WithdrawalClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_withdrawer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_queued\",\"type\":\"uint256\"}],\"name\":\"WithdrawalRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_yield\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_fee\",\"type\":\"uint256\"}],\"name\":\"YieldDistribution\",\"type\":\"event\"},{\"stateMutability\":\"nonpayable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"addWithdrawalQueueLiquidity\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"allocate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"assetDefaultStrategies\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"autoAllocateThreshold\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"burnForStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"cacheWETHAssetIndex\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"calculateRedeemOutputs\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"capitalPaused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"checkBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"}],\"name\":\"claimWithdrawal\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"requestIds\",\"type\":\"uint256[]\"}],\"name\":\"claimWithdrawals\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256\",\"name\":\"totalAmount\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"dripper\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllAssets\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllStrategies\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"getAssetConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isSupported\",\"type\":\"bool\"},{\"internalType\":\"enum VaultStorage.UnitConversion\",\"name\":\"unitConversion\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"decimals\",\"type\":\"uint8\"},{\"internalType\":\"uint16\",\"name\":\"allowedOracleSlippageBps\",\"type\":\"uint16\"}],\"internalType\":\"struct VaultStorage.Asset\",\"name\":\"config\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAssetCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStrategyCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"governor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_priceProvider\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_oToken\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"isSupportedAsset\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maxSupplyDiff\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_minimumOusdAmount\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"mintForStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"netOusdMintForStrategyThreshold\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"netOusdMintedForStrategy\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"ousdMetaStrategy\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"priceProvider\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"asset\",\"type\":\"address\"}],\"name\":\"priceUnitMint\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"price\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"asset\",\"type\":\"address\"}],\"name\":\"priceUnitRedeem\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"price\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebase\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebasePaused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebaseThreshold\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_minimumUnitAmount\",\"type\":\"uint256\"}],\"name\":\"redeem\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_minimumUnitAmount\",\"type\":\"uint256\"}],\"name\":\"redeemAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"redeemFeeBps\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"requestWithdrawal\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"queued\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImpl\",\"type\":\"address\"}],\"name\":\"setAdminImpl\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"strategistAddr\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalValue\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newGovernor\",\"type\":\"address\"}],\"name\":\"transferGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"trusteeAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"trusteeFeeBps\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"vaultBuffer\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"weth\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wethAssetIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawalQueueMetadata\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"queued\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"claimable\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"claimed\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"nextWithdrawalIndex\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"withdrawalRequests\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"withdrawer\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"claimed\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"queued\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"Origin Protocol Inc\",\"kind\":\"dev\",\"methods\":{\"addWithdrawalQueueLiquidity()\":{\"details\":\"is called from the Native Staking strategy when validator withdrawals are processed. It also called before any WETH is allocated to a strategy.\"},\"burnForStrategy(uint256)\":{\"details\":\"Notice: can't use `nonReentrant` modifier since the `redeem` function could require withdrawal on `ConvexOUSDMetaStrategy` and that one can call `burnForStrategy` while the execution of the `redeem` has not yet completed -> causing a `nonReentrant` collision. Also important to understand is that this is a limitation imposed by the test suite. Production / mainnet contracts should never be configured in a way where mint/redeem functions that are moving funds between the Vault and end user wallets can influence strategies utilizing this function.\",\"params\":{\"_amount\":\"Amount of OUSD to burn\"}},\"cacheWETHAssetIndex()\":{\"details\":\"Caches WETH's index in `allAssets` variable. Reduces gas usage by redeem by caching that.\"},\"checkBalance(address)\":{\"params\":{\"_asset\":\"Address of asset\"},\"returns\":{\"_0\":\"uint256 Balance of asset in decimals of asset\"}},\"claimWithdrawal(uint256)\":{\"params\":{\"requestId\":\"Unique ID for the withdrawal request\"},\"returns\":{\"amount\":\"Amount of WETH transferred to the withdrawer\"}},\"claimWithdrawals(uint256[])\":{\"params\":{\"requestIds\":\"Unique ID of each withdrawal request\"},\"returns\":{\"amounts\":\"Amount of WETH received for each request\"}},\"isSupportedAsset(address)\":{\"params\":{\"_asset\":\"address of the asset\"},\"returns\":{\"_0\":\"true if supported\"}},\"mint(address,uint256,uint256)\":{\"params\":{\"_amount\":\"Amount of the asset being deposited\",\"_asset\":\"Address of the asset being deposited\",\"_minimumOusdAmount\":\"Minimum OTokens to mint\"}},\"mintForStrategy(uint256)\":{\"params\":{\"_amount\":\"Amount of the asset being deposited Notice: can't use `nonReentrant` modifier since the `mint` function can call `allocate`, and that can trigger `ConvexOUSDMetaStrategy` to call this function while the execution of the `mint` has not yet completed -> causing a `nonReentrant` collision. Also important to understand is that this is a limitation imposed by the test suite. Production / mainnet contracts should never be configured in a way where mint/redeem functions that are moving funds between the Vault and end user wallets can influence strategies utilizing this function.\"}},\"priceUnitMint(address)\":{\"params\":{\"asset\":\"address of the asset\"},\"returns\":{\"price\":\"uint256: unit (USD / ETH) price for 1 unit of the asset, in 18 decimal fixed\"}},\"priceUnitRedeem(address)\":{\"params\":{\"asset\":\"Address of the asset\"},\"returns\":{\"price\":\"uint256: unit (USD / ETH) price for 1 unit of the asset, in 18 decimal fixed\"}},\"redeem(uint256,uint256)\":{\"params\":{\"_amount\":\"Amount of OTokens to burn\",\"_minimumUnitAmount\":\"Minimum stablecoin units to receive in return\"}},\"redeemAll(uint256)\":{\"params\":{\"_minimumUnitAmount\":\"Minimum stablecoin units to receive in return\"}},\"requestWithdrawal(uint256)\":{\"params\":{\"_amount\":\"Amount of oTokens to burn. eg OETH\",\"queued\":\"Cumulative total of all WETH queued including already claimed requests. This request can be claimed once the withdrawal queue's claimable amount is greater than or equal this request's queued amount.\",\"requestId\":\"Unique ID for the withdrawal request\"}},\"setAdminImpl(address)\":{\"params\":{\"newImpl\":\"address of the implementation\"}},\"totalValue()\":{\"returns\":{\"value\":\"Total value in USD/ETH (1e18)\"}},\"transferGovernance(address)\":{\"params\":{\"_newGovernor\":\"Address of the new Governor\"}}},\"title\":\"OETH VaultCore Contract\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"addWithdrawalQueueLiquidity()\":{\"notice\":\"Collects harvested rewards from the Dripper as WETH then adds WETH to the withdrawal queue if there is a funding shortfall.\"},\"allocate()\":{\"notice\":\"Allocate unallocated funds on Vault to strategies.*\"},\"assetDefaultStrategies(address)\":{\"notice\":\"Mapping of asset address to the Strategy that they should automatically\"},\"autoAllocateThreshold()\":{\"notice\":\"OToken mints over this amount automatically allocate funds. 18 decimals.\"},\"burnForStrategy(uint256)\":{\"notice\":\"Burn OTokens for Metapool Strategy\"},\"calculateRedeemOutputs(uint256)\":{\"notice\":\"Calculate the outputs for a redeem function, i.e. the mix of coins that will be returned\"},\"capitalPaused()\":{\"notice\":\"pause operations that change the OToken supply. eg mint, redeem, allocate, mint/burn for strategy\"},\"checkBalance(address)\":{\"notice\":\"Get the balance of an asset held in Vault and all strategies.\"},\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"claimWithdrawal(uint256)\":{\"notice\":\"Claim a previously requested withdrawal once it is claimable.\"},\"claimWithdrawals(uint256[])\":{\"notice\":\"Claim a previously requested withdrawals once they are claimable.\"},\"dripper()\":{\"notice\":\"Address of the Dripper contract that streams harvested rewards to the Vault\"},\"getAllAssets()\":{\"notice\":\"Return all vault asset addresses in order\"},\"getAllStrategies()\":{\"notice\":\"Return the array of all strategies\"},\"getAssetConfig(address)\":{\"notice\":\"Gets the vault configuration of a supported asset.\"},\"getAssetCount()\":{\"notice\":\"Return the number of assets supported by the Vault.\"},\"getStrategyCount()\":{\"notice\":\"Return the number of strategies active on the Vault.\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"isSupportedAsset(address)\":{\"notice\":\"Returns whether the vault supports the asset\"},\"maxSupplyDiff()\":{\"notice\":\"Max difference between total supply and total value of assets. 18 decimals.\"},\"mint(address,uint256,uint256)\":{\"notice\":\"Deposit a supported asset and mint OTokens.\"},\"mintForStrategy(uint256)\":{\"notice\":\"Mint OTokens for a Metapool Strategy\"},\"netOusdMintForStrategyThreshold()\":{\"notice\":\"How much net total OTokens are allowed to be minted by all strategies\"},\"netOusdMintedForStrategy()\":{\"notice\":\"How much OTokens are currently minted by the strategy\"},\"ousdMetaStrategy()\":{\"notice\":\"Metapool strategy that is allowed to mint/burn OTokens without changing collateral\"},\"priceProvider()\":{\"notice\":\"Address of the Oracle price provider contract\"},\"priceUnitMint(address)\":{\"notice\":\"Returns the total price in 18 digit units for a given asset. Never goes above 1, since that is how we price mints.\"},\"priceUnitRedeem(address)\":{\"notice\":\"Returns the total price in 18 digit unit for a given asset. Never goes below 1, since that is how we price redeems\"},\"rebase()\":{\"notice\":\"Calculate the total value of assets held by the Vault and all strategies and update the supply of OTokens.\"},\"rebasePaused()\":{\"notice\":\"pause rebasing if true\"},\"rebaseThreshold()\":{\"notice\":\"OToken mints over this amount automatically rebase. 18 decimals.\"},\"redeem(uint256,uint256)\":{\"notice\":\"Withdraw a supported asset and burn OTokens.\"},\"redeemAll(uint256)\":{\"notice\":\"Withdraw a supported asset and burn all OTokens.\"},\"redeemFeeBps()\":{\"notice\":\"Redemption fee in basis points. eg 50 = 0.5%\"},\"requestWithdrawal(uint256)\":{\"notice\":\"Request an asynchronous withdrawal of the underlying asset. eg WETH\"},\"setAdminImpl(address)\":{\"notice\":\"set the implementation for the admin, this needs to be in a base class else we cannot set it\"},\"strategistAddr()\":{\"notice\":\"Address of the Strategist\"},\"totalValue()\":{\"notice\":\"Determine the total value of assets held by the vault and its strategies.\"},\"transferGovernance(address)\":{\"notice\":\"Transfers Governance of the contract to a new account (`newGovernor`). Can only be called by the current Governor. Must be claimed for this to complete\"},\"trusteeAddress()\":{\"notice\":\"Trustee contract that can collect a percentage of yield\"},\"trusteeFeeBps()\":{\"notice\":\"Amount of yield collected in basis points. eg 2000 = 20%\"},\"vaultBuffer()\":{\"notice\":\"Percentage of assets to keep in Vault to handle (most) withdrawals. 100% = 1e18.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/vault/OETHVaultCore.sol\":\"OETHVaultCore\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address recipient, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address sender,\\n address recipient,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0x61437cb513a887a1bbad006e7b1c8b414478427d33de47c5600af3c748f108da\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Address.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize, which returns 0 for contracts in\\n // construction, since the code is only stored at the end of the\\n // constructor execution.\\n\\n uint256 size;\\n assembly {\\n size := extcodesize(account)\\n }\\n return size > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x51b758a8815ecc9596c66c37d56b1d33883a444631a3f916b9fe65cb863ef7c4\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/math/SafeMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\\n\\npragma solidity ^0.8.0;\\n\\n// CAUTION\\n// This version of SafeMath should only be used with Solidity 0.8 or later,\\n// because it relies on the compiler's built in overflow checks.\\n\\n/**\\n * @dev Wrappers over Solidity's arithmetic operations.\\n *\\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\\n * now has built in overflow checking.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n uint256 c = a + b;\\n if (c < a) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b > a) return (false, 0);\\n return (true, a - b);\\n }\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) return (true, 0);\\n uint256 c = a * b;\\n if (c / a != b) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a / b);\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a % b);\\n }\\n }\\n\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n *\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a + b;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n *\\n * - Subtraction cannot overflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a - b;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n *\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a * b;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator.\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a / b;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a % b;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\\n * overflow (when the result is negative).\\n *\\n * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {trySub}.\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n *\\n * - Subtraction cannot overflow.\\n */\\n function sub(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b <= a, errorMessage);\\n return a - b;\\n }\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function div(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a / b;\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting with custom message when dividing by zero.\\n *\\n * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {tryMod}.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function mod(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a % b;\\n }\\n }\\n}\\n\",\"keccak256\":\"0xa2f576be637946f767aa56601c26d717f48a0aff44f82e46f13807eea1009a21\",\"license\":\"MIT\"},\"contracts/governance/Governable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Base for contracts that are managed by the Origin Protocol's Governor.\\n * @dev Copy of the openzeppelin Ownable.sol contract with nomenclature change\\n * from owner to governor and renounce methods removed. Does not use\\n * Context.sol like Ownable.sol does for simplification.\\n * @author Origin Protocol Inc\\n */\\ncontract Governable {\\n // Storage position of the owner and pendingOwner of the contract\\n // keccak256(\\\"OUSD.governor\\\");\\n bytes32 private constant governorPosition =\\n 0x7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a;\\n\\n // keccak256(\\\"OUSD.pending.governor\\\");\\n bytes32 private constant pendingGovernorPosition =\\n 0x44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db;\\n\\n // keccak256(\\\"OUSD.reentry.status\\\");\\n bytes32 private constant reentryStatusPosition =\\n 0x53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac4535;\\n\\n // See OpenZeppelin ReentrancyGuard implementation\\n uint256 constant _NOT_ENTERED = 1;\\n uint256 constant _ENTERED = 2;\\n\\n event PendingGovernorshipTransfer(\\n address indexed previousGovernor,\\n address indexed newGovernor\\n );\\n\\n event GovernorshipTransferred(\\n address indexed previousGovernor,\\n address indexed newGovernor\\n );\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial Governor.\\n */\\n constructor() {\\n _setGovernor(msg.sender);\\n emit GovernorshipTransferred(address(0), _governor());\\n }\\n\\n /**\\n * @notice Returns the address of the current Governor.\\n */\\n function governor() public view returns (address) {\\n return _governor();\\n }\\n\\n /**\\n * @dev Returns the address of the current Governor.\\n */\\n function _governor() internal view returns (address governorOut) {\\n bytes32 position = governorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n governorOut := sload(position)\\n }\\n }\\n\\n /**\\n * @dev Returns the address of the pending Governor.\\n */\\n function _pendingGovernor()\\n internal\\n view\\n returns (address pendingGovernor)\\n {\\n bytes32 position = pendingGovernorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n pendingGovernor := sload(position)\\n }\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the Governor.\\n */\\n modifier onlyGovernor() {\\n require(isGovernor(), \\\"Caller is not the Governor\\\");\\n _;\\n }\\n\\n /**\\n * @notice Returns true if the caller is the current Governor.\\n */\\n function isGovernor() public view returns (bool) {\\n return msg.sender == _governor();\\n }\\n\\n function _setGovernor(address newGovernor) internal {\\n bytes32 position = governorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, newGovernor)\\n }\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a `nonReentrant` function from another `nonReentrant`\\n * function is not supported. It is possible to prevent this from happening\\n * by making the `nonReentrant` function external, and make it call a\\n * `private` function that does the actual work.\\n */\\n modifier nonReentrant() {\\n bytes32 position = reentryStatusPosition;\\n uint256 _reentry_status;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n _reentry_status := sload(position)\\n }\\n\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_reentry_status != _ENTERED, \\\"Reentrant call\\\");\\n\\n // Any calls to nonReentrant after this point will fail\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, _ENTERED)\\n }\\n\\n _;\\n\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, _NOT_ENTERED)\\n }\\n }\\n\\n function _setPendingGovernor(address newGovernor) internal {\\n bytes32 position = pendingGovernorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, newGovernor)\\n }\\n }\\n\\n /**\\n * @notice Transfers Governance of the contract to a new account (`newGovernor`).\\n * Can only be called by the current Governor. Must be claimed for this to complete\\n * @param _newGovernor Address of the new Governor\\n */\\n function transferGovernance(address _newGovernor) external onlyGovernor {\\n _setPendingGovernor(_newGovernor);\\n emit PendingGovernorshipTransfer(_governor(), _newGovernor);\\n }\\n\\n /**\\n * @notice Claim Governance of the contract to a new account (`newGovernor`).\\n * Can only be called by the new Governor.\\n */\\n function claimGovernance() external {\\n require(\\n msg.sender == _pendingGovernor(),\\n \\\"Only the pending Governor can complete the claim\\\"\\n );\\n _changeGovernor(msg.sender);\\n }\\n\\n /**\\n * @dev Change Governance of the contract to a new account (`newGovernor`).\\n * @param _newGovernor Address of the new Governor\\n */\\n function _changeGovernor(address _newGovernor) internal {\\n require(_newGovernor != address(0), \\\"New Governor is address(0)\\\");\\n emit GovernorshipTransferred(_governor(), _newGovernor);\\n _setGovernor(_newGovernor);\\n }\\n}\\n\",\"keccak256\":\"0xb7133d6ce7a9e673ff79fcedb3fd41ae6e58e251f94915bb65731abe524270b4\",\"license\":\"MIT\"},\"contracts/interfaces/IBasicToken.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IBasicToken {\\n function symbol() external view returns (string memory);\\n\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0xa562062698aa12572123b36dfd2072f1a39e44fed2031cc19c2c9fd522f96ec2\",\"license\":\"MIT\"},\"contracts/interfaces/IDripper.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IDripper {\\n /// @notice How much funds have dripped out already and are currently\\n // available to be sent to the vault.\\n /// @return The amount that would be sent if a collect was called\\n function availableFunds() external view returns (uint256);\\n\\n /// @notice Collect all dripped funds and send to vault.\\n /// Recalculate new drip rate.\\n function collect() external;\\n\\n /// @notice Collect all dripped funds, send to vault, recalculate new drip\\n /// rate, and rebase mToken.\\n function collectAndRebase() external;\\n}\\n\",\"keccak256\":\"0xa2c33ae21a1331a27a17d550d2dd0774a959e17380bb55d6f6c1797d938b8e50\",\"license\":\"MIT\"},\"contracts/interfaces/IGetExchangeRateToken.sol\":{\"content\":\"pragma solidity ^0.8.0;\\n\\ninterface IGetExchangeRateToken {\\n function getExchangeRate() external view returns (uint256 _exchangeRate);\\n}\\n\",\"keccak256\":\"0x641d5892d570f3f9e256d39a9571e58b02c39368726b01c4cdf7d91f45e349d8\"},\"contracts/interfaces/IOracle.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IOracle {\\n /**\\n * @dev returns the asset price in USD, in 8 decimal digits.\\n *\\n * The version of priceProvider deployed for OETH has 18 decimal digits\\n */\\n function price(address asset) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0x9eabf152389f145c9c23ed71972af73fb1708cbc4b26e524a9ba29a557b7cfe5\",\"license\":\"MIT\"},\"contracts/interfaces/IStrategy.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Platform interface to integrate with lending platform like Compound, AAVE etc.\\n */\\ninterface IStrategy {\\n /**\\n * @dev Deposit the given asset to platform\\n * @param _asset asset address\\n * @param _amount Amount to deposit\\n */\\n function deposit(address _asset, uint256 _amount) external;\\n\\n /**\\n * @dev Deposit the entire balance of all supported assets in the Strategy\\n * to the platform\\n */\\n function depositAll() external;\\n\\n /**\\n * @dev Withdraw given asset from Lending platform\\n */\\n function withdraw(\\n address _recipient,\\n address _asset,\\n uint256 _amount\\n ) external;\\n\\n /**\\n * @dev Liquidate all assets in strategy and return them to Vault.\\n */\\n function withdrawAll() external;\\n\\n /**\\n * @dev Returns the current balance of the given asset.\\n */\\n function checkBalance(address _asset)\\n external\\n view\\n returns (uint256 balance);\\n\\n /**\\n * @dev Returns bool indicating whether strategy supports asset.\\n */\\n function supportsAsset(address _asset) external view returns (bool);\\n\\n /**\\n * @dev Collect reward tokens from the Strategy.\\n */\\n function collectRewardTokens() external;\\n\\n /**\\n * @dev The address array of the reward tokens for the Strategy.\\n */\\n function getRewardTokenAddresses() external view returns (address[] memory);\\n}\\n\",\"keccak256\":\"0xb291e409a9b95527f9ed19cd6bff8eeb9921a21c1f5194a48c0bb9ce6613959a\",\"license\":\"MIT\"},\"contracts/token/OUSD.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OUSD Token Contract\\n * @dev ERC20 compatible contract for OUSD\\n * @dev Implements an elastic supply\\n * @author Origin Protocol Inc\\n */\\nimport { SafeMath } from \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\nimport { Address } from \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport { Initializable } from \\\"../utils/Initializable.sol\\\";\\nimport { InitializableERC20Detailed } from \\\"../utils/InitializableERC20Detailed.sol\\\";\\nimport { StableMath } from \\\"../utils/StableMath.sol\\\";\\nimport { Governable } from \\\"../governance/Governable.sol\\\";\\n\\n/**\\n * NOTE that this is an ERC20 token but the invariant that the sum of\\n * balanceOf(x) for all x is not >= totalSupply(). This is a consequence of the\\n * rebasing design. Any integrations with OUSD should be aware.\\n */\\n\\ncontract OUSD is Initializable, InitializableERC20Detailed, Governable {\\n using SafeMath for uint256;\\n using StableMath for uint256;\\n\\n event TotalSupplyUpdatedHighres(\\n uint256 totalSupply,\\n uint256 rebasingCredits,\\n uint256 rebasingCreditsPerToken\\n );\\n event AccountRebasingEnabled(address account);\\n event AccountRebasingDisabled(address account);\\n\\n enum RebaseOptions {\\n NotSet,\\n OptOut,\\n OptIn\\n }\\n\\n uint256 private constant MAX_SUPPLY = ~uint128(0); // (2^128) - 1\\n uint256 public _totalSupply;\\n mapping(address => mapping(address => uint256)) private _allowances;\\n address public vaultAddress = address(0);\\n mapping(address => uint256) private _creditBalances;\\n uint256 private _rebasingCredits;\\n uint256 private _rebasingCreditsPerToken;\\n // Frozen address/credits are non rebasing (value is held in contracts which\\n // do not receive yield unless they explicitly opt in)\\n uint256 public nonRebasingSupply;\\n mapping(address => uint256) public nonRebasingCreditsPerToken;\\n mapping(address => RebaseOptions) public rebaseState;\\n mapping(address => uint256) public isUpgraded;\\n\\n uint256 private constant RESOLUTION_INCREASE = 1e9;\\n\\n function initialize(\\n string calldata _nameArg,\\n string calldata _symbolArg,\\n address _vaultAddress,\\n uint256 _initialCreditsPerToken\\n ) external onlyGovernor initializer {\\n InitializableERC20Detailed._initialize(_nameArg, _symbolArg, 18);\\n _rebasingCreditsPerToken = _initialCreditsPerToken;\\n vaultAddress = _vaultAddress;\\n }\\n\\n /**\\n * @dev Verifies that the caller is the Vault contract\\n */\\n modifier onlyVault() {\\n require(vaultAddress == msg.sender, \\\"Caller is not the Vault\\\");\\n _;\\n }\\n\\n /**\\n * @return The total supply of OUSD.\\n */\\n function totalSupply() public view override returns (uint256) {\\n return _totalSupply;\\n }\\n\\n /**\\n * @return Low resolution rebasingCreditsPerToken\\n */\\n function rebasingCreditsPerToken() public view returns (uint256) {\\n return _rebasingCreditsPerToken / RESOLUTION_INCREASE;\\n }\\n\\n /**\\n * @return Low resolution total number of rebasing credits\\n */\\n function rebasingCredits() public view returns (uint256) {\\n return _rebasingCredits / RESOLUTION_INCREASE;\\n }\\n\\n /**\\n * @return High resolution rebasingCreditsPerToken\\n */\\n function rebasingCreditsPerTokenHighres() public view returns (uint256) {\\n return _rebasingCreditsPerToken;\\n }\\n\\n /**\\n * @return High resolution total number of rebasing credits\\n */\\n function rebasingCreditsHighres() public view returns (uint256) {\\n return _rebasingCredits;\\n }\\n\\n /**\\n * @dev Gets the balance of the specified address.\\n * @param _account Address to query the balance of.\\n * @return A uint256 representing the amount of base units owned by the\\n * specified address.\\n */\\n function balanceOf(address _account)\\n public\\n view\\n override\\n returns (uint256)\\n {\\n if (_creditBalances[_account] == 0) return 0;\\n return\\n _creditBalances[_account].divPrecisely(_creditsPerToken(_account));\\n }\\n\\n /**\\n * @dev Gets the credits balance of the specified address.\\n * @dev Backwards compatible with old low res credits per token.\\n * @param _account The address to query the balance of.\\n * @return (uint256, uint256) Credit balance and credits per token of the\\n * address\\n */\\n function creditsBalanceOf(address _account)\\n public\\n view\\n returns (uint256, uint256)\\n {\\n uint256 cpt = _creditsPerToken(_account);\\n if (cpt == 1e27) {\\n // For a period before the resolution upgrade, we created all new\\n // contract accounts at high resolution. Since they are not changing\\n // as a result of this upgrade, we will return their true values\\n return (_creditBalances[_account], cpt);\\n } else {\\n return (\\n _creditBalances[_account] / RESOLUTION_INCREASE,\\n cpt / RESOLUTION_INCREASE\\n );\\n }\\n }\\n\\n /**\\n * @dev Gets the credits balance of the specified address.\\n * @param _account The address to query the balance of.\\n * @return (uint256, uint256, bool) Credit balance, credits per token of the\\n * address, and isUpgraded\\n */\\n function creditsBalanceOfHighres(address _account)\\n public\\n view\\n returns (\\n uint256,\\n uint256,\\n bool\\n )\\n {\\n return (\\n _creditBalances[_account],\\n _creditsPerToken(_account),\\n isUpgraded[_account] == 1\\n );\\n }\\n\\n /**\\n * @dev Transfer tokens to a specified address.\\n * @param _to the address to transfer to.\\n * @param _value the amount to be transferred.\\n * @return true on success.\\n */\\n function transfer(address _to, uint256 _value)\\n public\\n override\\n returns (bool)\\n {\\n require(_to != address(0), \\\"Transfer to zero address\\\");\\n require(\\n _value <= balanceOf(msg.sender),\\n \\\"Transfer greater than balance\\\"\\n );\\n\\n _executeTransfer(msg.sender, _to, _value);\\n\\n emit Transfer(msg.sender, _to, _value);\\n\\n return true;\\n }\\n\\n /**\\n * @dev Transfer tokens from one address to another.\\n * @param _from The address you want to send tokens from.\\n * @param _to The address you want to transfer to.\\n * @param _value The amount of tokens to be transferred.\\n */\\n function transferFrom(\\n address _from,\\n address _to,\\n uint256 _value\\n ) public override returns (bool) {\\n require(_to != address(0), \\\"Transfer to zero address\\\");\\n require(_value <= balanceOf(_from), \\\"Transfer greater than balance\\\");\\n\\n _allowances[_from][msg.sender] = _allowances[_from][msg.sender].sub(\\n _value\\n );\\n\\n _executeTransfer(_from, _to, _value);\\n\\n emit Transfer(_from, _to, _value);\\n\\n return true;\\n }\\n\\n /**\\n * @dev Update the count of non rebasing credits in response to a transfer\\n * @param _from The address you want to send tokens from.\\n * @param _to The address you want to transfer to.\\n * @param _value Amount of OUSD to transfer\\n */\\n function _executeTransfer(\\n address _from,\\n address _to,\\n uint256 _value\\n ) internal {\\n bool isNonRebasingTo = _isNonRebasingAccount(_to);\\n bool isNonRebasingFrom = _isNonRebasingAccount(_from);\\n\\n // Credits deducted and credited might be different due to the\\n // differing creditsPerToken used by each account\\n uint256 creditsCredited = _value.mulTruncate(_creditsPerToken(_to));\\n uint256 creditsDeducted = _value.mulTruncate(_creditsPerToken(_from));\\n\\n _creditBalances[_from] = _creditBalances[_from].sub(\\n creditsDeducted,\\n \\\"Transfer amount exceeds balance\\\"\\n );\\n _creditBalances[_to] = _creditBalances[_to].add(creditsCredited);\\n\\n if (isNonRebasingTo && !isNonRebasingFrom) {\\n // Transfer to non-rebasing account from rebasing account, credits\\n // are removed from the non rebasing tally\\n nonRebasingSupply = nonRebasingSupply.add(_value);\\n // Update rebasingCredits by subtracting the deducted amount\\n _rebasingCredits = _rebasingCredits.sub(creditsDeducted);\\n } else if (!isNonRebasingTo && isNonRebasingFrom) {\\n // Transfer to rebasing account from non-rebasing account\\n // Decreasing non-rebasing credits by the amount that was sent\\n nonRebasingSupply = nonRebasingSupply.sub(_value);\\n // Update rebasingCredits by adding the credited amount\\n _rebasingCredits = _rebasingCredits.add(creditsCredited);\\n }\\n }\\n\\n /**\\n * @dev Function to check the amount of tokens that _owner has allowed to\\n * `_spender`.\\n * @param _owner The address which owns the funds.\\n * @param _spender The address which will spend the funds.\\n * @return The number of tokens still available for the _spender.\\n */\\n function allowance(address _owner, address _spender)\\n public\\n view\\n override\\n returns (uint256)\\n {\\n return _allowances[_owner][_spender];\\n }\\n\\n /**\\n * @dev Approve the passed address to spend the specified amount of tokens\\n * on behalf of msg.sender. This method is included for ERC20\\n * compatibility. `increaseAllowance` and `decreaseAllowance` should be\\n * used instead.\\n *\\n * Changing an allowance with this method brings the risk that someone\\n * may transfer both the old and the new allowance - if they are both\\n * greater than zero - if a transfer transaction is mined before the\\n * later approve() call is mined.\\n * @param _spender The address which will spend the funds.\\n * @param _value The amount of tokens to be spent.\\n */\\n function approve(address _spender, uint256 _value)\\n public\\n override\\n returns (bool)\\n {\\n _allowances[msg.sender][_spender] = _value;\\n emit Approval(msg.sender, _spender, _value);\\n return true;\\n }\\n\\n /**\\n * @dev Increase the amount of tokens that an owner has allowed to\\n * `_spender`.\\n * This method should be used instead of approve() to avoid the double\\n * approval vulnerability described above.\\n * @param _spender The address which will spend the funds.\\n * @param _addedValue The amount of tokens to increase the allowance by.\\n */\\n function increaseAllowance(address _spender, uint256 _addedValue)\\n public\\n returns (bool)\\n {\\n _allowances[msg.sender][_spender] = _allowances[msg.sender][_spender]\\n .add(_addedValue);\\n emit Approval(msg.sender, _spender, _allowances[msg.sender][_spender]);\\n return true;\\n }\\n\\n /**\\n * @dev Decrease the amount of tokens that an owner has allowed to\\n `_spender`.\\n * @param _spender The address which will spend the funds.\\n * @param _subtractedValue The amount of tokens to decrease the allowance\\n * by.\\n */\\n function decreaseAllowance(address _spender, uint256 _subtractedValue)\\n public\\n returns (bool)\\n {\\n uint256 oldValue = _allowances[msg.sender][_spender];\\n if (_subtractedValue >= oldValue) {\\n _allowances[msg.sender][_spender] = 0;\\n } else {\\n _allowances[msg.sender][_spender] = oldValue.sub(_subtractedValue);\\n }\\n emit Approval(msg.sender, _spender, _allowances[msg.sender][_spender]);\\n return true;\\n }\\n\\n /**\\n * @dev Mints new tokens, increasing totalSupply.\\n */\\n function mint(address _account, uint256 _amount) external onlyVault {\\n _mint(_account, _amount);\\n }\\n\\n /**\\n * @dev Creates `_amount` tokens and assigns them to `_account`, increasing\\n * the total supply.\\n *\\n * Emits a {Transfer} event with `from` set to the zero address.\\n *\\n * Requirements\\n *\\n * - `to` cannot be the zero address.\\n */\\n function _mint(address _account, uint256 _amount) internal nonReentrant {\\n require(_account != address(0), \\\"Mint to the zero address\\\");\\n\\n bool isNonRebasingAccount = _isNonRebasingAccount(_account);\\n\\n uint256 creditAmount = _amount.mulTruncate(_creditsPerToken(_account));\\n _creditBalances[_account] = _creditBalances[_account].add(creditAmount);\\n\\n // If the account is non rebasing and doesn't have a set creditsPerToken\\n // then set it i.e. this is a mint from a fresh contract\\n if (isNonRebasingAccount) {\\n nonRebasingSupply = nonRebasingSupply.add(_amount);\\n } else {\\n _rebasingCredits = _rebasingCredits.add(creditAmount);\\n }\\n\\n _totalSupply = _totalSupply.add(_amount);\\n\\n require(_totalSupply < MAX_SUPPLY, \\\"Max supply\\\");\\n\\n emit Transfer(address(0), _account, _amount);\\n }\\n\\n /**\\n * @dev Burns tokens, decreasing totalSupply.\\n */\\n function burn(address account, uint256 amount) external onlyVault {\\n _burn(account, amount);\\n }\\n\\n /**\\n * @dev Destroys `_amount` tokens from `_account`, reducing the\\n * total supply.\\n *\\n * Emits a {Transfer} event with `to` set to the zero address.\\n *\\n * Requirements\\n *\\n * - `_account` cannot be the zero address.\\n * - `_account` must have at least `_amount` tokens.\\n */\\n function _burn(address _account, uint256 _amount) internal nonReentrant {\\n require(_account != address(0), \\\"Burn from the zero address\\\");\\n if (_amount == 0) {\\n return;\\n }\\n\\n bool isNonRebasingAccount = _isNonRebasingAccount(_account);\\n uint256 creditAmount = _amount.mulTruncate(_creditsPerToken(_account));\\n uint256 currentCredits = _creditBalances[_account];\\n\\n // Remove the credits, burning rounding errors\\n if (\\n currentCredits == creditAmount || currentCredits - 1 == creditAmount\\n ) {\\n // Handle dust from rounding\\n _creditBalances[_account] = 0;\\n } else if (currentCredits > creditAmount) {\\n _creditBalances[_account] = _creditBalances[_account].sub(\\n creditAmount\\n );\\n } else {\\n revert(\\\"Remove exceeds balance\\\");\\n }\\n\\n // Remove from the credit tallies and non-rebasing supply\\n if (isNonRebasingAccount) {\\n nonRebasingSupply = nonRebasingSupply.sub(_amount);\\n } else {\\n _rebasingCredits = _rebasingCredits.sub(creditAmount);\\n }\\n\\n _totalSupply = _totalSupply.sub(_amount);\\n\\n emit Transfer(_account, address(0), _amount);\\n }\\n\\n /**\\n * @dev Get the credits per token for an account. Returns a fixed amount\\n * if the account is non-rebasing.\\n * @param _account Address of the account.\\n */\\n function _creditsPerToken(address _account)\\n internal\\n view\\n returns (uint256)\\n {\\n if (nonRebasingCreditsPerToken[_account] != 0) {\\n return nonRebasingCreditsPerToken[_account];\\n } else {\\n return _rebasingCreditsPerToken;\\n }\\n }\\n\\n /**\\n * @dev Is an account using rebasing accounting or non-rebasing accounting?\\n * Also, ensure contracts are non-rebasing if they have not opted in.\\n * @param _account Address of the account.\\n */\\n function _isNonRebasingAccount(address _account) internal returns (bool) {\\n bool isContract = Address.isContract(_account);\\n if (isContract && rebaseState[_account] == RebaseOptions.NotSet) {\\n _ensureRebasingMigration(_account);\\n }\\n return nonRebasingCreditsPerToken[_account] > 0;\\n }\\n\\n /**\\n * @dev Ensures internal account for rebasing and non-rebasing credits and\\n * supply is updated following deployment of frozen yield change.\\n */\\n function _ensureRebasingMigration(address _account) internal {\\n if (nonRebasingCreditsPerToken[_account] == 0) {\\n emit AccountRebasingDisabled(_account);\\n if (_creditBalances[_account] == 0) {\\n // Since there is no existing balance, we can directly set to\\n // high resolution, and do not have to do any other bookkeeping\\n nonRebasingCreditsPerToken[_account] = 1e27;\\n } else {\\n // Migrate an existing account:\\n\\n // Set fixed credits per token for this account\\n nonRebasingCreditsPerToken[_account] = _rebasingCreditsPerToken;\\n // Update non rebasing supply\\n nonRebasingSupply = nonRebasingSupply.add(balanceOf(_account));\\n // Update credit tallies\\n _rebasingCredits = _rebasingCredits.sub(\\n _creditBalances[_account]\\n );\\n }\\n }\\n }\\n\\n /**\\n * @notice Enable rebasing for an account.\\n * @dev Add a contract address to the non-rebasing exception list. The\\n * address's balance will be part of rebases and the account will be exposed\\n * to upside and downside.\\n * @param _account Address of the account.\\n */\\n function governanceRebaseOptIn(address _account)\\n public\\n nonReentrant\\n onlyGovernor\\n {\\n _rebaseOptIn(_account);\\n }\\n\\n /**\\n * @dev Add a contract address to the non-rebasing exception list. The\\n * address's balance will be part of rebases and the account will be exposed\\n * to upside and downside.\\n */\\n function rebaseOptIn() public nonReentrant {\\n _rebaseOptIn(msg.sender);\\n }\\n\\n function _rebaseOptIn(address _account) internal {\\n require(_isNonRebasingAccount(_account), \\\"Account has not opted out\\\");\\n\\n // Convert balance into the same amount at the current exchange rate\\n uint256 newCreditBalance = _creditBalances[_account]\\n .mul(_rebasingCreditsPerToken)\\n .div(_creditsPerToken(_account));\\n\\n // Decreasing non rebasing supply\\n nonRebasingSupply = nonRebasingSupply.sub(balanceOf(_account));\\n\\n _creditBalances[_account] = newCreditBalance;\\n\\n // Increase rebasing credits, totalSupply remains unchanged so no\\n // adjustment necessary\\n _rebasingCredits = _rebasingCredits.add(_creditBalances[_account]);\\n\\n rebaseState[_account] = RebaseOptions.OptIn;\\n\\n // Delete any fixed credits per token\\n delete nonRebasingCreditsPerToken[_account];\\n emit AccountRebasingEnabled(_account);\\n }\\n\\n /**\\n * @dev Explicitly mark that an address is non-rebasing.\\n */\\n function rebaseOptOut() public nonReentrant {\\n require(!_isNonRebasingAccount(msg.sender), \\\"Account has not opted in\\\");\\n\\n // Increase non rebasing supply\\n nonRebasingSupply = nonRebasingSupply.add(balanceOf(msg.sender));\\n // Set fixed credits per token\\n nonRebasingCreditsPerToken[msg.sender] = _rebasingCreditsPerToken;\\n\\n // Decrease rebasing credits, total supply remains unchanged so no\\n // adjustment necessary\\n _rebasingCredits = _rebasingCredits.sub(_creditBalances[msg.sender]);\\n\\n // Mark explicitly opted out of rebasing\\n rebaseState[msg.sender] = RebaseOptions.OptOut;\\n emit AccountRebasingDisabled(msg.sender);\\n }\\n\\n /**\\n * @dev Modify the supply without minting new tokens. This uses a change in\\n * the exchange rate between \\\"credits\\\" and OUSD tokens to change balances.\\n * @param _newTotalSupply New total supply of OUSD.\\n */\\n function changeSupply(uint256 _newTotalSupply)\\n external\\n onlyVault\\n nonReentrant\\n {\\n require(_totalSupply > 0, \\\"Cannot increase 0 supply\\\");\\n\\n if (_totalSupply == _newTotalSupply) {\\n emit TotalSupplyUpdatedHighres(\\n _totalSupply,\\n _rebasingCredits,\\n _rebasingCreditsPerToken\\n );\\n return;\\n }\\n\\n _totalSupply = _newTotalSupply > MAX_SUPPLY\\n ? MAX_SUPPLY\\n : _newTotalSupply;\\n\\n _rebasingCreditsPerToken = _rebasingCredits.divPrecisely(\\n _totalSupply.sub(nonRebasingSupply)\\n );\\n\\n require(_rebasingCreditsPerToken > 0, \\\"Invalid change in supply\\\");\\n\\n _totalSupply = _rebasingCredits\\n .divPrecisely(_rebasingCreditsPerToken)\\n .add(nonRebasingSupply);\\n\\n emit TotalSupplyUpdatedHighres(\\n _totalSupply,\\n _rebasingCredits,\\n _rebasingCreditsPerToken\\n );\\n }\\n}\\n\",\"keccak256\":\"0x2dc66b1ba02716d64eb47dd9117fda62650d8b57669e6c351437e0ad29ad5f19\",\"license\":\"MIT\"},\"contracts/utils/Helpers.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { IBasicToken } from \\\"../interfaces/IBasicToken.sol\\\";\\n\\nlibrary Helpers {\\n /**\\n * @notice Fetch the `symbol()` from an ERC20 token\\n * @dev Grabs the `symbol()` from a contract\\n * @param _token Address of the ERC20 token\\n * @return string Symbol of the ERC20 token\\n */\\n function getSymbol(address _token) internal view returns (string memory) {\\n string memory symbol = IBasicToken(_token).symbol();\\n return symbol;\\n }\\n\\n /**\\n * @notice Fetch the `decimals()` from an ERC20 token\\n * @dev Grabs the `decimals()` from a contract and fails if\\n * the decimal value does not live within a certain range\\n * @param _token Address of the ERC20 token\\n * @return uint256 Decimals of the ERC20 token\\n */\\n function getDecimals(address _token) internal view returns (uint256) {\\n uint256 decimals = IBasicToken(_token).decimals();\\n require(\\n decimals >= 4 && decimals <= 18,\\n \\\"Token must have sufficient decimal places\\\"\\n );\\n\\n return decimals;\\n }\\n}\\n\",\"keccak256\":\"0x108b7a69e0140da0072ca18f90a03a3340574400f81aa6076cd2cccdf13699c2\",\"license\":\"MIT\"},\"contracts/utils/Initializable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Base contract any contracts that need to initialize state after deployment.\\n * @author Origin Protocol Inc\\n */\\nabstract contract Initializable {\\n /**\\n * @dev Indicates that the contract has been initialized.\\n */\\n bool private initialized;\\n\\n /**\\n * @dev Indicates that the contract is in the process of being initialized.\\n */\\n bool private initializing;\\n\\n /**\\n * @dev Modifier to protect an initializer function from being invoked twice.\\n */\\n modifier initializer() {\\n require(\\n initializing || !initialized,\\n \\\"Initializable: contract is already initialized\\\"\\n );\\n\\n bool isTopLevelCall = !initializing;\\n if (isTopLevelCall) {\\n initializing = true;\\n initialized = true;\\n }\\n\\n _;\\n\\n if (isTopLevelCall) {\\n initializing = false;\\n }\\n }\\n\\n uint256[50] private ______gap;\\n}\\n\",\"keccak256\":\"0xaadbcc138114afed4af4f353c2ced2916e6ee14be91434789187f192caf0d786\",\"license\":\"MIT\"},\"contracts/utils/InitializableERC20Detailed.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { IERC20 } from \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @dev Optional functions from the ERC20 standard.\\n * Converted from openzeppelin/contracts/token/ERC20/ERC20Detailed.sol\\n * @author Origin Protocol Inc\\n */\\nabstract contract InitializableERC20Detailed is IERC20 {\\n // Storage gap to skip storage from prior to OUSD reset\\n uint256[100] private _____gap;\\n\\n string private _name;\\n string private _symbol;\\n uint8 private _decimals;\\n\\n /**\\n * @dev Sets the values for `name`, `symbol`, and `decimals`. All three of\\n * these values are immutable: they can only be set once during\\n * construction.\\n * @notice To avoid variable shadowing appended `Arg` after arguments name.\\n */\\n function _initialize(\\n string memory nameArg,\\n string memory symbolArg,\\n uint8 decimalsArg\\n ) internal {\\n _name = nameArg;\\n _symbol = symbolArg;\\n _decimals = decimalsArg;\\n }\\n\\n /**\\n * @notice Returns the name of the token.\\n */\\n function name() public view returns (string memory) {\\n return _name;\\n }\\n\\n /**\\n * @notice Returns the symbol of the token, usually a shorter version of the\\n * name.\\n */\\n function symbol() public view returns (string memory) {\\n return _symbol;\\n }\\n\\n /**\\n * @notice Returns the number of decimals used to get its user representation.\\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\\n * be displayed to a user as `5,05` (`505 / 10 ** 2`).\\n *\\n * Tokens usually opt for a value of 18, imitating the relationship between\\n * Ether and Wei.\\n *\\n * NOTE: This information is only used for _display_ purposes: it in\\n * no way affects any of the arithmetic of the contract, including\\n * {IERC20-balanceOf} and {IERC20-transfer}.\\n */\\n function decimals() public view returns (uint8) {\\n return _decimals;\\n }\\n}\\n\",\"keccak256\":\"0xe35ac2d813a30d845a3b52bba72588d7e936c2b3f3373d15568c14db46aeed60\",\"license\":\"MIT\"},\"contracts/utils/StableMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { SafeMath } from \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\n\\n// Based on StableMath from Stability Labs Pty. Ltd.\\n// https://github.com/mstable/mStable-contracts/blob/master/contracts/shared/StableMath.sol\\n\\nlibrary StableMath {\\n using SafeMath for uint256;\\n\\n /**\\n * @dev Scaling unit for use in specific calculations,\\n * where 1 * 10**18, or 1e18 represents a unit '1'\\n */\\n uint256 private constant FULL_SCALE = 1e18;\\n\\n /***************************************\\n Helpers\\n ****************************************/\\n\\n /**\\n * @dev Adjust the scale of an integer\\n * @param to Decimals to scale to\\n * @param from Decimals to scale from\\n */\\n function scaleBy(\\n uint256 x,\\n uint256 to,\\n uint256 from\\n ) internal pure returns (uint256) {\\n if (to > from) {\\n x = x.mul(10**(to - from));\\n } else if (to < from) {\\n // slither-disable-next-line divide-before-multiply\\n x = x.div(10**(from - to));\\n }\\n return x;\\n }\\n\\n /***************************************\\n Precise Arithmetic\\n ****************************************/\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the full scale\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit\\n */\\n function mulTruncate(uint256 x, uint256 y) internal pure returns (uint256) {\\n return mulTruncateScale(x, y, FULL_SCALE);\\n }\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the given scale. For example,\\n * when calculating 90% of 10e18, (10e18 * 9e17) / 1e18 = (9e36) / 1e18 = 9e18\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @param scale Scale unit\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit\\n */\\n function mulTruncateScale(\\n uint256 x,\\n uint256 y,\\n uint256 scale\\n ) internal pure returns (uint256) {\\n // e.g. assume scale = fullScale\\n // z = 10e18 * 9e17 = 9e36\\n uint256 z = x.mul(y);\\n // return 9e36 / 1e18 = 9e18\\n return z.div(scale);\\n }\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the full scale, rounding up the result\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit, rounded up to the closest base unit.\\n */\\n function mulTruncateCeil(uint256 x, uint256 y)\\n internal\\n pure\\n returns (uint256)\\n {\\n // e.g. 8e17 * 17268172638 = 138145381104e17\\n uint256 scaled = x.mul(y);\\n // e.g. 138145381104e17 + 9.99...e17 = 138145381113.99...e17\\n uint256 ceil = scaled.add(FULL_SCALE.sub(1));\\n // e.g. 13814538111.399...e18 / 1e18 = 13814538111\\n return ceil.div(FULL_SCALE);\\n }\\n\\n /**\\n * @dev Precisely divides two units, by first scaling the left hand operand. Useful\\n * for finding percentage weightings, i.e. 8e18/10e18 = 80% (or 8e17)\\n * @param x Left hand input to division\\n * @param y Right hand input to division\\n * @return Result after multiplying the left operand by the scale, and\\n * executing the division on the right hand input.\\n */\\n function divPrecisely(uint256 x, uint256 y)\\n internal\\n pure\\n returns (uint256)\\n {\\n // e.g. 8e18 * 1e18 = 8e36\\n uint256 z = x.mul(FULL_SCALE);\\n // e.g. 8e36 / 10e18 = 8e17\\n return z.div(y);\\n }\\n}\\n\",\"keccak256\":\"0x1eb49f6f79045d9e0a8e1dced8e01d9e559e5fac554dcbb53e43140b601b04e7\",\"license\":\"MIT\"},\"contracts/vault/OETHVaultCore.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { StableMath } from \\\"../utils/StableMath.sol\\\";\\nimport { VaultCore } from \\\"./VaultCore.sol\\\";\\n\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport { IERC20 } from \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport { IStrategy } from \\\"../interfaces/IStrategy.sol\\\";\\nimport { IDripper } from \\\"../interfaces/IDripper.sol\\\";\\n\\n/**\\n * @title OETH VaultCore Contract\\n * @author Origin Protocol Inc\\n */\\ncontract OETHVaultCore is VaultCore {\\n using SafeERC20 for IERC20;\\n using StableMath for uint256;\\n\\n address public immutable weth;\\n uint256 public wethAssetIndex;\\n\\n constructor(address _weth) {\\n weth = _weth;\\n }\\n\\n /**\\n * @dev Caches WETH's index in `allAssets` variable.\\n * Reduces gas usage by redeem by caching that.\\n */\\n function cacheWETHAssetIndex() external onlyGovernor {\\n uint256 assetCount = allAssets.length;\\n for (uint256 i = 0; i < assetCount; ++i) {\\n if (allAssets[i] == weth) {\\n wethAssetIndex = i;\\n break;\\n }\\n }\\n\\n require(allAssets[wethAssetIndex] == weth, \\\"Invalid WETH Asset Index\\\");\\n }\\n\\n // @inheritdoc VaultCore\\n // slither-disable-start reentrancy-no-eth\\n function _mint(\\n address _asset,\\n uint256 _amount,\\n uint256 _minimumOusdAmount\\n ) internal virtual override {\\n require(_asset == weth, \\\"Unsupported asset for minting\\\");\\n require(_amount > 0, \\\"Amount must be greater than 0\\\");\\n require(\\n _amount >= _minimumOusdAmount,\\n \\\"Mint amount lower than minimum\\\"\\n );\\n\\n emit Mint(msg.sender, _amount);\\n\\n // Rebase must happen before any transfers occur.\\n if (!rebasePaused && _amount >= rebaseThreshold) {\\n // Stream any harvested rewards (WETH) that are available to the Vault\\n IDripper(dripper).collect();\\n\\n _rebase();\\n }\\n\\n // Mint oTokens\\n oUSD.mint(msg.sender, _amount);\\n\\n // Transfer the deposited coins to the vault\\n IERC20(_asset).safeTransferFrom(msg.sender, address(this), _amount);\\n\\n // Give priority to the withdrawal queue for the new WETH liquidity\\n _addWithdrawalQueueLiquidity();\\n\\n // Auto-allocate if necessary\\n if (_amount >= autoAllocateThreshold) {\\n _allocate();\\n }\\n }\\n\\n // slither-disable-end reentrancy-no-eth\\n\\n // @inheritdoc VaultCore\\n function _calculateRedeemOutputs(uint256 _amount)\\n internal\\n view\\n virtual\\n override\\n returns (uint256[] memory outputs)\\n {\\n // Overrides `VaultCore._calculateRedeemOutputs` to redeem with only\\n // WETH instead of LST-mix. Doesn't change the function signature\\n // for backward compatibility\\n\\n // Calculate redeem fee\\n if (redeemFeeBps > 0) {\\n uint256 redeemFee = _amount.mulTruncateScale(redeemFeeBps, 1e4);\\n _amount = _amount - redeemFee;\\n }\\n\\n // Ensure that the WETH index is cached\\n uint256 _wethAssetIndex = wethAssetIndex;\\n require(\\n allAssets[_wethAssetIndex] == weth,\\n \\\"WETH Asset index not cached\\\"\\n );\\n\\n outputs = new uint256[](allAssets.length);\\n outputs[_wethAssetIndex] = _amount;\\n }\\n\\n // @inheritdoc VaultCore\\n function _redeem(uint256 _amount, uint256 _minimumUnitAmount)\\n internal\\n virtual\\n override\\n {\\n // Override `VaultCore._redeem` to simplify it. Gets rid of oracle\\n // usage and looping through all assets for LST-mix redeem. Instead\\n // does a simple WETH-only redeem.\\n emit Redeem(msg.sender, _amount);\\n\\n if (_amount == 0) {\\n return;\\n }\\n\\n // Amount excluding fees\\n uint256 amountMinusFee = _calculateRedeemOutputs(_amount)[\\n wethAssetIndex\\n ];\\n\\n require(\\n amountMinusFee >= _minimumUnitAmount,\\n \\\"Redeem amount lower than minimum\\\"\\n );\\n\\n // If there is any WETH in the Vault available after accounting for the withdrawal queue\\n if (_wethAvailable() >= amountMinusFee) {\\n // Use Vault funds first if sufficient\\n IERC20(weth).safeTransfer(msg.sender, amountMinusFee);\\n } else {\\n address strategyAddr = assetDefaultStrategies[weth];\\n if (strategyAddr != address(0)) {\\n // Nothing in Vault, but something in Strategy, send from there\\n IStrategy strategy = IStrategy(strategyAddr);\\n strategy.withdraw(msg.sender, weth, amountMinusFee);\\n } else {\\n // Cant find funds anywhere\\n revert(\\\"Liquidity error\\\");\\n }\\n }\\n\\n // Burn OETH from user (including fees)\\n oUSD.burn(msg.sender, _amount);\\n\\n _postRedeem(_amount);\\n }\\n\\n /**\\n * @notice Request an asynchronous withdrawal of the underlying asset. eg WETH\\n * @param _amount Amount of oTokens to burn. eg OETH\\n * @param requestId Unique ID for the withdrawal request\\n * @param queued Cumulative total of all WETH queued including already claimed requests.\\n * This request can be claimed once the withdrawal queue's claimable amount\\n * is greater than or equal this request's queued amount.\\n */\\n function requestWithdrawal(uint256 _amount)\\n external\\n whenNotCapitalPaused\\n nonReentrant\\n returns (uint256 requestId, uint256 queued)\\n {\\n // Burn the user's OETH\\n // This also checks the requester has enough OETH to burn\\n oUSD.burn(msg.sender, _amount);\\n\\n requestId = withdrawalQueueMetadata.nextWithdrawalIndex;\\n queued = withdrawalQueueMetadata.queued + _amount;\\n\\n // store the next withdrawal request\\n withdrawalQueueMetadata.nextWithdrawalIndex = uint128(requestId + 1);\\n withdrawalQueueMetadata.queued = uint128(queued);\\n\\n emit WithdrawalRequested(msg.sender, requestId, _amount, queued);\\n\\n withdrawalRequests[requestId] = WithdrawalRequest({\\n withdrawer: msg.sender,\\n claimed: false,\\n amount: uint128(_amount),\\n queued: uint128(queued)\\n });\\n }\\n\\n /**\\n * @notice Claim a previously requested withdrawal once it is claimable.\\n * @param requestId Unique ID for the withdrawal request\\n * @return amount Amount of WETH transferred to the withdrawer\\n */\\n function claimWithdrawal(uint256 requestId)\\n external\\n whenNotCapitalPaused\\n nonReentrant\\n returns (uint256 amount)\\n {\\n amount = _claimWithdrawal(requestId);\\n\\n // transfer WETH from the vault to the withdrawer\\n IERC20(weth).safeTransfer(msg.sender, amount);\\n }\\n\\n /**\\n * @notice Claim a previously requested withdrawals once they are claimable.\\n * @param requestIds Unique ID of each withdrawal request\\n * @return amounts Amount of WETH received for each request\\n */\\n function claimWithdrawals(uint256[] memory requestIds)\\n external\\n whenNotCapitalPaused\\n nonReentrant\\n returns (uint256[] memory amounts, uint256 totalAmount)\\n {\\n amounts = new uint256[](requestIds.length);\\n for (uint256 i = 0; i < requestIds.length; ++i) {\\n amounts[i] = _claimWithdrawal(requestIds[i]);\\n totalAmount += amounts[i];\\n }\\n\\n // transfer all the claimed WETH from the vault to the withdrawer\\n IERC20(weth).safeTransfer(msg.sender, totalAmount);\\n }\\n\\n // slither-disable-start reentrancy-no-eth\\n\\n function _claimWithdrawal(uint256 requestId)\\n internal\\n returns (uint256 amount)\\n {\\n // Check if there's enough liquidity to cover the withdrawal request\\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\\n WithdrawalRequest memory request = withdrawalRequests[requestId];\\n\\n require(request.claimed == false, \\\"already claimed\\\");\\n require(request.withdrawer == msg.sender, \\\"not requester\\\");\\n\\n // Try and get more liquidity in the withdrawal queue if there is not enough\\n if (request.queued > queue.claimable) {\\n // Stream any harvested rewards (WETH) that are available to the Vault\\n IDripper(dripper).collect();\\n\\n // Add any WETH from the Dripper to the withdrawal queue\\n uint256 addedClaimable = _addWithdrawalQueueLiquidity();\\n\\n // If there still isn't enough liquidity in the queue to claim, revert\\n require(\\n request.queued <= queue.claimable + addedClaimable,\\n \\\"queue pending liquidity\\\"\\n );\\n }\\n\\n // Store the updated claimed amount\\n withdrawalQueueMetadata.claimed = queue.claimed + request.amount;\\n // Store the request as claimed\\n withdrawalRequests[requestId].claimed = true;\\n\\n emit WithdrawalClaimed(msg.sender, requestId, request.amount);\\n\\n return request.amount;\\n }\\n\\n // slither-disable-end reentrancy-no-eth\\n\\n /// @notice Collects harvested rewards from the Dripper as WETH then\\n /// adds WETH to the withdrawal queue if there is a funding shortfall.\\n /// @dev is called from the Native Staking strategy when validator withdrawals are processed.\\n /// It also called before any WETH is allocated to a strategy.\\n function addWithdrawalQueueLiquidity() external {\\n // Stream any harvested rewards (WETH) that are available to the Vault\\n IDripper(dripper).collect();\\n\\n _addWithdrawalQueueLiquidity();\\n }\\n\\n /// @dev Adds WETH to the withdrawal queue if there is a funding shortfall.\\n function _addWithdrawalQueueLiquidity()\\n internal\\n returns (uint256 addedClaimable)\\n {\\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\\n\\n // Check if the claimable WETH is less than the queued amount\\n uint256 queueShortfall = queue.queued - queue.claimable;\\n\\n // No need to get WETH balance if all the withdrawal requests are claimable\\n if (queueShortfall > 0) {\\n uint256 wethBalance = IERC20(weth).balanceOf(address(this));\\n\\n // Of the claimable withdrawal requests, how much is unclaimed?\\n uint256 unclaimed = queue.claimable - queue.claimed;\\n if (wethBalance > unclaimed) {\\n uint256 unallocatedWeth = wethBalance - unclaimed;\\n\\n // the new claimable amount is the smaller of the queue shortfall or unallocated weth\\n addedClaimable = queueShortfall < unallocatedWeth\\n ? queueShortfall\\n : unallocatedWeth;\\n uint256 newClaimable = queue.claimable + addedClaimable;\\n\\n // Store the new claimable amount back to storage\\n withdrawalQueueMetadata.claimable = uint128(newClaimable);\\n\\n // emit a WithdrawalClaimable event\\n emit WithdrawalClaimable(newClaimable, addedClaimable);\\n }\\n }\\n }\\n\\n /***************************************\\n View Functions\\n ****************************************/\\n\\n function _wethAvailable() internal view returns (uint256 wethAvailable) {\\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\\n\\n // Check if the claimable WETH is less than the queued amount\\n uint256 queueShortfall = queue.queued - queue.claimable;\\n uint256 wethBalance = IERC20(weth).balanceOf(address(this));\\n // Of the claimable withdrawal requests, how much is unclaimed?\\n uint256 unclaimed = queue.claimable - queue.claimed;\\n\\n if (wethBalance > queueShortfall + unclaimed) {\\n wethAvailable = wethBalance - queueShortfall - unclaimed;\\n }\\n }\\n\\n function _checkBalance(address _asset)\\n internal\\n view\\n override\\n returns (uint256 balance)\\n {\\n balance = super._checkBalance(_asset);\\n\\n if (_asset == weth) {\\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\\n // Need to remove WETH that is reserved for the withdrawal queue\\n return balance + queue.claimed - queue.queued;\\n }\\n }\\n\\n function _allocate() internal override {\\n // Add any unallocated WETH to the withdrawal queue first\\n _addWithdrawalQueueLiquidity();\\n\\n super._allocate();\\n }\\n\\n function _totalValue() internal view override returns (uint256 value) {\\n value = super._totalValue();\\n\\n // Need to remove WETH that is reserved for the withdrawal queue.\\n // reserved for the withdrawal queue = cumulative queued total - total claimed\\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\\n value = value + queue.claimed - queue.queued;\\n }\\n}\\n\",\"keccak256\":\"0xe42502bef951bd6f7121f729c03399ec8af2e6c678007974552fe13f65ce4d1d\",\"license\":\"MIT\"},\"contracts/vault/VaultCore.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OToken VaultCore contract\\n * @notice The Vault contract stores assets. On a deposit, OTokens will be minted\\n and sent to the depositor. On a withdrawal, OTokens will be burned and\\n assets will be sent to the withdrawer. The Vault accepts deposits of\\n interest from yield bearing strategies which will modify the supply\\n of OTokens.\\n * @author Origin Protocol Inc\\n */\\n\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\nimport { StableMath } from \\\"../utils/StableMath.sol\\\";\\nimport { IOracle } from \\\"../interfaces/IOracle.sol\\\";\\nimport { IGetExchangeRateToken } from \\\"../interfaces/IGetExchangeRateToken.sol\\\";\\nimport { IDripper } from \\\"../interfaces/IDripper.sol\\\";\\n\\nimport \\\"./VaultInitializer.sol\\\";\\n\\ncontract VaultCore is VaultInitializer {\\n using SafeERC20 for IERC20;\\n using StableMath for uint256;\\n // max signed int\\n uint256 internal constant MAX_INT = 2**255 - 1;\\n // max un-signed int\\n uint256 internal constant MAX_UINT =\\n 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;\\n\\n /**\\n * @dev Verifies that the rebasing is not paused.\\n */\\n modifier whenNotRebasePaused() {\\n require(!rebasePaused, \\\"Rebasing paused\\\");\\n _;\\n }\\n\\n /**\\n * @dev Verifies that the deposits are not paused.\\n */\\n modifier whenNotCapitalPaused() {\\n require(!capitalPaused, \\\"Capital paused\\\");\\n _;\\n }\\n\\n modifier onlyOusdMetaStrategy() {\\n require(\\n msg.sender == ousdMetaStrategy,\\n \\\"Caller is not the OUSD meta strategy\\\"\\n );\\n _;\\n }\\n\\n /**\\n * @notice Deposit a supported asset and mint OTokens.\\n * @param _asset Address of the asset being deposited\\n * @param _amount Amount of the asset being deposited\\n * @param _minimumOusdAmount Minimum OTokens to mint\\n */\\n function mint(\\n address _asset,\\n uint256 _amount,\\n uint256 _minimumOusdAmount\\n ) external whenNotCapitalPaused nonReentrant {\\n _mint(_asset, _amount, _minimumOusdAmount);\\n }\\n\\n function _mint(\\n address _asset,\\n uint256 _amount,\\n uint256 _minimumOusdAmount\\n ) internal virtual {\\n require(assets[_asset].isSupported, \\\"Asset is not supported\\\");\\n require(_amount > 0, \\\"Amount must be greater than 0\\\");\\n\\n uint256 units = _toUnits(_amount, _asset);\\n uint256 unitPrice = _toUnitPrice(_asset, true);\\n uint256 priceAdjustedDeposit = (units * unitPrice) / 1e18;\\n\\n if (_minimumOusdAmount > 0) {\\n require(\\n priceAdjustedDeposit >= _minimumOusdAmount,\\n \\\"Mint amount lower than minimum\\\"\\n );\\n }\\n\\n emit Mint(msg.sender, priceAdjustedDeposit);\\n\\n // Rebase must happen before any transfers occur.\\n if (priceAdjustedDeposit >= rebaseThreshold && !rebasePaused) {\\n if (dripper != address(0)) {\\n // Stream any harvested rewards that are available\\n IDripper(dripper).collect();\\n }\\n _rebase();\\n }\\n\\n // Mint matching amount of OTokens\\n oUSD.mint(msg.sender, priceAdjustedDeposit);\\n\\n // Transfer the deposited coins to the vault\\n IERC20 asset = IERC20(_asset);\\n asset.safeTransferFrom(msg.sender, address(this), _amount);\\n\\n if (priceAdjustedDeposit >= autoAllocateThreshold) {\\n _allocate();\\n }\\n }\\n\\n /**\\n * @notice Mint OTokens for a Metapool Strategy\\n * @param _amount Amount of the asset being deposited\\n *\\n * Notice: can't use `nonReentrant` modifier since the `mint` function can\\n * call `allocate`, and that can trigger `ConvexOUSDMetaStrategy` to call this function\\n * while the execution of the `mint` has not yet completed -> causing a `nonReentrant` collision.\\n *\\n * Also important to understand is that this is a limitation imposed by the test suite.\\n * Production / mainnet contracts should never be configured in a way where mint/redeem functions\\n * that are moving funds between the Vault and end user wallets can influence strategies\\n * utilizing this function.\\n */\\n function mintForStrategy(uint256 _amount)\\n external\\n whenNotCapitalPaused\\n onlyOusdMetaStrategy\\n {\\n require(_amount < MAX_INT, \\\"Amount too high\\\");\\n\\n emit Mint(msg.sender, _amount);\\n\\n // safe to cast because of the require check at the beginning of the function\\n netOusdMintedForStrategy += int256(_amount);\\n\\n require(\\n abs(netOusdMintedForStrategy) < netOusdMintForStrategyThreshold,\\n \\\"Minted ousd surpassed netOusdMintForStrategyThreshold.\\\"\\n );\\n\\n // Mint matching amount of OTokens\\n oUSD.mint(msg.sender, _amount);\\n }\\n\\n // In memoriam\\n\\n /**\\n * @notice Withdraw a supported asset and burn OTokens.\\n * @param _amount Amount of OTokens to burn\\n * @param _minimumUnitAmount Minimum stablecoin units to receive in return\\n */\\n function redeem(uint256 _amount, uint256 _minimumUnitAmount)\\n external\\n whenNotCapitalPaused\\n nonReentrant\\n {\\n _redeem(_amount, _minimumUnitAmount);\\n }\\n\\n /**\\n * @notice Withdraw a supported asset and burn OTokens.\\n * @param _amount Amount of OTokens to burn\\n * @param _minimumUnitAmount Minimum stablecoin units to receive in return\\n */\\n function _redeem(uint256 _amount, uint256 _minimumUnitAmount)\\n internal\\n virtual\\n {\\n // Calculate redemption outputs\\n uint256[] memory outputs = _calculateRedeemOutputs(_amount);\\n\\n emit Redeem(msg.sender, _amount);\\n\\n // Send outputs\\n uint256 assetCount = allAssets.length;\\n for (uint256 i = 0; i < assetCount; ++i) {\\n if (outputs[i] == 0) continue;\\n\\n address assetAddr = allAssets[i];\\n\\n if (IERC20(assetAddr).balanceOf(address(this)) >= outputs[i]) {\\n // Use Vault funds first if sufficient\\n IERC20(assetAddr).safeTransfer(msg.sender, outputs[i]);\\n } else {\\n address strategyAddr = assetDefaultStrategies[assetAddr];\\n if (strategyAddr != address(0)) {\\n // Nothing in Vault, but something in Strategy, send from there\\n IStrategy strategy = IStrategy(strategyAddr);\\n strategy.withdraw(msg.sender, assetAddr, outputs[i]);\\n } else {\\n // Cant find funds anywhere\\n revert(\\\"Liquidity error\\\");\\n }\\n }\\n }\\n\\n if (_minimumUnitAmount > 0) {\\n uint256 unitTotal = 0;\\n for (uint256 i = 0; i < outputs.length; ++i) {\\n unitTotal += _toUnits(outputs[i], allAssets[i]);\\n }\\n require(\\n unitTotal >= _minimumUnitAmount,\\n \\\"Redeem amount lower than minimum\\\"\\n );\\n }\\n\\n oUSD.burn(msg.sender, _amount);\\n\\n _postRedeem(_amount);\\n }\\n\\n function _postRedeem(uint256 _amount) internal {\\n // Until we can prove that we won't affect the prices of our assets\\n // by withdrawing them, this should be here.\\n // It's possible that a strategy was off on its asset total, perhaps\\n // a reward token sold for more or for less than anticipated.\\n uint256 totalUnits = 0;\\n if (_amount >= rebaseThreshold && !rebasePaused) {\\n totalUnits = _rebase();\\n } else {\\n totalUnits = _totalValue();\\n }\\n\\n // Check that the OTokens are backed by enough assets\\n if (maxSupplyDiff > 0) {\\n // Allow a max difference of maxSupplyDiff% between\\n // backing assets value and OUSD total supply\\n uint256 diff = oUSD.totalSupply().divPrecisely(totalUnits);\\n require(\\n (diff > 1e18 ? diff - 1e18 : 1e18 - diff) <= maxSupplyDiff,\\n \\\"Backing supply liquidity error\\\"\\n );\\n }\\n }\\n\\n /**\\n * @notice Burn OTokens for Metapool Strategy\\n * @param _amount Amount of OUSD to burn\\n *\\n * @dev Notice: can't use `nonReentrant` modifier since the `redeem` function could\\n * require withdrawal on `ConvexOUSDMetaStrategy` and that one can call `burnForStrategy`\\n * while the execution of the `redeem` has not yet completed -> causing a `nonReentrant` collision.\\n *\\n * Also important to understand is that this is a limitation imposed by the test suite.\\n * Production / mainnet contracts should never be configured in a way where mint/redeem functions\\n * that are moving funds between the Vault and end user wallets can influence strategies\\n * utilizing this function.\\n */\\n function burnForStrategy(uint256 _amount)\\n external\\n whenNotCapitalPaused\\n onlyOusdMetaStrategy\\n {\\n require(_amount < MAX_INT, \\\"Amount too high\\\");\\n\\n emit Redeem(msg.sender, _amount);\\n\\n // safe to cast because of the require check at the beginning of the function\\n netOusdMintedForStrategy -= int256(_amount);\\n\\n require(\\n abs(netOusdMintedForStrategy) < netOusdMintForStrategyThreshold,\\n \\\"Attempting to burn too much OUSD.\\\"\\n );\\n\\n // Burn OTokens\\n oUSD.burn(msg.sender, _amount);\\n }\\n\\n /**\\n * @notice Withdraw a supported asset and burn all OTokens.\\n * @param _minimumUnitAmount Minimum stablecoin units to receive in return\\n */\\n function redeemAll(uint256 _minimumUnitAmount)\\n external\\n whenNotCapitalPaused\\n nonReentrant\\n {\\n _redeem(oUSD.balanceOf(msg.sender), _minimumUnitAmount);\\n }\\n\\n /**\\n * @notice Allocate unallocated funds on Vault to strategies.\\n **/\\n function allocate() external whenNotCapitalPaused nonReentrant {\\n _allocate();\\n }\\n\\n /**\\n * @dev Allocate unallocated funds on Vault to strategies.\\n **/\\n function _allocate() internal virtual {\\n uint256 vaultValue = _totalValueInVault();\\n // Nothing in vault to allocate\\n if (vaultValue == 0) return;\\n uint256 strategiesValue = _totalValueInStrategies();\\n // We have a method that does the same as this, gas optimisation\\n uint256 calculatedTotalValue = vaultValue + strategiesValue;\\n\\n // We want to maintain a buffer on the Vault so calculate a percentage\\n // modifier to multiply each amount being allocated by to enforce the\\n // vault buffer\\n uint256 vaultBufferModifier;\\n if (strategiesValue == 0) {\\n // Nothing in Strategies, allocate 100% minus the vault buffer to\\n // strategies\\n vaultBufferModifier = uint256(1e18) - vaultBuffer;\\n } else {\\n vaultBufferModifier =\\n (vaultBuffer * calculatedTotalValue) /\\n vaultValue;\\n if (1e18 > vaultBufferModifier) {\\n // E.g. 1e18 - (1e17 * 10e18)/5e18 = 8e17\\n // (5e18 * 8e17) / 1e18 = 4e18 allocated from Vault\\n vaultBufferModifier = uint256(1e18) - vaultBufferModifier;\\n } else {\\n // We need to let the buffer fill\\n return;\\n }\\n }\\n if (vaultBufferModifier == 0) return;\\n\\n // Iterate over all assets in the Vault and allocate to the appropriate\\n // strategy\\n uint256 assetCount = allAssets.length;\\n for (uint256 i = 0; i < assetCount; ++i) {\\n IERC20 asset = IERC20(allAssets[i]);\\n uint256 assetBalance = asset.balanceOf(address(this));\\n // No balance, nothing to do here\\n if (assetBalance == 0) continue;\\n\\n // Multiply the balance by the vault buffer modifier and truncate\\n // to the scale of the asset decimals\\n uint256 allocateAmount = assetBalance.mulTruncate(\\n vaultBufferModifier\\n );\\n\\n address depositStrategyAddr = assetDefaultStrategies[\\n address(asset)\\n ];\\n\\n if (depositStrategyAddr != address(0) && allocateAmount > 0) {\\n IStrategy strategy = IStrategy(depositStrategyAddr);\\n // Transfer asset to Strategy and call deposit method to\\n // mint or take required action\\n asset.safeTransfer(address(strategy), allocateAmount);\\n strategy.deposit(address(asset), allocateAmount);\\n emit AssetAllocated(\\n address(asset),\\n depositStrategyAddr,\\n allocateAmount\\n );\\n }\\n }\\n }\\n\\n /**\\n * @notice Calculate the total value of assets held by the Vault and all\\n * strategies and update the supply of OTokens.\\n */\\n function rebase() external virtual nonReentrant {\\n _rebase();\\n }\\n\\n /**\\n * @dev Calculate the total value of assets held by the Vault and all\\n * strategies and update the supply of OTokens, optionally sending a\\n * portion of the yield to the trustee.\\n * @return totalUnits Total balance of Vault in units\\n */\\n function _rebase() internal whenNotRebasePaused returns (uint256) {\\n uint256 ousdSupply = oUSD.totalSupply();\\n uint256 vaultValue = _totalValue();\\n if (ousdSupply == 0) {\\n return vaultValue;\\n }\\n\\n // Yield fee collection\\n address _trusteeAddress = trusteeAddress; // gas savings\\n if (_trusteeAddress != address(0) && (vaultValue > ousdSupply)) {\\n uint256 yield = vaultValue - ousdSupply;\\n uint256 fee = yield.mulTruncateScale(trusteeFeeBps, 1e4);\\n require(yield > fee, \\\"Fee must not be greater than yield\\\");\\n if (fee > 0) {\\n oUSD.mint(_trusteeAddress, fee);\\n }\\n emit YieldDistribution(_trusteeAddress, yield, fee);\\n }\\n\\n // Only rachet OToken supply upwards\\n ousdSupply = oUSD.totalSupply(); // Final check should use latest value\\n if (vaultValue > ousdSupply) {\\n oUSD.changeSupply(vaultValue);\\n }\\n return vaultValue;\\n }\\n\\n /**\\n * @notice Determine the total value of assets held by the vault and its\\n * strategies.\\n * @return value Total value in USD/ETH (1e18)\\n */\\n function totalValue() external view virtual returns (uint256 value) {\\n value = _totalValue();\\n }\\n\\n /**\\n * @dev Internal Calculate the total value of the assets held by the\\n * vault and its strategies.\\n * @return value Total value in USD/ETH (1e18)\\n */\\n function _totalValue() internal view virtual returns (uint256 value) {\\n return _totalValueInVault() + _totalValueInStrategies();\\n }\\n\\n /**\\n * @dev Internal to calculate total value of all assets held in Vault.\\n * @return value Total value in USD/ETH (1e18)\\n */\\n function _totalValueInVault()\\n internal\\n view\\n virtual\\n returns (uint256 value)\\n {\\n uint256 assetCount = allAssets.length;\\n for (uint256 y = 0; y < assetCount; ++y) {\\n address assetAddr = allAssets[y];\\n uint256 balance = IERC20(assetAddr).balanceOf(address(this));\\n if (balance > 0) {\\n value += _toUnits(balance, assetAddr);\\n }\\n }\\n }\\n\\n /**\\n * @dev Internal to calculate total value of all assets held in Strategies.\\n * @return value Total value in USD/ETH (1e18)\\n */\\n function _totalValueInStrategies() internal view returns (uint256 value) {\\n uint256 stratCount = allStrategies.length;\\n for (uint256 i = 0; i < stratCount; ++i) {\\n value = value + _totalValueInStrategy(allStrategies[i]);\\n }\\n }\\n\\n /**\\n * @dev Internal to calculate total value of all assets held by strategy.\\n * @param _strategyAddr Address of the strategy\\n * @return value Total value in USD/ETH (1e18)\\n */\\n function _totalValueInStrategy(address _strategyAddr)\\n internal\\n view\\n returns (uint256 value)\\n {\\n IStrategy strategy = IStrategy(_strategyAddr);\\n uint256 assetCount = allAssets.length;\\n for (uint256 y = 0; y < assetCount; ++y) {\\n address assetAddr = allAssets[y];\\n if (strategy.supportsAsset(assetAddr)) {\\n uint256 balance = strategy.checkBalance(assetAddr);\\n if (balance > 0) {\\n value += _toUnits(balance, assetAddr);\\n }\\n }\\n }\\n }\\n\\n /**\\n * @notice Get the balance of an asset held in Vault and all strategies.\\n * @param _asset Address of asset\\n * @return uint256 Balance of asset in decimals of asset\\n */\\n function checkBalance(address _asset) external view returns (uint256) {\\n return _checkBalance(_asset);\\n }\\n\\n /**\\n * @notice Get the balance of an asset held in Vault and all strategies.\\n * @param _asset Address of asset\\n * @return balance Balance of asset in decimals of asset\\n */\\n function _checkBalance(address _asset)\\n internal\\n view\\n virtual\\n returns (uint256 balance)\\n {\\n IERC20 asset = IERC20(_asset);\\n balance = asset.balanceOf(address(this));\\n uint256 stratCount = allStrategies.length;\\n for (uint256 i = 0; i < stratCount; ++i) {\\n IStrategy strategy = IStrategy(allStrategies[i]);\\n if (strategy.supportsAsset(_asset)) {\\n balance = balance + strategy.checkBalance(_asset);\\n }\\n }\\n }\\n\\n /**\\n * @notice Calculate the outputs for a redeem function, i.e. the mix of\\n * coins that will be returned\\n */\\n function calculateRedeemOutputs(uint256 _amount)\\n external\\n view\\n returns (uint256[] memory)\\n {\\n return _calculateRedeemOutputs(_amount);\\n }\\n\\n /**\\n * @dev Calculate the outputs for a redeem function, i.e. the mix of\\n * coins that will be returned.\\n * @return outputs Array of amounts respective to the supported assets\\n */\\n function _calculateRedeemOutputs(uint256 _amount)\\n internal\\n view\\n virtual\\n returns (uint256[] memory outputs)\\n {\\n // We always give out coins in proportion to how many we have,\\n // Now if all coins were the same value, this math would easy,\\n // just take the percentage of each coin, and multiply by the\\n // value to be given out. But if coins are worth more than $1,\\n // then we would end up handing out too many coins. We need to\\n // adjust by the total value of coins.\\n //\\n // To do this, we total up the value of our coins, by their\\n // percentages. Then divide what we would otherwise give out by\\n // this number.\\n //\\n // Let say we have 100 DAI at $1.06 and 200 USDT at $1.00.\\n // So for every 1 DAI we give out, we'll be handing out 2 USDT\\n // Our total output ratio is: 33% * 1.06 + 66% * 1.00 = 1.02\\n //\\n // So when calculating the output, we take the percentage of\\n // each coin, times the desired output value, divided by the\\n // totalOutputRatio.\\n //\\n // For example, withdrawing: 30 OUSD:\\n // DAI 33% * 30 / 1.02 = 9.80 DAI\\n // USDT = 66 % * 30 / 1.02 = 19.60 USDT\\n //\\n // Checking these numbers:\\n // 9.80 DAI * 1.06 = $10.40\\n // 19.60 USDT * 1.00 = $19.60\\n //\\n // And so the user gets $10.40 + $19.60 = $30 worth of value.\\n\\n uint256 assetCount = allAssets.length;\\n uint256[] memory assetUnits = new uint256[](assetCount);\\n uint256[] memory assetBalances = new uint256[](assetCount);\\n outputs = new uint256[](assetCount);\\n\\n // Calculate redeem fee\\n if (redeemFeeBps > 0) {\\n uint256 redeemFee = _amount.mulTruncateScale(redeemFeeBps, 1e4);\\n _amount = _amount - redeemFee;\\n }\\n\\n // Calculate assets balances and decimals once,\\n // for a large gas savings.\\n uint256 totalUnits = 0;\\n for (uint256 i = 0; i < assetCount; ++i) {\\n address assetAddr = allAssets[i];\\n uint256 balance = _checkBalance(assetAddr);\\n assetBalances[i] = balance;\\n assetUnits[i] = _toUnits(balance, assetAddr);\\n totalUnits = totalUnits + assetUnits[i];\\n }\\n // Calculate totalOutputRatio\\n uint256 totalOutputRatio = 0;\\n for (uint256 i = 0; i < assetCount; ++i) {\\n uint256 unitPrice = _toUnitPrice(allAssets[i], false);\\n uint256 ratio = (assetUnits[i] * unitPrice) / totalUnits;\\n totalOutputRatio = totalOutputRatio + ratio;\\n }\\n // Calculate final outputs\\n uint256 factor = _amount.divPrecisely(totalOutputRatio);\\n for (uint256 i = 0; i < assetCount; ++i) {\\n outputs[i] = (assetBalances[i] * factor) / totalUnits;\\n }\\n }\\n\\n /***************************************\\n Pricing\\n ****************************************/\\n\\n /**\\n * @notice Returns the total price in 18 digit units for a given asset.\\n * Never goes above 1, since that is how we price mints.\\n * @param asset address of the asset\\n * @return price uint256: unit (USD / ETH) price for 1 unit of the asset, in 18 decimal fixed\\n */\\n function priceUnitMint(address asset)\\n external\\n view\\n returns (uint256 price)\\n {\\n /* need to supply 1 asset unit in asset's decimals and can not just hard-code\\n * to 1e18 and ignore calling `_toUnits` since we need to consider assets\\n * with the exchange rate\\n */\\n uint256 units = _toUnits(\\n uint256(1e18).scaleBy(_getDecimals(asset), 18),\\n asset\\n );\\n price = (_toUnitPrice(asset, true) * units) / 1e18;\\n }\\n\\n /**\\n * @notice Returns the total price in 18 digit unit for a given asset.\\n * Never goes below 1, since that is how we price redeems\\n * @param asset Address of the asset\\n * @return price uint256: unit (USD / ETH) price for 1 unit of the asset, in 18 decimal fixed\\n */\\n function priceUnitRedeem(address asset)\\n external\\n view\\n returns (uint256 price)\\n {\\n /* need to supply 1 asset unit in asset's decimals and can not just hard-code\\n * to 1e18 and ignore calling `_toUnits` since we need to consider assets\\n * with the exchange rate\\n */\\n uint256 units = _toUnits(\\n uint256(1e18).scaleBy(_getDecimals(asset), 18),\\n asset\\n );\\n price = (_toUnitPrice(asset, false) * units) / 1e18;\\n }\\n\\n /***************************************\\n Utils\\n ****************************************/\\n\\n /**\\n * @dev Convert a quantity of a token into 1e18 fixed decimal \\\"units\\\"\\n * in the underlying base (USD/ETH) used by the vault.\\n * Price is not taken into account, only quantity.\\n *\\n * Examples of this conversion:\\n *\\n * - 1e18 DAI becomes 1e18 units (same decimals)\\n * - 1e6 USDC becomes 1e18 units (decimal conversion)\\n * - 1e18 rETH becomes 1.2e18 units (exchange rate conversion)\\n *\\n * @param _raw Quantity of asset\\n * @param _asset Core Asset address\\n * @return value 1e18 normalized quantity of units\\n */\\n function _toUnits(uint256 _raw, address _asset)\\n internal\\n view\\n returns (uint256)\\n {\\n UnitConversion conversion = assets[_asset].unitConversion;\\n if (conversion == UnitConversion.DECIMALS) {\\n return _raw.scaleBy(18, _getDecimals(_asset));\\n } else if (conversion == UnitConversion.GETEXCHANGERATE) {\\n uint256 exchangeRate = IGetExchangeRateToken(_asset)\\n .getExchangeRate();\\n return (_raw * exchangeRate) / 1e18;\\n } else {\\n revert(\\\"Unsupported conversion type\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns asset's unit price accounting for different asset types\\n * and takes into account the context in which that price exists -\\n * - mint or redeem.\\n *\\n * Note: since we are returning the price of the unit and not the one of the\\n * asset (see comment above how 1 rETH exchanges for 1.2 units) we need\\n * to make the Oracle price adjustment as well since we are pricing the\\n * units and not the assets.\\n *\\n * The price also snaps to a \\\"full unit price\\\" in case a mint or redeem\\n * action would be unfavourable to the protocol.\\n *\\n */\\n function _toUnitPrice(address _asset, bool isMint)\\n internal\\n view\\n returns (uint256 price)\\n {\\n UnitConversion conversion = assets[_asset].unitConversion;\\n price = IOracle(priceProvider).price(_asset);\\n\\n if (conversion == UnitConversion.GETEXCHANGERATE) {\\n uint256 exchangeRate = IGetExchangeRateToken(_asset)\\n .getExchangeRate();\\n price = (price * 1e18) / exchangeRate;\\n } else if (conversion != UnitConversion.DECIMALS) {\\n revert(\\\"Unsupported conversion type\\\");\\n }\\n\\n /* At this stage the price is already adjusted to the unit\\n * so the price checks are agnostic to underlying asset being\\n * pegged to a USD or to an ETH or having a custom exchange rate.\\n */\\n require(price <= MAX_UNIT_PRICE_DRIFT, \\\"Vault: Price exceeds max\\\");\\n require(price >= MIN_UNIT_PRICE_DRIFT, \\\"Vault: Price under min\\\");\\n\\n if (isMint) {\\n /* Never price a normalized unit price for more than one\\n * unit of OETH/OUSD when minting.\\n */\\n if (price > 1e18) {\\n price = 1e18;\\n }\\n require(price >= MINT_MINIMUM_UNIT_PRICE, \\\"Asset price below peg\\\");\\n } else {\\n /* Never give out more than 1 normalized unit amount of assets\\n * for one unit of OETH/OUSD when redeeming.\\n */\\n if (price < 1e18) {\\n price = 1e18;\\n }\\n }\\n }\\n\\n function _getDecimals(address _asset)\\n internal\\n view\\n returns (uint256 decimals)\\n {\\n decimals = assets[_asset].decimals;\\n require(decimals > 0, \\\"Decimals not cached\\\");\\n }\\n\\n /**\\n * @notice Return the number of assets supported by the Vault.\\n */\\n function getAssetCount() public view returns (uint256) {\\n return allAssets.length;\\n }\\n\\n /**\\n * @notice Gets the vault configuration of a supported asset.\\n */\\n function getAssetConfig(address _asset)\\n public\\n view\\n returns (Asset memory config)\\n {\\n config = assets[_asset];\\n }\\n\\n /**\\n * @notice Return all vault asset addresses in order\\n */\\n function getAllAssets() external view returns (address[] memory) {\\n return allAssets;\\n }\\n\\n /**\\n * @notice Return the number of strategies active on the Vault.\\n */\\n function getStrategyCount() external view returns (uint256) {\\n return allStrategies.length;\\n }\\n\\n /**\\n * @notice Return the array of all strategies\\n */\\n function getAllStrategies() external view returns (address[] memory) {\\n return allStrategies;\\n }\\n\\n /**\\n * @notice Returns whether the vault supports the asset\\n * @param _asset address of the asset\\n * @return true if supported\\n */\\n function isSupportedAsset(address _asset) external view returns (bool) {\\n return assets[_asset].isSupported;\\n }\\n\\n /**\\n * @dev Falldown to the admin implementation\\n * @notice This is a catch all for all functions not declared in core\\n */\\n // solhint-disable-next-line no-complex-fallback\\n fallback() external {\\n bytes32 slot = adminImplPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n // Copy msg.data. We take full control of memory in this inline assembly\\n // block because it will not return to Solidity code. We overwrite the\\n // Solidity scratch pad at memory position 0.\\n calldatacopy(0, 0, calldatasize())\\n\\n // Call the implementation.\\n // out and outsize are 0 because we don't know the size yet.\\n let result := delegatecall(\\n gas(),\\n sload(slot),\\n 0,\\n calldatasize(),\\n 0,\\n 0\\n )\\n\\n // Copy the returned data.\\n returndatacopy(0, 0, returndatasize())\\n\\n switch result\\n // delegatecall returns 0 on error.\\n case 0 {\\n revert(0, returndatasize())\\n }\\n default {\\n return(0, returndatasize())\\n }\\n }\\n }\\n\\n function abs(int256 x) private pure returns (uint256) {\\n require(x < int256(MAX_INT), \\\"Amount too high\\\");\\n return x >= 0 ? uint256(x) : uint256(-x);\\n }\\n}\\n\",\"keccak256\":\"0x53b63416345037aefda0c13b0d7b6480737fe5edc50a23fa7383720808a5399e\",\"license\":\"MIT\"},\"contracts/vault/VaultInitializer.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OToken VaultInitializer contract\\n * @notice The Vault contract initializes the vault.\\n * @author Origin Protocol Inc\\n */\\n\\nimport \\\"./VaultStorage.sol\\\";\\n\\ncontract VaultInitializer is VaultStorage {\\n function initialize(address _priceProvider, address _oToken)\\n external\\n onlyGovernor\\n initializer\\n {\\n require(_priceProvider != address(0), \\\"PriceProvider address is zero\\\");\\n require(_oToken != address(0), \\\"oToken address is zero\\\");\\n\\n oUSD = OUSD(_oToken);\\n\\n priceProvider = _priceProvider;\\n\\n rebasePaused = false;\\n capitalPaused = true;\\n\\n // Initial redeem fee of 0 basis points\\n redeemFeeBps = 0;\\n // Initial Vault buffer of 0%\\n vaultBuffer = 0;\\n // Initial allocate threshold of 25,000 OUSD\\n autoAllocateThreshold = 25000e18;\\n // Threshold for rebasing\\n rebaseThreshold = 1000e18;\\n // Initialize all strategies\\n allStrategies = new address[](0);\\n }\\n}\\n\",\"keccak256\":\"0x5b9676307bbabe14b5278f00ec7edc557b84debbfa1391902d78100cb9cd467e\",\"license\":\"MIT\"},\"contracts/vault/VaultStorage.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OToken VaultStorage contract\\n * @notice The VaultStorage contract defines the storage for the Vault contracts\\n * @author Origin Protocol Inc\\n */\\n\\nimport { IERC20 } from \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport { Address } from \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport { IStrategy } from \\\"../interfaces/IStrategy.sol\\\";\\nimport { Governable } from \\\"../governance/Governable.sol\\\";\\nimport { OUSD } from \\\"../token/OUSD.sol\\\";\\nimport { Initializable } from \\\"../utils/Initializable.sol\\\";\\nimport \\\"../utils/Helpers.sol\\\";\\n\\ncontract VaultStorage is Initializable, Governable {\\n using SafeERC20 for IERC20;\\n\\n event AssetSupported(address _asset);\\n event AssetRemoved(address _asset);\\n event AssetDefaultStrategyUpdated(address _asset, address _strategy);\\n event AssetAllocated(address _asset, address _strategy, uint256 _amount);\\n event StrategyApproved(address _addr);\\n event StrategyRemoved(address _addr);\\n event Mint(address _addr, uint256 _value);\\n event Redeem(address _addr, uint256 _value);\\n event CapitalPaused();\\n event CapitalUnpaused();\\n event RebasePaused();\\n event RebaseUnpaused();\\n event VaultBufferUpdated(uint256 _vaultBuffer);\\n event OusdMetaStrategyUpdated(address _ousdMetaStrategy);\\n event RedeemFeeUpdated(uint256 _redeemFeeBps);\\n event PriceProviderUpdated(address _priceProvider);\\n event AllocateThresholdUpdated(uint256 _threshold);\\n event RebaseThresholdUpdated(uint256 _threshold);\\n event StrategistUpdated(address _address);\\n event MaxSupplyDiffChanged(uint256 maxSupplyDiff);\\n event YieldDistribution(address _to, uint256 _yield, uint256 _fee);\\n event TrusteeFeeBpsChanged(uint256 _basis);\\n event TrusteeAddressChanged(address _address);\\n event NetOusdMintForStrategyThresholdChanged(uint256 _threshold);\\n event SwapperChanged(address _address);\\n event SwapAllowedUndervalueChanged(uint256 _basis);\\n event SwapSlippageChanged(address _asset, uint256 _basis);\\n event Swapped(\\n address indexed _fromAsset,\\n address indexed _toAsset,\\n uint256 _fromAssetAmount,\\n uint256 _toAssetAmount\\n );\\n event DripperChanged(address indexed _dripper);\\n event WithdrawalRequested(\\n address indexed _withdrawer,\\n uint256 indexed _requestId,\\n uint256 _amount,\\n uint256 _queued\\n );\\n event WithdrawalClaimed(\\n address indexed _withdrawer,\\n uint256 indexed _requestId,\\n uint256 _amount\\n );\\n event WithdrawalClaimable(uint256 _claimable, uint256 _newClaimable);\\n\\n // Assets supported by the Vault, i.e. Stablecoins\\n enum UnitConversion {\\n DECIMALS,\\n GETEXCHANGERATE\\n }\\n // Changed to fit into a single storage slot so the decimals needs to be recached\\n struct Asset {\\n // Note: OETHVaultCore doesn't use `isSupported` when minting,\\n // redeeming or checking balance of assets.\\n bool isSupported;\\n UnitConversion unitConversion;\\n uint8 decimals;\\n // Max allowed slippage from the Oracle price when swapping collateral assets in basis points.\\n // For example 40 == 0.4% slippage\\n uint16 allowedOracleSlippageBps;\\n }\\n\\n /// @dev mapping of supported vault assets to their configuration\\n // slither-disable-next-line uninitialized-state\\n mapping(address => Asset) internal assets;\\n /// @dev list of all assets supported by the vault.\\n // slither-disable-next-line uninitialized-state\\n address[] internal allAssets;\\n\\n // Strategies approved for use by the Vault\\n struct Strategy {\\n bool isSupported;\\n uint256 _deprecated; // Deprecated storage slot\\n }\\n /// @dev mapping of strategy contracts to their configuration\\n mapping(address => Strategy) internal strategies;\\n /// @dev list of all vault strategies\\n address[] internal allStrategies;\\n\\n /// @notice Address of the Oracle price provider contract\\n // slither-disable-next-line uninitialized-state\\n address public priceProvider;\\n /// @notice pause rebasing if true\\n bool public rebasePaused = false;\\n /// @notice pause operations that change the OToken supply.\\n /// eg mint, redeem, allocate, mint/burn for strategy\\n bool public capitalPaused = true;\\n /// @notice Redemption fee in basis points. eg 50 = 0.5%\\n uint256 public redeemFeeBps;\\n /// @notice Percentage of assets to keep in Vault to handle (most) withdrawals. 100% = 1e18.\\n uint256 public vaultBuffer;\\n /// @notice OToken mints over this amount automatically allocate funds. 18 decimals.\\n uint256 public autoAllocateThreshold;\\n /// @notice OToken mints over this amount automatically rebase. 18 decimals.\\n uint256 public rebaseThreshold;\\n\\n /// @dev Address of the OToken token. eg OUSD or OETH.\\n // slither-disable-next-line uninitialized-state\\n OUSD internal oUSD;\\n\\n //keccak256(\\\"OUSD.vault.governor.admin.impl\\\");\\n bytes32 constant adminImplPosition =\\n 0xa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd9;\\n\\n // Address of the contract responsible for post rebase syncs with AMMs\\n address private _deprecated_rebaseHooksAddr = address(0);\\n\\n // Deprecated: Address of Uniswap\\n // slither-disable-next-line constable-states\\n address private _deprecated_uniswapAddr = address(0);\\n\\n /// @notice Address of the Strategist\\n address public strategistAddr = address(0);\\n\\n /// @notice Mapping of asset address to the Strategy that they should automatically\\n // be allocated to\\n // slither-disable-next-line uninitialized-state\\n mapping(address => address) public assetDefaultStrategies;\\n\\n /// @notice Max difference between total supply and total value of assets. 18 decimals.\\n // slither-disable-next-line uninitialized-state\\n uint256 public maxSupplyDiff;\\n\\n /// @notice Trustee contract that can collect a percentage of yield\\n address public trusteeAddress;\\n\\n /// @notice Amount of yield collected in basis points. eg 2000 = 20%\\n uint256 public trusteeFeeBps;\\n\\n /// @dev Deprecated: Tokens that should be swapped for stablecoins\\n address[] private _deprecated_swapTokens;\\n\\n uint256 constant MINT_MINIMUM_UNIT_PRICE = 0.998e18;\\n\\n /// @notice Metapool strategy that is allowed to mint/burn OTokens without changing collateral\\n address public ousdMetaStrategy = address(0);\\n\\n /// @notice How much OTokens are currently minted by the strategy\\n int256 public netOusdMintedForStrategy = 0;\\n\\n /// @notice How much net total OTokens are allowed to be minted by all strategies\\n uint256 public netOusdMintForStrategyThreshold = 0;\\n\\n uint256 constant MIN_UNIT_PRICE_DRIFT = 0.7e18;\\n uint256 constant MAX_UNIT_PRICE_DRIFT = 1.3e18;\\n\\n /// @notice Collateral swap configuration.\\n /// @dev is packed into a single storage slot to save gas.\\n struct SwapConfig {\\n // Contract that swaps the vault's collateral assets\\n address swapper;\\n // Max allowed percentage the total value can drop below the total supply in basis points.\\n // For example 100 == 1%\\n uint16 allowedUndervalueBps;\\n }\\n SwapConfig internal swapConfig = SwapConfig(address(0), 0);\\n\\n /// @notice Address of the Dripper contract that streams harvested rewards to the Vault\\n /// @dev The vault is proxied so needs to be set with setDripper against the proxy contract.\\n // slither-disable-start constable-states\\n // slither-disable-next-line uninitialized-state\\n address public dripper;\\n // slither-disable-end constable-states\\n\\n /// Withdrawal Queue Storage /////\\n\\n struct WithdrawalQueueMetadata {\\n // cumulative total of all withdrawal requests included the ones that have already been claimed\\n uint128 queued;\\n // cumulative total of all the requests that can be claimed included the ones that have already been claimed\\n uint128 claimable;\\n // total of all the requests that have been claimed\\n uint128 claimed;\\n // index of the next withdrawal request starting at 0\\n uint128 nextWithdrawalIndex;\\n }\\n\\n // slither-disable-next-line uninitialized-state\\n WithdrawalQueueMetadata public withdrawalQueueMetadata;\\n\\n struct WithdrawalRequest {\\n address withdrawer;\\n bool claimed;\\n // Amount of oTokens to redeem\\n uint128 amount;\\n // cumulative total of all withdrawal requests including this one.\\n // this request can be claimed when this queued amount is less than or equal to the queue's claimable amount.\\n uint128 queued;\\n }\\n\\n // Mapping of withdrawal requests indexes to the user withdrawal request data\\n mapping(uint256 => WithdrawalRequest) public withdrawalRequests;\\n\\n // For future use\\n uint256[46] private __gap;\\n\\n /**\\n * @notice set the implementation for the admin, this needs to be in a base class else we cannot set it\\n * @param newImpl address of the implementation\\n */\\n function setAdminImpl(address newImpl) external onlyGovernor {\\n require(\\n Address.isContract(newImpl),\\n \\\"new implementation is not a contract\\\"\\n );\\n bytes32 position = adminImplPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, newImpl)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xe13565f58d63805320aa4aac336b294fa6b6e55b028a6727510bf99764ebce14\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x6037805461ffff60a01b1916600160a81b179055603d80546001600160a01b0319908116909155603e805482169055603f80548216905560458054909116905560006046819055604781905560e060405260a081905260c052604880546001600160b01b03191690553480156200007557600080fd5b50604051620045363803806200453683398101604081905262000098916200010e565b620000b0336000805160206200451683398151915255565b60008051602062004516833981519152546040516001600160a01b03909116906000907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a360601b6001600160601b03191660805262000140565b6000602082840312156200012157600080fd5b81516001600160a01b03811681146200013957600080fd5b9392505050565b60805160601c614363620001b36000396000818161040b015281816108e10152818161095401528181610d350152818161183a0152818161190f0152818161249d015281816125a701528181612785015281816127bb0152818161280f01528181612cf3015261324801526143636000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806367bd7ba311610182578063ab80dafb116100e9578063c7af3352116100a2578063e45cc9f01161007c578063e45cc9f014610712578063e6cc54321461071b578063f84444361461072f578063fc0cfeee14610742576102bb565b8063c7af3352146106ef578063d38bfff4146106f7578063d4c3eea01461070a576102bb565b8063ab80dafb146106a9578063abaa9916146106bc578063af14052c146106c4578063b888879e146106cc578063b9b17f9f146106df578063c3b28864146106e7576102bb565b8063937b25811161013b578063937b2581146105915780639be918e61461061b5780639ee679e8146106475780639fa1826e1461066f578063a0aead4d14610678578063a403e4d514610680576102bb565b806367bd7ba3146105195780636ec3ab67146105395780637136a7a6146105595780637a2202f31461056c5780637cbc2373146105755780638e510b5214610588576102bb565b8063485cc95511610226578063570d8e1d116101df578063570d8e1d146104b25780635b60f9fc146104c55780635d36b190146104d85780635f515226146104e0578063603ea03b146104f35780636217f3ea14610506576102bb565b8063485cc9551461043557806348e30f541461044857806349c1d54d1461046957806352d38e5d1461047c57806353ca9f241461048557806354c6d858146104a9576102bb565b80632acada4d116102785780632acada4d1461037757806331e19cfa1461038c578063362bd1a3146103945780633b8fe28d146103f35780633fc8cef31461040657806344c547071461042d576102bb565b806309f6442c146103015780630c340a241461031d578063156e29f61461033d57806318ce56bd146103525780631edfe3da14610365578063207134b01461036e575b7fa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd9366000803760008036600084545af43d6000803e8080156102fc573d6000f35b3d6000fd5b61030a60385481565b6040519081526020015b60405180910390f35b610325610755565b6040516001600160a01b039091168152602001610314565b61035061034b366004613c26565b610772565b005b604554610325906001600160a01b031681565b61030a60395481565b61030a60435481565b61037f6107f0565b6040516103149190613e04565b60365461030a565b604a54604b546103c0916001600160801b0380821692600160801b928390048216928183169291041684565b604080516001600160801b0395861681529385166020850152918416918301919091529091166060820152608001610314565b61030a610401366004613bd8565b610852565b6103257f000000000000000000000000000000000000000000000000000000000000000081565b6103506108ad565b610350610443366004613bf3565b6109f6565b61045b610456366004613c59565b610bf8565b604051610314929190613e64565b604254610325906001600160a01b031681565b61030a603b5481565b60375461049990600160a01b900460ff1681565b6040519015158152602001610314565b61030a607b5481565b603f54610325906001600160a01b031681565b61030a6104d3366004613bd8565b610d67565b610350610d90565b61030a6104ee366004613bd8565b610e36565b604954610325906001600160a01b031681565b610350610514366004613d40565b610e47565b61052c610527366004613d40565b610fde565b6040516103149190613e51565b61054c610547366004613bd8565b610fe9565b6040516103149190613fad565b610350610567366004613d40565b61108f565b61030a60475481565b610350610583366004613d72565b61117a565b61030a60415481565b6105e261059f366004613d40565b604c60205260009081526040902080546001909101546001600160a01b03821691600160a01b900460ff16906001600160801b0380821691600160801b90041684565b604080516001600160a01b03909516855292151560208501526001600160801b0391821692840192909252166060820152608001610314565b610499610629366004613bd8565b6001600160a01b031660009081526033602052604090205460ff1690565b61065a610655366004613d40565b6111ed565b60408051928352602083019190915201610314565b61030a603a5481565b60345461030a565b61032561068e366004613bd8565b6040602081905260009182529020546001600160a01b031681565b6103506106b7366004613d40565b6113e4565b61035061155b565b6103506115ca565b603754610325906001600160a01b031681565b610350611610565b61037f611680565b6104996116e0565b610350610705366004613bd8565b611711565b61030a6117b5565b61030a60465481565b60375461049990600160a81b900460ff1681565b61030a61073d366004613d40565b6117bf565b610350610750366004613bd8565b61186b565b600061076d60008051602061430e8339815191525490565b905090565b603754600160a81b900460ff16156107a55760405162461bcd60e51b815260040161079c90613f5d565b60405180910390fd5b6000805160206142ee833981519152805460028114156107d75760405162461bcd60e51b815260040161079c90613f85565b600282556107e685858561190d565b5060019055505050565b6060603480548060200260200160405190810160405280929190818152602001828054801561084857602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161082a575b5050505050905090565b60008061087b61087561086485611b8e565b670de0b6b3a7640000906012611bf8565b84611c5a565b9050670de0b6b3a764000081610892856001611db6565b61089c9190614194565b6108a69190614087565b9392505050565b6108b56116e0565b6108d15760405162461bcd60e51b815260040161079c90613efd565b60345460005b81811015610951577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166034828154811061091c5761091c6142c1565b6000918252602090912001546001600160a01b0316141561094157607b819055610951565b61094a8161425d565b90506108d7565b507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166034607b5481548110610991576109916142c1565b6000918252602090912001546001600160a01b0316146109f35760405162461bcd60e51b815260206004820152601860248201527f496e76616c6964205745544820417373657420496e6465780000000000000000604482015260640161079c565b50565b6109fe6116e0565b610a1a5760405162461bcd60e51b815260040161079c90613efd565b600054610100900460ff1680610a33575060005460ff16155b610a965760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161079c565b600054610100900460ff16158015610ab8576000805461ffff19166101011790555b6001600160a01b038316610b0e5760405162461bcd60e51b815260206004820152601d60248201527f507269636550726f76696465722061646472657373206973207a65726f000000604482015260640161079c565b6001600160a01b038216610b5d5760405162461bcd60e51b81526020600482015260166024820152756f546f6b656e2061646472657373206973207a65726f60501b604482015260640161079c565b603c80546001600160a01b038481166001600160a01b031990921691909117909155603780546001600160b01b03191691851691909117600160a81b17905560006038819055603981905569054b40b1f852bda00000603a55683635c9adc5dea00000603b556040805191825260208201908190529051610be091603691613b50565b508015610bf3576000805461ff00191690555b505050565b603754606090600090600160a81b900460ff1615610c285760405162461bcd60e51b815260040161079c90613f5d565b6000805160206142ee83398151915280546002811415610c5a5760405162461bcd60e51b815260040161079c90613f85565b60028255845167ffffffffffffffff811115610c7857610c786142d7565b604051908082528060200260200182016040528015610ca1578160200160208202803683370190505b50935060005b8551811015610d2757610cd2868281518110610cc557610cc56142c1565b60200260200101516120a8565b858281518110610ce457610ce46142c1565b602002602001018181525050848181518110610d0257610d026142c1565b602002602001015184610d15919061406f565b9350610d208161425d565b9050610ca7565b50610d5c6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163385612377565b600182555050915091565b600080610d7961087561086485611b8e565b9050670de0b6b3a764000081610892856000611db6565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614610e2b5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b606482015260840161079c565b610e34336123cd565b565b6000610e418261248e565b92915050565b603754600160a81b900460ff1615610e715760405162461bcd60e51b815260040161079c90613f5d565b6045546001600160a01b03163314610e9b5760405162461bcd60e51b815260040161079c90613eb9565b6001600160ff1b038110610ec15760405162461bcd60e51b815260040161079c90613f34565b7f222838db2794d11532d940e8dec38ae307ed0b63cd97c233322e221f998767a63382604051610ef2929190613deb565b60405180910390a18060466000828254610f0c91906141b3565b9091555050604754604654610f209061252c565b10610f775760405162461bcd60e51b815260206004820152602160248201527f417474656d7074696e6720746f206275726e20746f6f206d756368204f5553446044820152601760f91b606482015260840161079c565b603c54604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac90610fa99033908590600401613deb565b600060405180830381600087803b158015610fc357600080fd5b505af1158015610fd7573d6000803e3d6000fd5b5050505050565b6060610e418261256f565b604080516080808201835260008083526020808401829052838501829052606084018290526001600160a01b038616825260338152908490208451928301909452835460ff808216151584529394929391840191610100909104166001811115611055576110556142ab565b6001811115611066576110666142ab565b8152905462010000810460ff1660208301526301000000900461ffff1660409091015292915050565b603754600160a81b900460ff16156110b95760405162461bcd60e51b815260040161079c90613f5d565b6000805160206142ee833981519152805460028114156110eb5760405162461bcd60e51b815260040161079c90613f85565b60028255603c546040516370a0823160e01b8152336004820152611172916001600160a01b0316906370a082319060240160206040518083038186803b15801561113457600080fd5b505afa158015611148573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061116c9190613d59565b846126b0565b506001905550565b603754600160a81b900460ff16156111a45760405162461bcd60e51b815260040161079c90613f5d565b6000805160206142ee833981519152805460028114156111d65760405162461bcd60e51b815260040161079c90613f85565b600282556111e484846126b0565b50600190555050565b6037546000908190600160a81b900460ff161561121c5760405162461bcd60e51b815260040161079c90613f5d565b6000805160206142ee8339815191528054600281141561124e5760405162461bcd60e51b815260040161079c90613f85565b60028255603c54604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac906112849033908990600401613deb565b600060405180830381600087803b15801561129e57600080fd5b505af11580156112b2573d6000803e3d6000fd5b5050604b54604a546001600160801b03600160801b909204821697506112dc93508892501661406f565b92506112e984600161406f565b604b80546001600160801b03928316600160801b02908316179055604a80549185166001600160801b03199092169190911790556040805186815260208101859052859133917f38e3d972947cfef94205163d483d6287ef27eb312e20cb8e0b13a49989db232e910160405180910390a35060408051608081018252338152600060208083018281526001600160801b03988916848601908152878a1660608601908152898552604c909352949092209251835492511515600160a01b026001600160a81b03199093166001600160a01b039190911617919091178255915191518616600160801b0291909516176001948501559290925591565b603754600160a81b900460ff161561140e5760405162461bcd60e51b815260040161079c90613f5d565b6045546001600160a01b031633146114385760405162461bcd60e51b815260040161079c90613eb9565b6001600160ff1b03811061145e5760405162461bcd60e51b815260040161079c90613f34565b7f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d4121396885338260405161148f929190613deb565b60405180910390a180604660008282546114a99190614003565b90915550506047546046546114bd9061252c565b106115295760405162461bcd60e51b815260206004820152603660248201527f4d696e746564206f75736420737572706173736564206e65744f7573644d696e6044820152753a2337b929ba3930ba32b3bcaa343932b9b437b6321760511b606482015260840161079c565b603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990610fa99033908590600401613deb565b603754600160a81b900460ff16156115855760405162461bcd60e51b815260040161079c90613f5d565b6000805160206142ee833981519152805460028114156115b75760405162461bcd60e51b815260040161079c90613f85565b600282556115c361292c565b5060019055565b6000805160206142ee833981519152805460028114156115fc5760405162461bcd60e51b815260040161079c90613f85565b6002825561160861293d565b505060019055565b604960009054906101000a90046001600160a01b03166001600160a01b031663e52253816040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561166057600080fd5b505af1158015611674573d6000803e3d6000fd5b505050506109f3612c78565b60606036805480602002602001604051908101604052809291908181526020018280548015610848576020028201919060005260206000209081546001600160a01b0316815260019091019060200180831161082a575050505050905090565b60006116f860008051602061430e8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b6117196116e0565b6117355760405162461bcd60e51b815260040161079c90613efd565b61175d817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b031661177d60008051602061430e8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b600061076d612e45565b603754600090600160a81b900460ff16156117ec5760405162461bcd60e51b815260040161079c90613f5d565b6000805160206142ee8339815191528054600281141561181e5760405162461bcd60e51b815260040161079c90613f85565b6002825561182b846120a8565b92506118616001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163385612377565b5060019055919050565b6118736116e0565b61188f5760405162461bcd60e51b815260040161079c90613efd565b803b6118e95760405162461bcd60e51b8152602060048201526024808201527f6e657720696d706c656d656e746174696f6e206973206e6f74206120636f6e746044820152631c9858dd60e21b606482015260840161079c565b7fa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd955565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b03161461198e5760405162461bcd60e51b815260206004820152601d60248201527f556e737570706f7274656420617373657420666f72206d696e74696e67000000604482015260640161079c565b600082116119de5760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e2030000000604482015260640161079c565b80821015611a2e5760405162461bcd60e51b815260206004820152601e60248201527f4d696e7420616d6f756e74206c6f776572207468616e206d696e696d756d0000604482015260640161079c565b7f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d41213968853383604051611a5f929190613deb565b60405180910390a1603754600160a01b900460ff16158015611a835750603b548210155b15611afa57604960009054906101000a90046001600160a01b03166001600160a01b031663e52253816040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611ad857600080fd5b505af1158015611aec573d6000803e3d6000fd5b50505050611af861293d565b505b603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990611b2c9033908690600401613deb565b600060405180830381600087803b158015611b4657600080fd5b505af1158015611b5a573d6000803e3d6000fd5b50611b74925050506001600160a01b038416333085612eaf565b611b7c612c78565b50603a548210610bf357610bf361292c565b6001600160a01b03811660009081526033602052604090205462010000900460ff1680611bf35760405162461bcd60e51b8152602060048201526013602482015272111958da5b585b1cc81b9bdd0818d858da1959606a1b604482015260640161079c565b919050565b600081831115611c2857611c21611c0f838561421a565b611c1a90600a6140ec565b8590612eed565b9350611c52565b81831015611c5257611c4f611c3d848461421a565b611c4890600a6140ec565b8590612ef9565b93505b509192915050565b6001600160a01b038116600090815260336020526040812054610100900460ff1681816001811115611c8e57611c8e6142ab565b1415611cb257611caa6012611ca285611b8e565b869190611bf8565b915050610e41565b6001816001811115611cc657611cc66142ab565b1415611d67576000836001600160a01b031663e6aa216c6040518163ffffffff1660e01b815260040160206040518083038186803b158015611d0757600080fd5b505afa158015611d1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d3f9190613d59565b9050670de0b6b3a7640000611d548287614194565b611d5e9190614087565b92505050610e41565b60405162461bcd60e51b815260206004820152601b60248201527f556e737570706f7274656420636f6e76657273696f6e20747970650000000000604482015260640161079c565b5092915050565b6001600160a01b038281166000818152603360205260408082205460375491516315d5220f60e31b81526004810194909452919361010090920460ff169291169063aea910789060240160206040518083038186803b158015611e1857600080fd5b505afa158015611e2c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e509190613d59565b91506001816001811115611e6657611e666142ab565b1415611f06576000846001600160a01b031663e6aa216c6040518163ffffffff1660e01b815260040160206040518083038186803b158015611ea757600080fd5b505afa158015611ebb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611edf9190613d59565b905080611ef484670de0b6b3a7640000614194565b611efe9190614087565b925050611f67565b6000816001811115611f1a57611f1a6142ab565b14611f675760405162461bcd60e51b815260206004820152601b60248201527f556e737570706f7274656420636f6e76657273696f6e20747970650000000000604482015260640161079c565b67120a871cc0020000821115611fbf5760405162461bcd60e51b815260206004820152601860248201527f5661756c743a2050726963652065786365656473206d61780000000000000000604482015260640161079c565b6709b6e64a8ec600008210156120105760405162461bcd60e51b81526020600482015260166024820152752b30bab63a1d10283934b1b2903ab73232b91036b4b760511b604482015260640161079c565b821561208757670de0b6b3a764000082111561203257670de0b6b3a764000091505b670dd99bb65dd700008210156120825760405162461bcd60e51b815260206004820152601560248201527441737365742070726963652062656c6f772070656760581b604482015260640161079c565b611daf565b670de0b6b3a7640000821015611daf5750670de0b6b3a76400009392505050565b6040805160808082018352604a546001600160801b038082168452600160801b918290048116602080860191909152604b548083168688015283900482166060808701919091526000888152604c83528781208851968701895280546001600160a01b0381168852600160a01b900460ff1615801594880194909452600101548085169887019890985293909604909116948301949094529261217f5760405162461bcd60e51b815260206004820152600f60248201526e185b1c9958591e4818db185a5b5959608a1b604482015260640161079c565b80516001600160a01b031633146121c85760405162461bcd60e51b815260206004820152600d60248201526c3737ba103932b8bab2b9ba32b960991b604482015260640161079c565b81602001516001600160801b031681606001516001600160801b031611156122d557604960009054906101000a90046001600160a01b03166001600160a01b031663e52253816040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561223a57600080fd5b505af115801561224e573d6000803e3d6000fd5b50505050600061225c612c78565b90508083602001516001600160801b0316612277919061406f565b82606001516001600160801b031611156122d35760405162461bcd60e51b815260206004820152601760248201527f71756575652070656e64696e67206c6971756964697479000000000000000000604482015260640161079c565b505b806040015182604001516122e99190614044565b604b80546001600160801b039283166001600160801b03199091161790556000858152604c6020908152604091829020805460ff60a01b1916600160a01b179055838201518251931683529051869233927f2d43eb174787155132b52ddb6b346e2dca99302eac3df4466dbeff953d3c84d192918290030190a3604001516001600160801b03169392505050565b610bf38363a9059cbb60e01b8484604051602401612396929190613deb565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612f05565b6001600160a01b0381166124235760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f722069732061646472657373283029000000000000604482015260640161079c565b806001600160a01b031661244360008051602061430e8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36109f38160008051602061430e83398151915255565b600061249982612fd7565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161415611bf35760408051608081018252604a546001600160801b03808216808452600160801b9283900482166020850152604b54808316958501869052929092041660608301529091612522908461406f565b6108a6919061421a565b60006001600160ff1b0382126125545760405162461bcd60e51b815260040161079c90613f34565b600082121561256b5761256682614278565b610e41565b5090565b6038546060901561259e5760385460009061258e9084906127106131a6565b905061259a818461421a565b9250505b6000607b5490507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316603482815481106125e2576125e26142c1565b6000918252602090912001546001600160a01b0316146126445760405162461bcd60e51b815260206004820152601b60248201527f5745544820417373657420696e646578206e6f74206361636865640000000000604482015260640161079c565b60345467ffffffffffffffff81111561265f5761265f6142d7565b604051908082528060200260200182016040528015612688578160200160208202803683370190505b5091508282828151811061269e5761269e6142c1565b60200260200101818152505050919050565b7f222838db2794d11532d940e8dec38ae307ed0b63cd97c233322e221f998767a633836040516126e1929190613deb565b60405180910390a1816126f2575050565b60006126fd8361256f565b607b5481518110612710576127106142c1565b602002602001015190508181101561276a5760405162461bcd60e51b815260206004820181905260248201527f52656465656d20616d6f756e74206c6f776572207468616e206d696e696d756d604482015260640161079c565b806127736131c8565b106127b1576127ac6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163383612377565b6128bf565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660009081526040602081905290205416801561288357604051636ce5768960e11b81523360048201526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660248301526044820184905282919082169063d9caed1290606401600060405180830381600087803b15801561286557600080fd5b505af1158015612879573d6000803e3d6000fd5b50505050506128bd565b60405162461bcd60e51b815260206004820152600f60248201526e2634b8bab4b234ba3c9032b93937b960891b604482015260640161079c565b505b603c54604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac906128f19033908790600401613deb565b600060405180830381600087803b15801561290b57600080fd5b505af115801561291f573d6000803e3d6000fd5b50505050610bf383613314565b612934612c78565b50610e3461347a565b603754600090600160a01b900460ff161561298c5760405162461bcd60e51b815260206004820152600f60248201526e149958985cda5b99c81c185d5cd959608a1b604482015260640161079c565b603c54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd916004808301926020929190829003018186803b1580156129d157600080fd5b505afa1580156129e5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a099190613d59565b90506000612a15612e45565b905081612a25579150612c759050565b6042546001600160a01b03168015801590612a3f57508282115b15612b81576000612a50848461421a565b90506000612a6d604354612710846131a69092919063ffffffff16565b9050808211612ac95760405162461bcd60e51b815260206004820152602260248201527f466565206d757374206e6f742062652067726561746572207468616e207969656044820152611b1960f21b606482015260840161079c565b8015612b3457603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990612b019086908590600401613deb565b600060405180830381600087803b158015612b1b57600080fd5b505af1158015612b2f573d6000803e3d6000fd5b505050505b604080516001600160a01b0385168152602081018490529081018290527f09516ecf4a8a86e59780a9befc6dee948bc9e60a36e3be68d31ea817ee8d2c809060600160405180910390a150505b603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015612bcf57600080fd5b505afa158015612be3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c079190613d59565b925082821115612c7057603c546040516339a7919f60e01b8152600481018490526001600160a01b03909116906339a7919f90602401600060405180830381600087803b158015612c5757600080fd5b505af1158015612c6b573d6000803e3d6000fd5b505050505b509150505b90565b60408051608081018252604a546001600160801b03808216808452600160801b92839004821660208501819052604b5480841696860196909652929094041660608301526000928391612cca916141f2565b6001600160801b031690508015612e40576040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015612d3d57600080fd5b505afa158015612d51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d759190613d59565b9050600083604001518460200151612d8d91906141f2565b6001600160801b0316905080821115612e3d576000612dac828461421a565b9050808410612dbb5780612dbd565b835b955060008686602001516001600160801b0316612dda919061406f565b604a80546001600160801b03808416600160801b0291161790556040519091507fee79a0c43d3993055690b54e074b5153e8bae8d1a872b656dedb64aa8f46333390612e329083908a90918252602082015260400190565b60405180910390a150505b50505b505090565b6000612e4f6136e8565b60408051608081018252604a546001600160801b03808216808452600160801b9283900482166020850152604b54808316958501869052929092041660608301529293509190612e9f908461406f565b612ea9919061421a565b91505090565b6040516001600160a01b0380851660248301528316604482015260648101829052612ee79085906323b872dd60e01b90608401612396565b50505050565b60006108a68284614194565b60006108a68284614087565b6000612f5a826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166137049092919063ffffffff16565b805190915015610bf35780806020019051810190612f789190613d1e565b610bf35760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161079c565b6040516370a0823160e01b815230600482015260009082906001600160a01b038216906370a082319060240160206040518083038186803b15801561301b57600080fd5b505afa15801561302f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130539190613d59565b60365490925060005b8181101561319e57600060368281548110613079576130796142c1565b60009182526020909120015460405163551c457b60e11b81526001600160a01b0388811660048301529091169150819063aa388af69060240160206040518083038186803b1580156130ca57600080fd5b505afa1580156130de573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131029190613d1e565b1561318d57604051632fa8a91360e11b81526001600160a01b038781166004830152821690635f5152269060240160206040518083038186803b15801561314857600080fd5b505afa15801561315c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131809190613d59565b61318a908661406f565b94505b506131978161425d565b905061305c565b505050919050565b6000806131b38585612eed565b90506131bf8184612ef9565b95945050505050565b60408051608081018252604a546001600160801b03808216808452600160801b92839004821660208501819052604b548084169686019690965292909404166060830152600092839161321a916141f2565b6040516370a0823160e01b81523060048201526001600160801b039190911691506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a082319060240160206040518083038186803b15801561328a57600080fd5b505afa15801561329e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132c29190613d59565b90506000836040015184602001516132da91906141f2565b6001600160801b031690506132ef818461406f565b821115612e3d5780613301848461421a565b61330b919061421a565b94505050505090565b6000603b5482101580156133325750603754600160a01b900460ff16155b156133465761333f61293d565b9050613351565b61334e612e45565b90505b604154156134765760006133eb82603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156133ad57600080fd5b505afa1580156133c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133e59190613d59565b9061371b565b9050604154670de0b6b3a764000082116134165761341182670de0b6b3a764000061421a565b613428565b613428670de0b6b3a76400008361421a565b1115610bf35760405162461bcd60e51b815260206004820152601e60248201527f4261636b696e6720737570706c79206c6971756964697479206572726f720000604482015260640161079c565b5050565b600061348461373c565b90508061348e5750565b6000613498613819565b905060006134a6828461406f565b90506000826134cb576039546134c490670de0b6b3a764000061421a565b9050613508565b83826039546134da9190614194565b6134e49190614087565b905080670de0b6b3a76400001115612ee7576134c481670de0b6b3a764000061421a565b806135135750505050565b60345460005b818110156136e057600060348281548110613536576135366142c1565b60009182526020822001546040516370a0823160e01b81523060048201526001600160a01b03909116925082906370a082319060240160206040518083038186803b15801561358457600080fd5b505afa158015613598573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135bc9190613d59565b9050806135ca5750506136d0565b60006135d68287613875565b6001600160a01b038085166000908152604060208190529020549192501680158015906136035750600082115b156136cb578061361d6001600160a01b0386168285612377565b6040516311f9fbc960e21b81526001600160a01b038216906347e7ef249061364b9088908790600401613deb565b600060405180830381600087803b15801561366557600080fd5b505af1158015613679573d6000803e3d6000fd5b5050604080516001600160a01b03808a168252861660208201529081018690527f41b99659f6ba0803f444aff29e5bf6e26dd86a3219aff92119d69710a956ba8d9250606001905060405180910390a1505b505050505b6136d98161425d565b9050613519565b505050505050565b60006136f2613819565b6136fa61373c565b61076d919061406f565b6060613713848460008561388a565b949350505050565b60008061373084670de0b6b3a7640000612eed565b90506137138184612ef9565b603454600090815b81811015612e4057600060348281548110613761576137616142c1565b60009182526020822001546040516370a0823160e01b81523060048201526001600160a01b03909116925082906370a082319060240160206040518083038186803b1580156137af57600080fd5b505afa1580156137c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137e79190613d59565b90508015613806576137f98183611c5a565b613803908661406f565b94505b5050806138129061425d565b9050613744565b603654600090815b81811015612e40576138596036828154811061383f5761383f6142c1565b6000918252602090912001546001600160a01b03166139b2565b613863908461406f565b925061386e8161425d565b9050613821565b60006108a68383670de0b6b3a76400006131a6565b6060824710156138eb5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161079c565b843b6139395760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161079c565b600080866001600160a01b031685876040516139559190613dcf565b60006040518083038185875af1925050503d8060008114613992576040519150601f19603f3d011682016040523d82523d6000602084013e613997565b606091505b50915091506139a7828286613b17565b979650505050505050565b6034546000908290825b8181101561319e576000603482815481106139d9576139d96142c1565b60009182526020909120015460405163551c457b60e11b81526001600160a01b039182166004820181905292509085169063aa388af69060240160206040518083038186803b158015613a2b57600080fd5b505afa158015613a3f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a639190613d1e565b15613b0657604051632fa8a91360e11b81526001600160a01b03828116600483015260009190861690635f5152269060240160206040518083038186803b158015613aad57600080fd5b505afa158015613ac1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ae59190613d59565b90508015613b0457613af78183611c5a565b613b01908761406f565b95505b505b50613b108161425d565b90506139bc565b60608315613b265750816108a6565b825115613b365782518084602001fd5b8160405162461bcd60e51b815260040161079c9190613e86565b828054828255906000526020600020908101928215613ba5579160200282015b82811115613ba557825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190613b70565b5061256b9291505b8082111561256b5760008155600101613bad565b80356001600160a01b0381168114611bf357600080fd5b600060208284031215613bea57600080fd5b6108a682613bc1565b60008060408385031215613c0657600080fd5b613c0f83613bc1565b9150613c1d60208401613bc1565b90509250929050565b600080600060608486031215613c3b57600080fd5b613c4484613bc1565b95602085013595506040909401359392505050565b60006020808385031215613c6c57600080fd5b823567ffffffffffffffff80821115613c8457600080fd5b818501915085601f830112613c9857600080fd5b813581811115613caa57613caa6142d7565b8060051b604051601f19603f83011681018181108582111715613ccf57613ccf6142d7565b604052828152858101935084860182860187018a1015613cee57600080fd5b600095505b83861015613d11578035855260019590950194938601938601613cf3565b5098975050505050505050565b600060208284031215613d3057600080fd5b815180151581146108a657600080fd5b600060208284031215613d5257600080fd5b5035919050565b600060208284031215613d6b57600080fd5b5051919050565b60008060408385031215613d8557600080fd5b50508035926020909101359150565b600081518084526020808501945080840160005b83811015613dc457815187529582019590820190600101613da8565b509495945050505050565b60008251613de1818460208701614231565b9190910192915050565b6001600160a01b03929092168252602082015260400190565b6020808252825182820181905260009190848201906040850190845b81811015613e455783516001600160a01b031683529284019291840191600101613e20565b50909695505050505050565b6020815260006108a66020830184613d94565b604081526000613e776040830185613d94565b90508260208301529392505050565b6020815260008251806020840152613ea5816040850160208701614231565b601f01601f19169190910160400192915050565b60208082526024908201527f43616c6c6572206973206e6f7420746865204f555344206d65746120737472616040820152637465677960e01b606082015260800190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b6020808252600f908201526e082dadeeadce840e8dede40d0d2ced608b1b604082015260600190565b6020808252600e908201526d10d85c1a5d185b081c185d5cd95960921b604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b8151151581526020820151608082019060028110613fdb57634e487b7160e01b600052602160045260246000fd5b8060208401525060ff604084015116604083015261ffff606084015116606083015292915050565b600080821280156001600160ff1b038490038513161561402557614025614295565b600160ff1b839003841281161561403e5761403e614295565b50500190565b60006001600160801b0380831681851680830382111561406657614066614295565b01949350505050565b6000821982111561408257614082614295565b500190565b6000826140a457634e487b7160e01b600052601260045260246000fd5b500490565b600181815b808511156140e45781600019048211156140ca576140ca614295565b808516156140d757918102915b93841c93908002906140ae565b509250929050565b60006108a6838360008261410257506001610e41565b8161410f57506000610e41565b8160018114614125576002811461412f5761414b565b6001915050610e41565b60ff84111561414057614140614295565b50506001821b610e41565b5060208310610133831016604e8410600b841016171561416e575081810a610e41565b61417883836140a9565b806000190482111561418c5761418c614295565b029392505050565b60008160001904831182151516156141ae576141ae614295565b500290565b60008083128015600160ff1b8501841216156141d1576141d1614295565b6001600160ff1b03840183138116156141ec576141ec614295565b50500390565b60006001600160801b038381169083168181101561421257614212614295565b039392505050565b60008282101561422c5761422c614295565b500390565b60005b8381101561424c578181015183820152602001614234565b83811115612ee75750506000910152565b600060001982141561427157614271614295565b5060010190565b6000600160ff1b82141561428e5761428e614295565b5060000390565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fdfe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220c50e1d5377ccd0e0207b1b93cdbe2de692420544f1c0bb67494ccf540d5cd0c864736f6c634300080700337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106102bb5760003560e01c806367bd7ba311610182578063ab80dafb116100e9578063c7af3352116100a2578063e45cc9f01161007c578063e45cc9f014610712578063e6cc54321461071b578063f84444361461072f578063fc0cfeee14610742576102bb565b8063c7af3352146106ef578063d38bfff4146106f7578063d4c3eea01461070a576102bb565b8063ab80dafb146106a9578063abaa9916146106bc578063af14052c146106c4578063b888879e146106cc578063b9b17f9f146106df578063c3b28864146106e7576102bb565b8063937b25811161013b578063937b2581146105915780639be918e61461061b5780639ee679e8146106475780639fa1826e1461066f578063a0aead4d14610678578063a403e4d514610680576102bb565b806367bd7ba3146105195780636ec3ab67146105395780637136a7a6146105595780637a2202f31461056c5780637cbc2373146105755780638e510b5214610588576102bb565b8063485cc95511610226578063570d8e1d116101df578063570d8e1d146104b25780635b60f9fc146104c55780635d36b190146104d85780635f515226146104e0578063603ea03b146104f35780636217f3ea14610506576102bb565b8063485cc9551461043557806348e30f541461044857806349c1d54d1461046957806352d38e5d1461047c57806353ca9f241461048557806354c6d858146104a9576102bb565b80632acada4d116102785780632acada4d1461037757806331e19cfa1461038c578063362bd1a3146103945780633b8fe28d146103f35780633fc8cef31461040657806344c547071461042d576102bb565b806309f6442c146103015780630c340a241461031d578063156e29f61461033d57806318ce56bd146103525780631edfe3da14610365578063207134b01461036e575b7fa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd9366000803760008036600084545af43d6000803e8080156102fc573d6000f35b3d6000fd5b61030a60385481565b6040519081526020015b60405180910390f35b610325610755565b6040516001600160a01b039091168152602001610314565b61035061034b366004613c26565b610772565b005b604554610325906001600160a01b031681565b61030a60395481565b61030a60435481565b61037f6107f0565b6040516103149190613e04565b60365461030a565b604a54604b546103c0916001600160801b0380821692600160801b928390048216928183169291041684565b604080516001600160801b0395861681529385166020850152918416918301919091529091166060820152608001610314565b61030a610401366004613bd8565b610852565b6103257f000000000000000000000000000000000000000000000000000000000000000081565b6103506108ad565b610350610443366004613bf3565b6109f6565b61045b610456366004613c59565b610bf8565b604051610314929190613e64565b604254610325906001600160a01b031681565b61030a603b5481565b60375461049990600160a01b900460ff1681565b6040519015158152602001610314565b61030a607b5481565b603f54610325906001600160a01b031681565b61030a6104d3366004613bd8565b610d67565b610350610d90565b61030a6104ee366004613bd8565b610e36565b604954610325906001600160a01b031681565b610350610514366004613d40565b610e47565b61052c610527366004613d40565b610fde565b6040516103149190613e51565b61054c610547366004613bd8565b610fe9565b6040516103149190613fad565b610350610567366004613d40565b61108f565b61030a60475481565b610350610583366004613d72565b61117a565b61030a60415481565b6105e261059f366004613d40565b604c60205260009081526040902080546001909101546001600160a01b03821691600160a01b900460ff16906001600160801b0380821691600160801b90041684565b604080516001600160a01b03909516855292151560208501526001600160801b0391821692840192909252166060820152608001610314565b610499610629366004613bd8565b6001600160a01b031660009081526033602052604090205460ff1690565b61065a610655366004613d40565b6111ed565b60408051928352602083019190915201610314565b61030a603a5481565b60345461030a565b61032561068e366004613bd8565b6040602081905260009182529020546001600160a01b031681565b6103506106b7366004613d40565b6113e4565b61035061155b565b6103506115ca565b603754610325906001600160a01b031681565b610350611610565b61037f611680565b6104996116e0565b610350610705366004613bd8565b611711565b61030a6117b5565b61030a60465481565b60375461049990600160a81b900460ff1681565b61030a61073d366004613d40565b6117bf565b610350610750366004613bd8565b61186b565b600061076d60008051602061430e8339815191525490565b905090565b603754600160a81b900460ff16156107a55760405162461bcd60e51b815260040161079c90613f5d565b60405180910390fd5b6000805160206142ee833981519152805460028114156107d75760405162461bcd60e51b815260040161079c90613f85565b600282556107e685858561190d565b5060019055505050565b6060603480548060200260200160405190810160405280929190818152602001828054801561084857602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161082a575b5050505050905090565b60008061087b61087561086485611b8e565b670de0b6b3a7640000906012611bf8565b84611c5a565b9050670de0b6b3a764000081610892856001611db6565b61089c9190614194565b6108a69190614087565b9392505050565b6108b56116e0565b6108d15760405162461bcd60e51b815260040161079c90613efd565b60345460005b81811015610951577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166034828154811061091c5761091c6142c1565b6000918252602090912001546001600160a01b0316141561094157607b819055610951565b61094a8161425d565b90506108d7565b507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166034607b5481548110610991576109916142c1565b6000918252602090912001546001600160a01b0316146109f35760405162461bcd60e51b815260206004820152601860248201527f496e76616c6964205745544820417373657420496e6465780000000000000000604482015260640161079c565b50565b6109fe6116e0565b610a1a5760405162461bcd60e51b815260040161079c90613efd565b600054610100900460ff1680610a33575060005460ff16155b610a965760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161079c565b600054610100900460ff16158015610ab8576000805461ffff19166101011790555b6001600160a01b038316610b0e5760405162461bcd60e51b815260206004820152601d60248201527f507269636550726f76696465722061646472657373206973207a65726f000000604482015260640161079c565b6001600160a01b038216610b5d5760405162461bcd60e51b81526020600482015260166024820152756f546f6b656e2061646472657373206973207a65726f60501b604482015260640161079c565b603c80546001600160a01b038481166001600160a01b031990921691909117909155603780546001600160b01b03191691851691909117600160a81b17905560006038819055603981905569054b40b1f852bda00000603a55683635c9adc5dea00000603b556040805191825260208201908190529051610be091603691613b50565b508015610bf3576000805461ff00191690555b505050565b603754606090600090600160a81b900460ff1615610c285760405162461bcd60e51b815260040161079c90613f5d565b6000805160206142ee83398151915280546002811415610c5a5760405162461bcd60e51b815260040161079c90613f85565b60028255845167ffffffffffffffff811115610c7857610c786142d7565b604051908082528060200260200182016040528015610ca1578160200160208202803683370190505b50935060005b8551811015610d2757610cd2868281518110610cc557610cc56142c1565b60200260200101516120a8565b858281518110610ce457610ce46142c1565b602002602001018181525050848181518110610d0257610d026142c1565b602002602001015184610d15919061406f565b9350610d208161425d565b9050610ca7565b50610d5c6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163385612377565b600182555050915091565b600080610d7961087561086485611b8e565b9050670de0b6b3a764000081610892856000611db6565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614610e2b5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b606482015260840161079c565b610e34336123cd565b565b6000610e418261248e565b92915050565b603754600160a81b900460ff1615610e715760405162461bcd60e51b815260040161079c90613f5d565b6045546001600160a01b03163314610e9b5760405162461bcd60e51b815260040161079c90613eb9565b6001600160ff1b038110610ec15760405162461bcd60e51b815260040161079c90613f34565b7f222838db2794d11532d940e8dec38ae307ed0b63cd97c233322e221f998767a63382604051610ef2929190613deb565b60405180910390a18060466000828254610f0c91906141b3565b9091555050604754604654610f209061252c565b10610f775760405162461bcd60e51b815260206004820152602160248201527f417474656d7074696e6720746f206275726e20746f6f206d756368204f5553446044820152601760f91b606482015260840161079c565b603c54604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac90610fa99033908590600401613deb565b600060405180830381600087803b158015610fc357600080fd5b505af1158015610fd7573d6000803e3d6000fd5b5050505050565b6060610e418261256f565b604080516080808201835260008083526020808401829052838501829052606084018290526001600160a01b038616825260338152908490208451928301909452835460ff808216151584529394929391840191610100909104166001811115611055576110556142ab565b6001811115611066576110666142ab565b8152905462010000810460ff1660208301526301000000900461ffff1660409091015292915050565b603754600160a81b900460ff16156110b95760405162461bcd60e51b815260040161079c90613f5d565b6000805160206142ee833981519152805460028114156110eb5760405162461bcd60e51b815260040161079c90613f85565b60028255603c546040516370a0823160e01b8152336004820152611172916001600160a01b0316906370a082319060240160206040518083038186803b15801561113457600080fd5b505afa158015611148573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061116c9190613d59565b846126b0565b506001905550565b603754600160a81b900460ff16156111a45760405162461bcd60e51b815260040161079c90613f5d565b6000805160206142ee833981519152805460028114156111d65760405162461bcd60e51b815260040161079c90613f85565b600282556111e484846126b0565b50600190555050565b6037546000908190600160a81b900460ff161561121c5760405162461bcd60e51b815260040161079c90613f5d565b6000805160206142ee8339815191528054600281141561124e5760405162461bcd60e51b815260040161079c90613f85565b60028255603c54604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac906112849033908990600401613deb565b600060405180830381600087803b15801561129e57600080fd5b505af11580156112b2573d6000803e3d6000fd5b5050604b54604a546001600160801b03600160801b909204821697506112dc93508892501661406f565b92506112e984600161406f565b604b80546001600160801b03928316600160801b02908316179055604a80549185166001600160801b03199092169190911790556040805186815260208101859052859133917f38e3d972947cfef94205163d483d6287ef27eb312e20cb8e0b13a49989db232e910160405180910390a35060408051608081018252338152600060208083018281526001600160801b03988916848601908152878a1660608601908152898552604c909352949092209251835492511515600160a01b026001600160a81b03199093166001600160a01b039190911617919091178255915191518616600160801b0291909516176001948501559290925591565b603754600160a81b900460ff161561140e5760405162461bcd60e51b815260040161079c90613f5d565b6045546001600160a01b031633146114385760405162461bcd60e51b815260040161079c90613eb9565b6001600160ff1b03811061145e5760405162461bcd60e51b815260040161079c90613f34565b7f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d4121396885338260405161148f929190613deb565b60405180910390a180604660008282546114a99190614003565b90915550506047546046546114bd9061252c565b106115295760405162461bcd60e51b815260206004820152603660248201527f4d696e746564206f75736420737572706173736564206e65744f7573644d696e6044820152753a2337b929ba3930ba32b3bcaa343932b9b437b6321760511b606482015260840161079c565b603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990610fa99033908590600401613deb565b603754600160a81b900460ff16156115855760405162461bcd60e51b815260040161079c90613f5d565b6000805160206142ee833981519152805460028114156115b75760405162461bcd60e51b815260040161079c90613f85565b600282556115c361292c565b5060019055565b6000805160206142ee833981519152805460028114156115fc5760405162461bcd60e51b815260040161079c90613f85565b6002825561160861293d565b505060019055565b604960009054906101000a90046001600160a01b03166001600160a01b031663e52253816040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561166057600080fd5b505af1158015611674573d6000803e3d6000fd5b505050506109f3612c78565b60606036805480602002602001604051908101604052809291908181526020018280548015610848576020028201919060005260206000209081546001600160a01b0316815260019091019060200180831161082a575050505050905090565b60006116f860008051602061430e8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b6117196116e0565b6117355760405162461bcd60e51b815260040161079c90613efd565b61175d817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b031661177d60008051602061430e8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b600061076d612e45565b603754600090600160a81b900460ff16156117ec5760405162461bcd60e51b815260040161079c90613f5d565b6000805160206142ee8339815191528054600281141561181e5760405162461bcd60e51b815260040161079c90613f85565b6002825561182b846120a8565b92506118616001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163385612377565b5060019055919050565b6118736116e0565b61188f5760405162461bcd60e51b815260040161079c90613efd565b803b6118e95760405162461bcd60e51b8152602060048201526024808201527f6e657720696d706c656d656e746174696f6e206973206e6f74206120636f6e746044820152631c9858dd60e21b606482015260840161079c565b7fa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd955565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b03161461198e5760405162461bcd60e51b815260206004820152601d60248201527f556e737570706f7274656420617373657420666f72206d696e74696e67000000604482015260640161079c565b600082116119de5760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e2030000000604482015260640161079c565b80821015611a2e5760405162461bcd60e51b815260206004820152601e60248201527f4d696e7420616d6f756e74206c6f776572207468616e206d696e696d756d0000604482015260640161079c565b7f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d41213968853383604051611a5f929190613deb565b60405180910390a1603754600160a01b900460ff16158015611a835750603b548210155b15611afa57604960009054906101000a90046001600160a01b03166001600160a01b031663e52253816040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611ad857600080fd5b505af1158015611aec573d6000803e3d6000fd5b50505050611af861293d565b505b603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990611b2c9033908690600401613deb565b600060405180830381600087803b158015611b4657600080fd5b505af1158015611b5a573d6000803e3d6000fd5b50611b74925050506001600160a01b038416333085612eaf565b611b7c612c78565b50603a548210610bf357610bf361292c565b6001600160a01b03811660009081526033602052604090205462010000900460ff1680611bf35760405162461bcd60e51b8152602060048201526013602482015272111958da5b585b1cc81b9bdd0818d858da1959606a1b604482015260640161079c565b919050565b600081831115611c2857611c21611c0f838561421a565b611c1a90600a6140ec565b8590612eed565b9350611c52565b81831015611c5257611c4f611c3d848461421a565b611c4890600a6140ec565b8590612ef9565b93505b509192915050565b6001600160a01b038116600090815260336020526040812054610100900460ff1681816001811115611c8e57611c8e6142ab565b1415611cb257611caa6012611ca285611b8e565b869190611bf8565b915050610e41565b6001816001811115611cc657611cc66142ab565b1415611d67576000836001600160a01b031663e6aa216c6040518163ffffffff1660e01b815260040160206040518083038186803b158015611d0757600080fd5b505afa158015611d1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d3f9190613d59565b9050670de0b6b3a7640000611d548287614194565b611d5e9190614087565b92505050610e41565b60405162461bcd60e51b815260206004820152601b60248201527f556e737570706f7274656420636f6e76657273696f6e20747970650000000000604482015260640161079c565b5092915050565b6001600160a01b038281166000818152603360205260408082205460375491516315d5220f60e31b81526004810194909452919361010090920460ff169291169063aea910789060240160206040518083038186803b158015611e1857600080fd5b505afa158015611e2c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e509190613d59565b91506001816001811115611e6657611e666142ab565b1415611f06576000846001600160a01b031663e6aa216c6040518163ffffffff1660e01b815260040160206040518083038186803b158015611ea757600080fd5b505afa158015611ebb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611edf9190613d59565b905080611ef484670de0b6b3a7640000614194565b611efe9190614087565b925050611f67565b6000816001811115611f1a57611f1a6142ab565b14611f675760405162461bcd60e51b815260206004820152601b60248201527f556e737570706f7274656420636f6e76657273696f6e20747970650000000000604482015260640161079c565b67120a871cc0020000821115611fbf5760405162461bcd60e51b815260206004820152601860248201527f5661756c743a2050726963652065786365656473206d61780000000000000000604482015260640161079c565b6709b6e64a8ec600008210156120105760405162461bcd60e51b81526020600482015260166024820152752b30bab63a1d10283934b1b2903ab73232b91036b4b760511b604482015260640161079c565b821561208757670de0b6b3a764000082111561203257670de0b6b3a764000091505b670dd99bb65dd700008210156120825760405162461bcd60e51b815260206004820152601560248201527441737365742070726963652062656c6f772070656760581b604482015260640161079c565b611daf565b670de0b6b3a7640000821015611daf5750670de0b6b3a76400009392505050565b6040805160808082018352604a546001600160801b038082168452600160801b918290048116602080860191909152604b548083168688015283900482166060808701919091526000888152604c83528781208851968701895280546001600160a01b0381168852600160a01b900460ff1615801594880194909452600101548085169887019890985293909604909116948301949094529261217f5760405162461bcd60e51b815260206004820152600f60248201526e185b1c9958591e4818db185a5b5959608a1b604482015260640161079c565b80516001600160a01b031633146121c85760405162461bcd60e51b815260206004820152600d60248201526c3737ba103932b8bab2b9ba32b960991b604482015260640161079c565b81602001516001600160801b031681606001516001600160801b031611156122d557604960009054906101000a90046001600160a01b03166001600160a01b031663e52253816040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561223a57600080fd5b505af115801561224e573d6000803e3d6000fd5b50505050600061225c612c78565b90508083602001516001600160801b0316612277919061406f565b82606001516001600160801b031611156122d35760405162461bcd60e51b815260206004820152601760248201527f71756575652070656e64696e67206c6971756964697479000000000000000000604482015260640161079c565b505b806040015182604001516122e99190614044565b604b80546001600160801b039283166001600160801b03199091161790556000858152604c6020908152604091829020805460ff60a01b1916600160a01b179055838201518251931683529051869233927f2d43eb174787155132b52ddb6b346e2dca99302eac3df4466dbeff953d3c84d192918290030190a3604001516001600160801b03169392505050565b610bf38363a9059cbb60e01b8484604051602401612396929190613deb565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612f05565b6001600160a01b0381166124235760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f722069732061646472657373283029000000000000604482015260640161079c565b806001600160a01b031661244360008051602061430e8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36109f38160008051602061430e83398151915255565b600061249982612fd7565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161415611bf35760408051608081018252604a546001600160801b03808216808452600160801b9283900482166020850152604b54808316958501869052929092041660608301529091612522908461406f565b6108a6919061421a565b60006001600160ff1b0382126125545760405162461bcd60e51b815260040161079c90613f34565b600082121561256b5761256682614278565b610e41565b5090565b6038546060901561259e5760385460009061258e9084906127106131a6565b905061259a818461421a565b9250505b6000607b5490507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316603482815481106125e2576125e26142c1565b6000918252602090912001546001600160a01b0316146126445760405162461bcd60e51b815260206004820152601b60248201527f5745544820417373657420696e646578206e6f74206361636865640000000000604482015260640161079c565b60345467ffffffffffffffff81111561265f5761265f6142d7565b604051908082528060200260200182016040528015612688578160200160208202803683370190505b5091508282828151811061269e5761269e6142c1565b60200260200101818152505050919050565b7f222838db2794d11532d940e8dec38ae307ed0b63cd97c233322e221f998767a633836040516126e1929190613deb565b60405180910390a1816126f2575050565b60006126fd8361256f565b607b5481518110612710576127106142c1565b602002602001015190508181101561276a5760405162461bcd60e51b815260206004820181905260248201527f52656465656d20616d6f756e74206c6f776572207468616e206d696e696d756d604482015260640161079c565b806127736131c8565b106127b1576127ac6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163383612377565b6128bf565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660009081526040602081905290205416801561288357604051636ce5768960e11b81523360048201526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660248301526044820184905282919082169063d9caed1290606401600060405180830381600087803b15801561286557600080fd5b505af1158015612879573d6000803e3d6000fd5b50505050506128bd565b60405162461bcd60e51b815260206004820152600f60248201526e2634b8bab4b234ba3c9032b93937b960891b604482015260640161079c565b505b603c54604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac906128f19033908790600401613deb565b600060405180830381600087803b15801561290b57600080fd5b505af115801561291f573d6000803e3d6000fd5b50505050610bf383613314565b612934612c78565b50610e3461347a565b603754600090600160a01b900460ff161561298c5760405162461bcd60e51b815260206004820152600f60248201526e149958985cda5b99c81c185d5cd959608a1b604482015260640161079c565b603c54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd916004808301926020929190829003018186803b1580156129d157600080fd5b505afa1580156129e5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a099190613d59565b90506000612a15612e45565b905081612a25579150612c759050565b6042546001600160a01b03168015801590612a3f57508282115b15612b81576000612a50848461421a565b90506000612a6d604354612710846131a69092919063ffffffff16565b9050808211612ac95760405162461bcd60e51b815260206004820152602260248201527f466565206d757374206e6f742062652067726561746572207468616e207969656044820152611b1960f21b606482015260840161079c565b8015612b3457603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990612b019086908590600401613deb565b600060405180830381600087803b158015612b1b57600080fd5b505af1158015612b2f573d6000803e3d6000fd5b505050505b604080516001600160a01b0385168152602081018490529081018290527f09516ecf4a8a86e59780a9befc6dee948bc9e60a36e3be68d31ea817ee8d2c809060600160405180910390a150505b603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015612bcf57600080fd5b505afa158015612be3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c079190613d59565b925082821115612c7057603c546040516339a7919f60e01b8152600481018490526001600160a01b03909116906339a7919f90602401600060405180830381600087803b158015612c5757600080fd5b505af1158015612c6b573d6000803e3d6000fd5b505050505b509150505b90565b60408051608081018252604a546001600160801b03808216808452600160801b92839004821660208501819052604b5480841696860196909652929094041660608301526000928391612cca916141f2565b6001600160801b031690508015612e40576040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015612d3d57600080fd5b505afa158015612d51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d759190613d59565b9050600083604001518460200151612d8d91906141f2565b6001600160801b0316905080821115612e3d576000612dac828461421a565b9050808410612dbb5780612dbd565b835b955060008686602001516001600160801b0316612dda919061406f565b604a80546001600160801b03808416600160801b0291161790556040519091507fee79a0c43d3993055690b54e074b5153e8bae8d1a872b656dedb64aa8f46333390612e329083908a90918252602082015260400190565b60405180910390a150505b50505b505090565b6000612e4f6136e8565b60408051608081018252604a546001600160801b03808216808452600160801b9283900482166020850152604b54808316958501869052929092041660608301529293509190612e9f908461406f565b612ea9919061421a565b91505090565b6040516001600160a01b0380851660248301528316604482015260648101829052612ee79085906323b872dd60e01b90608401612396565b50505050565b60006108a68284614194565b60006108a68284614087565b6000612f5a826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166137049092919063ffffffff16565b805190915015610bf35780806020019051810190612f789190613d1e565b610bf35760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161079c565b6040516370a0823160e01b815230600482015260009082906001600160a01b038216906370a082319060240160206040518083038186803b15801561301b57600080fd5b505afa15801561302f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130539190613d59565b60365490925060005b8181101561319e57600060368281548110613079576130796142c1565b60009182526020909120015460405163551c457b60e11b81526001600160a01b0388811660048301529091169150819063aa388af69060240160206040518083038186803b1580156130ca57600080fd5b505afa1580156130de573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131029190613d1e565b1561318d57604051632fa8a91360e11b81526001600160a01b038781166004830152821690635f5152269060240160206040518083038186803b15801561314857600080fd5b505afa15801561315c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131809190613d59565b61318a908661406f565b94505b506131978161425d565b905061305c565b505050919050565b6000806131b38585612eed565b90506131bf8184612ef9565b95945050505050565b60408051608081018252604a546001600160801b03808216808452600160801b92839004821660208501819052604b548084169686019690965292909404166060830152600092839161321a916141f2565b6040516370a0823160e01b81523060048201526001600160801b039190911691506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a082319060240160206040518083038186803b15801561328a57600080fd5b505afa15801561329e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132c29190613d59565b90506000836040015184602001516132da91906141f2565b6001600160801b031690506132ef818461406f565b821115612e3d5780613301848461421a565b61330b919061421a565b94505050505090565b6000603b5482101580156133325750603754600160a01b900460ff16155b156133465761333f61293d565b9050613351565b61334e612e45565b90505b604154156134765760006133eb82603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156133ad57600080fd5b505afa1580156133c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133e59190613d59565b9061371b565b9050604154670de0b6b3a764000082116134165761341182670de0b6b3a764000061421a565b613428565b613428670de0b6b3a76400008361421a565b1115610bf35760405162461bcd60e51b815260206004820152601e60248201527f4261636b696e6720737570706c79206c6971756964697479206572726f720000604482015260640161079c565b5050565b600061348461373c565b90508061348e5750565b6000613498613819565b905060006134a6828461406f565b90506000826134cb576039546134c490670de0b6b3a764000061421a565b9050613508565b83826039546134da9190614194565b6134e49190614087565b905080670de0b6b3a76400001115612ee7576134c481670de0b6b3a764000061421a565b806135135750505050565b60345460005b818110156136e057600060348281548110613536576135366142c1565b60009182526020822001546040516370a0823160e01b81523060048201526001600160a01b03909116925082906370a082319060240160206040518083038186803b15801561358457600080fd5b505afa158015613598573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135bc9190613d59565b9050806135ca5750506136d0565b60006135d68287613875565b6001600160a01b038085166000908152604060208190529020549192501680158015906136035750600082115b156136cb578061361d6001600160a01b0386168285612377565b6040516311f9fbc960e21b81526001600160a01b038216906347e7ef249061364b9088908790600401613deb565b600060405180830381600087803b15801561366557600080fd5b505af1158015613679573d6000803e3d6000fd5b5050604080516001600160a01b03808a168252861660208201529081018690527f41b99659f6ba0803f444aff29e5bf6e26dd86a3219aff92119d69710a956ba8d9250606001905060405180910390a1505b505050505b6136d98161425d565b9050613519565b505050505050565b60006136f2613819565b6136fa61373c565b61076d919061406f565b6060613713848460008561388a565b949350505050565b60008061373084670de0b6b3a7640000612eed565b90506137138184612ef9565b603454600090815b81811015612e4057600060348281548110613761576137616142c1565b60009182526020822001546040516370a0823160e01b81523060048201526001600160a01b03909116925082906370a082319060240160206040518083038186803b1580156137af57600080fd5b505afa1580156137c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137e79190613d59565b90508015613806576137f98183611c5a565b613803908661406f565b94505b5050806138129061425d565b9050613744565b603654600090815b81811015612e40576138596036828154811061383f5761383f6142c1565b6000918252602090912001546001600160a01b03166139b2565b613863908461406f565b925061386e8161425d565b9050613821565b60006108a68383670de0b6b3a76400006131a6565b6060824710156138eb5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161079c565b843b6139395760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161079c565b600080866001600160a01b031685876040516139559190613dcf565b60006040518083038185875af1925050503d8060008114613992576040519150601f19603f3d011682016040523d82523d6000602084013e613997565b606091505b50915091506139a7828286613b17565b979650505050505050565b6034546000908290825b8181101561319e576000603482815481106139d9576139d96142c1565b60009182526020909120015460405163551c457b60e11b81526001600160a01b039182166004820181905292509085169063aa388af69060240160206040518083038186803b158015613a2b57600080fd5b505afa158015613a3f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a639190613d1e565b15613b0657604051632fa8a91360e11b81526001600160a01b03828116600483015260009190861690635f5152269060240160206040518083038186803b158015613aad57600080fd5b505afa158015613ac1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ae59190613d59565b90508015613b0457613af78183611c5a565b613b01908761406f565b95505b505b50613b108161425d565b90506139bc565b60608315613b265750816108a6565b825115613b365782518084602001fd5b8160405162461bcd60e51b815260040161079c9190613e86565b828054828255906000526020600020908101928215613ba5579160200282015b82811115613ba557825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190613b70565b5061256b9291505b8082111561256b5760008155600101613bad565b80356001600160a01b0381168114611bf357600080fd5b600060208284031215613bea57600080fd5b6108a682613bc1565b60008060408385031215613c0657600080fd5b613c0f83613bc1565b9150613c1d60208401613bc1565b90509250929050565b600080600060608486031215613c3b57600080fd5b613c4484613bc1565b95602085013595506040909401359392505050565b60006020808385031215613c6c57600080fd5b823567ffffffffffffffff80821115613c8457600080fd5b818501915085601f830112613c9857600080fd5b813581811115613caa57613caa6142d7565b8060051b604051601f19603f83011681018181108582111715613ccf57613ccf6142d7565b604052828152858101935084860182860187018a1015613cee57600080fd5b600095505b83861015613d11578035855260019590950194938601938601613cf3565b5098975050505050505050565b600060208284031215613d3057600080fd5b815180151581146108a657600080fd5b600060208284031215613d5257600080fd5b5035919050565b600060208284031215613d6b57600080fd5b5051919050565b60008060408385031215613d8557600080fd5b50508035926020909101359150565b600081518084526020808501945080840160005b83811015613dc457815187529582019590820190600101613da8565b509495945050505050565b60008251613de1818460208701614231565b9190910192915050565b6001600160a01b03929092168252602082015260400190565b6020808252825182820181905260009190848201906040850190845b81811015613e455783516001600160a01b031683529284019291840191600101613e20565b50909695505050505050565b6020815260006108a66020830184613d94565b604081526000613e776040830185613d94565b90508260208301529392505050565b6020815260008251806020840152613ea5816040850160208701614231565b601f01601f19169190910160400192915050565b60208082526024908201527f43616c6c6572206973206e6f7420746865204f555344206d65746120737472616040820152637465677960e01b606082015260800190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b6020808252600f908201526e082dadeeadce840e8dede40d0d2ced608b1b604082015260600190565b6020808252600e908201526d10d85c1a5d185b081c185d5cd95960921b604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b8151151581526020820151608082019060028110613fdb57634e487b7160e01b600052602160045260246000fd5b8060208401525060ff604084015116604083015261ffff606084015116606083015292915050565b600080821280156001600160ff1b038490038513161561402557614025614295565b600160ff1b839003841281161561403e5761403e614295565b50500190565b60006001600160801b0380831681851680830382111561406657614066614295565b01949350505050565b6000821982111561408257614082614295565b500190565b6000826140a457634e487b7160e01b600052601260045260246000fd5b500490565b600181815b808511156140e45781600019048211156140ca576140ca614295565b808516156140d757918102915b93841c93908002906140ae565b509250929050565b60006108a6838360008261410257506001610e41565b8161410f57506000610e41565b8160018114614125576002811461412f5761414b565b6001915050610e41565b60ff84111561414057614140614295565b50506001821b610e41565b5060208310610133831016604e8410600b841016171561416e575081810a610e41565b61417883836140a9565b806000190482111561418c5761418c614295565b029392505050565b60008160001904831182151516156141ae576141ae614295565b500290565b60008083128015600160ff1b8501841216156141d1576141d1614295565b6001600160ff1b03840183138116156141ec576141ec614295565b50500390565b60006001600160801b038381169083168181101561421257614212614295565b039392505050565b60008282101561422c5761422c614295565b500390565b60005b8381101561424c578181015183820152602001614234565b83811115612ee75750506000910152565b600060001982141561427157614271614295565b5060010190565b6000600160ff1b82141561428e5761428e614295565b5060000390565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fdfe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220c50e1d5377ccd0e0207b1b93cdbe2de692420544f1c0bb67494ccf540d5cd0c864736f6c63430008070033", "libraries": {}, "devdoc": { "author": "Origin Protocol Inc", "kind": "dev", "methods": { + "addWithdrawalQueueLiquidity()": { + "details": "is called from the Native Staking strategy when validator withdrawals are processed. It also called before any WETH is allocated to a strategy." + }, "burnForStrategy(uint256)": { "details": "Notice: can't use `nonReentrant` modifier since the `redeem` function could require withdrawal on `ConvexOUSDMetaStrategy` and that one can call `burnForStrategy` while the execution of the `redeem` has not yet completed -> causing a `nonReentrant` collision. Also important to understand is that this is a limitation imposed by the test suite. Production / mainnet contracts should never be configured in a way where mint/redeem functions that are moving funds between the Vault and end user wallets can influence strategies utilizing this function.", "params": { @@ -1111,6 +1364,22 @@ "_0": "uint256 Balance of asset in decimals of asset" } }, + "claimWithdrawal(uint256)": { + "params": { + "requestId": "Unique ID for the withdrawal request" + }, + "returns": { + "amount": "Amount of WETH transferred to the withdrawer" + } + }, + "claimWithdrawals(uint256[])": { + "params": { + "requestIds": "Unique ID of each withdrawal request" + }, + "returns": { + "amounts": "Amount of WETH received for each request" + } + }, "isSupportedAsset(address)": { "params": { "_asset": "address of the asset" @@ -1158,6 +1427,13 @@ "_minimumUnitAmount": "Minimum stablecoin units to receive in return" } }, + "requestWithdrawal(uint256)": { + "params": { + "_amount": "Amount of oTokens to burn. eg OETH", + "queued": "Cumulative total of all WETH queued including already claimed requests. This request can be claimed once the withdrawal queue's claimable amount is greater than or equal this request's queued amount.", + "requestId": "Unique ID for the withdrawal request" + } + }, "setAdminImpl(address)": { "params": { "newImpl": "address of the implementation" @@ -1180,6 +1456,9 @@ "userdoc": { "kind": "user", "methods": { + "addWithdrawalQueueLiquidity()": { + "notice": "Collects harvested rewards from the Dripper as WETH then adds WETH to the withdrawal queue if there is a funding shortfall." + }, "allocate()": { "notice": "Allocate unallocated funds on Vault to strategies.*" }, @@ -1204,6 +1483,15 @@ "claimGovernance()": { "notice": "Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor." }, + "claimWithdrawal(uint256)": { + "notice": "Claim a previously requested withdrawal once it is claimable." + }, + "claimWithdrawals(uint256[])": { + "notice": "Claim a previously requested withdrawals once they are claimable." + }, + "dripper()": { + "notice": "Address of the Dripper contract that streams harvested rewards to the Vault" + }, "getAllAssets()": { "notice": "Return all vault asset addresses in order" }, @@ -1273,6 +1561,9 @@ "redeemFeeBps()": { "notice": "Redemption fee in basis points. eg 50 = 0.5%" }, + "requestWithdrawal(uint256)": { + "notice": "Request an asynchronous withdrawal of the underlying asset. eg WETH" + }, "setAdminImpl(address)": { "notice": "set the implementation for the admin, this needs to be in a base class else we cannot set it" }, @@ -1300,7 +1591,7 @@ "storageLayout": { "storage": [ { - "astId": 41419, + "astId": 24111, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "initialized", "offset": 0, @@ -1308,7 +1599,7 @@ "type": "t_bool" }, { - "astId": 41422, + "astId": 24114, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "initializing", "offset": 1, @@ -1316,7 +1607,7 @@ "type": "t_bool" }, { - "astId": 41462, + "astId": 24154, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "______gap", "offset": 0, @@ -1324,15 +1615,15 @@ "type": "t_array(t_uint256)50_storage" }, { - "astId": 46069, + "astId": 29745, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "assets", "offset": 0, "slot": "51", - "type": "t_mapping(t_address,t_struct(Asset)46063_storage)" + "type": "t_mapping(t_address,t_struct(Asset)29739_storage)" }, { - "astId": 46073, + "astId": 29749, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "allAssets", "offset": 0, @@ -1340,15 +1631,15 @@ "type": "t_array(t_address)dyn_storage" }, { - "astId": 46084, + "astId": 29760, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "strategies", "offset": 0, "slot": "53", - "type": "t_mapping(t_address,t_struct(Strategy)46078_storage)" + "type": "t_mapping(t_address,t_struct(Strategy)29754_storage)" }, { - "astId": 46088, + "astId": 29764, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "allStrategies", "offset": 0, @@ -1356,7 +1647,7 @@ "type": "t_array(t_address)dyn_storage" }, { - "astId": 46091, + "astId": 29767, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "priceProvider", "offset": 0, @@ -1364,7 +1655,7 @@ "type": "t_address" }, { - "astId": 46095, + "astId": 29771, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "rebasePaused", "offset": 20, @@ -1372,7 +1663,7 @@ "type": "t_bool" }, { - "astId": 46099, + "astId": 29775, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "capitalPaused", "offset": 21, @@ -1380,7 +1671,7 @@ "type": "t_bool" }, { - "astId": 46102, + "astId": 29778, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "redeemFeeBps", "offset": 0, @@ -1388,7 +1679,7 @@ "type": "t_uint256" }, { - "astId": 46105, + "astId": 29781, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "vaultBuffer", "offset": 0, @@ -1396,7 +1687,7 @@ "type": "t_uint256" }, { - "astId": 46108, + "astId": 29784, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "autoAllocateThreshold", "offset": 0, @@ -1404,7 +1695,7 @@ "type": "t_uint256" }, { - "astId": 46111, + "astId": 29787, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "rebaseThreshold", "offset": 0, @@ -1412,15 +1703,15 @@ "type": "t_uint256" }, { - "astId": 46115, + "astId": 29791, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "oUSD", "offset": 0, "slot": "60", - "type": "t_contract(OUSD)40245" + "type": "t_contract(OUSD)23477" }, { - "astId": 46124, + "astId": 29800, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "_deprecated_rebaseHooksAddr", "offset": 0, @@ -1428,7 +1719,7 @@ "type": "t_address" }, { - "astId": 46130, + "astId": 29806, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "_deprecated_uniswapAddr", "offset": 0, @@ -1436,7 +1727,7 @@ "type": "t_address" }, { - "astId": 46137, + "astId": 29813, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "strategistAddr", "offset": 0, @@ -1444,7 +1735,7 @@ "type": "t_address" }, { - "astId": 46142, + "astId": 29818, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "assetDefaultStrategies", "offset": 0, @@ -1452,7 +1743,7 @@ "type": "t_mapping(t_address,t_address)" }, { - "astId": 46145, + "astId": 29821, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "maxSupplyDiff", "offset": 0, @@ -1460,7 +1751,7 @@ "type": "t_uint256" }, { - "astId": 46148, + "astId": 29824, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "trusteeAddress", "offset": 0, @@ -1468,7 +1759,7 @@ "type": "t_address" }, { - "astId": 46151, + "astId": 29827, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "trusteeFeeBps", "offset": 0, @@ -1476,7 +1767,7 @@ "type": "t_uint256" }, { - "astId": 46155, + "astId": 29831, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "_deprecated_swapTokens", "offset": 0, @@ -1484,7 +1775,7 @@ "type": "t_array(t_address)dyn_storage" }, { - "astId": 46165, + "astId": 29841, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "ousdMetaStrategy", "offset": 0, @@ -1492,7 +1783,7 @@ "type": "t_address" }, { - "astId": 46169, + "astId": 29845, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "netOusdMintedForStrategy", "offset": 0, @@ -1500,7 +1791,7 @@ "type": "t_int256" }, { - "astId": 46173, + "astId": 29849, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "netOusdMintForStrategyThreshold", "offset": 0, @@ -1508,23 +1799,47 @@ "type": "t_uint256" }, { - "astId": 46194, + "astId": 29870, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "swapConfig", "offset": 0, "slot": "72", - "type": "t_struct(SwapConfig)46184_storage" + "type": "t_struct(SwapConfig)29860_storage" }, { - "astId": 46198, + "astId": 29873, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", - "label": "__gap", + "label": "dripper", "offset": 0, "slot": "73", - "type": "t_array(t_uint256)50_storage" + "type": "t_address" + }, + { + "astId": 29885, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "withdrawalQueueMetadata", + "offset": 0, + "slot": "74", + "type": "t_struct(WithdrawalQueueMetadata)29882_storage" }, { - "astId": 42360, + "astId": 29899, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "withdrawalRequests", + "offset": 0, + "slot": "76", + "type": "t_mapping(t_uint256,t_struct(WithdrawalRequest)29894_storage)" + }, + { + "astId": 29903, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "__gap", + "offset": 0, + "slot": "77", + "type": "t_array(t_uint256)46_storage" + }, + { + "astId": 25324, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "wethAssetIndex", "offset": 0, @@ -1544,6 +1859,12 @@ "label": "address[]", "numberOfBytes": "32" }, + "t_array(t_uint256)46_storage": { + "base": "t_uint256", + "encoding": "inplace", + "label": "uint256[46]", + "numberOfBytes": "1472" + }, "t_array(t_uint256)50_storage": { "base": "t_uint256", "encoding": "inplace", @@ -1555,12 +1876,12 @@ "label": "bool", "numberOfBytes": "1" }, - "t_contract(OUSD)40245": { + "t_contract(OUSD)23477": { "encoding": "inplace", "label": "contract OUSD", "numberOfBytes": "20" }, - "t_enum(UnitConversion)46053": { + "t_enum(UnitConversion)29729": { "encoding": "inplace", "label": "enum VaultStorage.UnitConversion", "numberOfBytes": "1" @@ -1577,26 +1898,33 @@ "numberOfBytes": "32", "value": "t_address" }, - "t_mapping(t_address,t_struct(Asset)46063_storage)": { + "t_mapping(t_address,t_struct(Asset)29739_storage)": { "encoding": "mapping", "key": "t_address", "label": "mapping(address => struct VaultStorage.Asset)", "numberOfBytes": "32", - "value": "t_struct(Asset)46063_storage" + "value": "t_struct(Asset)29739_storage" }, - "t_mapping(t_address,t_struct(Strategy)46078_storage)": { + "t_mapping(t_address,t_struct(Strategy)29754_storage)": { "encoding": "mapping", "key": "t_address", "label": "mapping(address => struct VaultStorage.Strategy)", "numberOfBytes": "32", - "value": "t_struct(Strategy)46078_storage" + "value": "t_struct(Strategy)29754_storage" }, - "t_struct(Asset)46063_storage": { + "t_mapping(t_uint256,t_struct(WithdrawalRequest)29894_storage)": { + "encoding": "mapping", + "key": "t_uint256", + "label": "mapping(uint256 => struct VaultStorage.WithdrawalRequest)", + "numberOfBytes": "32", + "value": "t_struct(WithdrawalRequest)29894_storage" + }, + "t_struct(Asset)29739_storage": { "encoding": "inplace", "label": "struct VaultStorage.Asset", "members": [ { - "astId": 46055, + "astId": 29731, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "isSupported", "offset": 0, @@ -1604,15 +1932,15 @@ "type": "t_bool" }, { - "astId": 46058, + "astId": 29734, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "unitConversion", "offset": 1, "slot": "0", - "type": "t_enum(UnitConversion)46053" + "type": "t_enum(UnitConversion)29729" }, { - "astId": 46060, + "astId": 29736, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "decimals", "offset": 2, @@ -1620,7 +1948,7 @@ "type": "t_uint8" }, { - "astId": 46062, + "astId": 29738, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "allowedOracleSlippageBps", "offset": 3, @@ -1630,12 +1958,12 @@ ], "numberOfBytes": "32" }, - "t_struct(Strategy)46078_storage": { + "t_struct(Strategy)29754_storage": { "encoding": "inplace", "label": "struct VaultStorage.Strategy", "members": [ { - "astId": 46075, + "astId": 29751, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "isSupported", "offset": 0, @@ -1643,7 +1971,7 @@ "type": "t_bool" }, { - "astId": 46077, + "astId": 29753, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "_deprecated", "offset": 0, @@ -1653,12 +1981,12 @@ ], "numberOfBytes": "64" }, - "t_struct(SwapConfig)46184_storage": { + "t_struct(SwapConfig)29860_storage": { "encoding": "inplace", "label": "struct VaultStorage.SwapConfig", "members": [ { - "astId": 46181, + "astId": 29857, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "swapper", "offset": 0, @@ -1666,7 +1994,7 @@ "type": "t_address" }, { - "astId": 46183, + "astId": 29859, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "allowedUndervalueBps", "offset": 20, @@ -1676,6 +2004,89 @@ ], "numberOfBytes": "32" }, + "t_struct(WithdrawalQueueMetadata)29882_storage": { + "encoding": "inplace", + "label": "struct VaultStorage.WithdrawalQueueMetadata", + "members": [ + { + "astId": 29875, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "queued", + "offset": 0, + "slot": "0", + "type": "t_uint128" + }, + { + "astId": 29877, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "claimable", + "offset": 16, + "slot": "0", + "type": "t_uint128" + }, + { + "astId": 29879, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "claimed", + "offset": 0, + "slot": "1", + "type": "t_uint128" + }, + { + "astId": 29881, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "nextWithdrawalIndex", + "offset": 16, + "slot": "1", + "type": "t_uint128" + } + ], + "numberOfBytes": "64" + }, + "t_struct(WithdrawalRequest)29894_storage": { + "encoding": "inplace", + "label": "struct VaultStorage.WithdrawalRequest", + "members": [ + { + "astId": 29887, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "withdrawer", + "offset": 0, + "slot": "0", + "type": "t_address" + }, + { + "astId": 29889, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "claimed", + "offset": 20, + "slot": "0", + "type": "t_bool" + }, + { + "astId": 29891, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "amount", + "offset": 0, + "slot": "1", + "type": "t_uint128" + }, + { + "astId": 29893, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "queued", + "offset": 16, + "slot": "1", + "type": "t_uint128" + } + ], + "numberOfBytes": "64" + }, + "t_uint128": { + "encoding": "inplace", + "label": "uint128", + "numberOfBytes": "16" + }, "t_uint16": { "encoding": "inplace", "label": "uint16", diff --git a/contracts/deployments/holesky/solcInputs/9b811e7a632431f9f724307daee2b897.json b/contracts/deployments/holesky/solcInputs/9b811e7a632431f9f724307daee2b897.json new file mode 100644 index 0000000000..fcd56c8ae6 --- /dev/null +++ b/contracts/deployments/holesky/solcInputs/9b811e7a632431f9f724307daee2b897.json @@ -0,0 +1,344 @@ +{ + "language": "Solidity", + "sources": { + "@openzeppelin/contracts/security/Pausable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (security/Pausable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which allows children to implement an emergency stop\n * mechanism that can be triggered by an authorized account.\n *\n * This module is used through inheritance. It will make available the\n * modifiers `whenNotPaused` and `whenPaused`, which can be applied to\n * the functions of your contract. Note that they will not be pausable by\n * simply including this module, only once the modifiers are put in place.\n */\nabstract contract Pausable is Context {\n /**\n * @dev Emitted when the pause is triggered by `account`.\n */\n event Paused(address account);\n\n /**\n * @dev Emitted when the pause is lifted by `account`.\n */\n event Unpaused(address account);\n\n bool private _paused;\n\n /**\n * @dev Initializes the contract in unpaused state.\n */\n constructor() {\n _paused = false;\n }\n\n /**\n * @dev Returns true if the contract is paused, and false otherwise.\n */\n function paused() public view virtual returns (bool) {\n return _paused;\n }\n\n /**\n * @dev Modifier to make a function callable only when the contract is not paused.\n *\n * Requirements:\n *\n * - The contract must not be paused.\n */\n modifier whenNotPaused() {\n require(!paused(), \"Pausable: paused\");\n _;\n }\n\n /**\n * @dev Modifier to make a function callable only when the contract is paused.\n *\n * Requirements:\n *\n * - The contract must be paused.\n */\n modifier whenPaused() {\n require(paused(), \"Pausable: not paused\");\n _;\n }\n\n /**\n * @dev Triggers stopped state.\n *\n * Requirements:\n *\n * - The contract must not be paused.\n */\n function _pause() internal virtual whenNotPaused {\n _paused = true;\n emit Paused(_msgSender());\n }\n\n /**\n * @dev Returns to normal state.\n *\n * Requirements:\n *\n * - The contract must be paused.\n */\n function _unpause() internal virtual whenPaused {\n _paused = false;\n emit Unpaused(_msgSender());\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/ERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `recipient` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address recipient, uint256 amount) public virtual override returns (bool) {\n _transfer(_msgSender(), recipient, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n _approve(_msgSender(), spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * Requirements:\n *\n * - `sender` and `recipient` cannot be the zero address.\n * - `sender` must have a balance of at least `amount`.\n * - the caller must have allowance for ``sender``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) public virtual override returns (bool) {\n _transfer(sender, recipient, amount);\n\n uint256 currentAllowance = _allowances[sender][_msgSender()];\n require(currentAllowance >= amount, \"ERC20: transfer amount exceeds allowance\");\n unchecked {\n _approve(sender, _msgSender(), currentAllowance - amount);\n }\n\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n _approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n uint256 currentAllowance = _allowances[_msgSender()][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(_msgSender(), spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `sender` cannot be the zero address.\n * - `recipient` cannot be the zero address.\n * - `sender` must have a balance of at least `amount`.\n */\n function _transfer(\n address sender,\n address recipient,\n uint256 amount\n ) internal virtual {\n require(sender != address(0), \"ERC20: transfer from the zero address\");\n require(recipient != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(sender, recipient, amount);\n\n uint256 senderBalance = _balances[sender];\n require(senderBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[sender] = senderBalance - amount;\n }\n _balances[recipient] += amount;\n\n emit Transfer(sender, recipient, amount);\n\n _afterTokenTransfer(sender, recipient, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/IERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address recipient, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length > 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721Receiver.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @title ERC721 token receiver interface\n * @dev Interface for any contract that wants to support safeTransfers\n * from ERC721 asset contracts.\n */\ninterface IERC721Receiver {\n /**\n * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}\n * by `operator` from `from`, this function is called.\n *\n * It must return its Solidity selector to confirm the token transfer.\n * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.\n *\n * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`.\n */\n function onERC721Received(\n address operator,\n address from,\n uint256 tokenId,\n bytes calldata data\n ) external returns (bytes4);\n}\n" + }, + "@openzeppelin/contracts/utils/Address.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Address.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize, which returns 0 for contracts in\n // construction, since the code is only stored at the end of the\n // constructor execution.\n\n uint256 size;\n assembly {\n size := extcodesize(account)\n }\n return size > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCall(target, data, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(isContract(target), \"Address: delegate call to non-contract\");\n\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Context.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/math/Math.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/Math.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n /**\n * @dev Returns the largest of two numbers.\n */\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\n return a >= b ? a : b;\n }\n\n /**\n * @dev Returns the smallest of two numbers.\n */\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\n return a < b ? a : b;\n }\n\n /**\n * @dev Returns the average of two numbers. The result is rounded towards\n * zero.\n */\n function average(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b) / 2 can overflow.\n return (a & b) + (a ^ b) / 2;\n }\n\n /**\n * @dev Returns the ceiling of the division of two numbers.\n *\n * This differs from standard division with `/` in that it rounds up instead\n * of rounding down.\n */\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b - 1) / b can overflow on addition, so we distribute.\n return a / b + (a % b == 0 ? 0 : 1);\n }\n}\n" + }, + "@openzeppelin/contracts/utils/math/SafeMath.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Strings.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" + }, + "contracts/governance/Governable.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title Base for contracts that are managed by the Origin Protocol's Governor.\n * @dev Copy of the openzeppelin Ownable.sol contract with nomenclature change\n * from owner to governor and renounce methods removed. Does not use\n * Context.sol like Ownable.sol does for simplification.\n * @author Origin Protocol Inc\n */\ncontract Governable {\n // Storage position of the owner and pendingOwner of the contract\n // keccak256(\"OUSD.governor\");\n bytes32 private constant governorPosition =\n 0x7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a;\n\n // keccak256(\"OUSD.pending.governor\");\n bytes32 private constant pendingGovernorPosition =\n 0x44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db;\n\n // keccak256(\"OUSD.reentry.status\");\n bytes32 private constant reentryStatusPosition =\n 0x53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac4535;\n\n // See OpenZeppelin ReentrancyGuard implementation\n uint256 constant _NOT_ENTERED = 1;\n uint256 constant _ENTERED = 2;\n\n event PendingGovernorshipTransfer(\n address indexed previousGovernor,\n address indexed newGovernor\n );\n\n event GovernorshipTransferred(\n address indexed previousGovernor,\n address indexed newGovernor\n );\n\n /**\n * @dev Initializes the contract setting the deployer as the initial Governor.\n */\n constructor() {\n _setGovernor(msg.sender);\n emit GovernorshipTransferred(address(0), _governor());\n }\n\n /**\n * @notice Returns the address of the current Governor.\n */\n function governor() public view returns (address) {\n return _governor();\n }\n\n /**\n * @dev Returns the address of the current Governor.\n */\n function _governor() internal view returns (address governorOut) {\n bytes32 position = governorPosition;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n governorOut := sload(position)\n }\n }\n\n /**\n * @dev Returns the address of the pending Governor.\n */\n function _pendingGovernor()\n internal\n view\n returns (address pendingGovernor)\n {\n bytes32 position = pendingGovernorPosition;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n pendingGovernor := sload(position)\n }\n }\n\n /**\n * @dev Throws if called by any account other than the Governor.\n */\n modifier onlyGovernor() {\n require(isGovernor(), \"Caller is not the Governor\");\n _;\n }\n\n /**\n * @notice Returns true if the caller is the current Governor.\n */\n function isGovernor() public view returns (bool) {\n return msg.sender == _governor();\n }\n\n function _setGovernor(address newGovernor) internal {\n bytes32 position = governorPosition;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n sstore(position, newGovernor)\n }\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a `nonReentrant` function from another `nonReentrant`\n * function is not supported. It is possible to prevent this from happening\n * by making the `nonReentrant` function external, and make it call a\n * `private` function that does the actual work.\n */\n modifier nonReentrant() {\n bytes32 position = reentryStatusPosition;\n uint256 _reentry_status;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n _reentry_status := sload(position)\n }\n\n // On the first call to nonReentrant, _notEntered will be true\n require(_reentry_status != _ENTERED, \"Reentrant call\");\n\n // Any calls to nonReentrant after this point will fail\n // solhint-disable-next-line no-inline-assembly\n assembly {\n sstore(position, _ENTERED)\n }\n\n _;\n\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n // solhint-disable-next-line no-inline-assembly\n assembly {\n sstore(position, _NOT_ENTERED)\n }\n }\n\n function _setPendingGovernor(address newGovernor) internal {\n bytes32 position = pendingGovernorPosition;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n sstore(position, newGovernor)\n }\n }\n\n /**\n * @notice Transfers Governance of the contract to a new account (`newGovernor`).\n * Can only be called by the current Governor. Must be claimed for this to complete\n * @param _newGovernor Address of the new Governor\n */\n function transferGovernance(address _newGovernor) external onlyGovernor {\n _setPendingGovernor(_newGovernor);\n emit PendingGovernorshipTransfer(_governor(), _newGovernor);\n }\n\n /**\n * @notice Claim Governance of the contract to a new account (`newGovernor`).\n * Can only be called by the new Governor.\n */\n function claimGovernance() external {\n require(\n msg.sender == _pendingGovernor(),\n \"Only the pending Governor can complete the claim\"\n );\n _changeGovernor(msg.sender);\n }\n\n /**\n * @dev Change Governance of the contract to a new account (`newGovernor`).\n * @param _newGovernor Address of the new Governor\n */\n function _changeGovernor(address _newGovernor) internal {\n require(_newGovernor != address(0), \"New Governor is address(0)\");\n emit GovernorshipTransferred(_governor(), _newGovernor);\n _setGovernor(_newGovernor);\n }\n}\n" + }, + "contracts/harvest/BaseHarvester.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { SafeMath } from \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/Math.sol\";\n\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { IOracle } from \"../interfaces/IOracle.sol\";\nimport { IStrategy } from \"../interfaces/IStrategy.sol\";\nimport { IUniswapV2Router } from \"../interfaces/uniswap/IUniswapV2Router02.sol\";\nimport { IUniswapV3Router } from \"../interfaces/uniswap/IUniswapV3Router.sol\";\nimport { IBalancerVault } from \"../interfaces/balancer/IBalancerVault.sol\";\nimport { ICurvePool } from \"../strategies/ICurvePool.sol\";\nimport \"../utils/Helpers.sol\";\n\nabstract contract BaseHarvester is Governable {\n using SafeERC20 for IERC20;\n using SafeMath for uint256;\n using StableMath for uint256;\n\n enum SwapPlatform {\n UniswapV2Compatible,\n UniswapV3,\n Balancer,\n Curve\n }\n\n event SupportedStrategyUpdate(address strategyAddress, bool isSupported);\n event RewardTokenConfigUpdated(\n address tokenAddress,\n uint16 allowedSlippageBps,\n uint16 harvestRewardBps,\n SwapPlatform swapPlatform,\n address swapPlatformAddr,\n bytes swapData,\n uint256 liquidationLimit,\n bool doSwapRewardToken\n );\n event RewardTokenSwapped(\n address indexed rewardToken,\n address indexed swappedInto,\n SwapPlatform swapPlatform,\n uint256 amountIn,\n uint256 amountOut\n );\n event RewardProceedsTransferred(\n address indexed token,\n address farmer,\n uint256 protcolYield,\n uint256 farmerFee\n );\n event RewardProceedsAddressChanged(address newProceedsAddress);\n\n error EmptyAddress();\n error InvalidSlippageBps();\n error InvalidHarvestRewardBps();\n\n error InvalidSwapPlatform(SwapPlatform swapPlatform);\n\n error InvalidUniswapV2PathLength();\n error InvalidTokenInSwapPath(address token);\n error EmptyBalancerPoolId();\n error InvalidCurvePoolAssetIndex(address token);\n\n error UnsupportedStrategy(address strategyAddress);\n\n error SlippageError(uint256 actualBalance, uint256 minExpected);\n error BalanceMismatchAfterSwap(uint256 actualBalance, uint256 minExpected);\n\n // Configuration properties for harvesting logic of reward tokens\n struct RewardTokenConfig {\n // Max allowed slippage when swapping reward token for a stablecoin denominated in basis points.\n uint16 allowedSlippageBps;\n // Reward when calling a harvest function denominated in basis points.\n uint16 harvestRewardBps;\n // Address of compatible exchange protocol (Uniswap V2/V3, SushiSwap, Balancer and Curve).\n address swapPlatformAddr;\n /* When true the reward token is being swapped. In a need of (temporarily) disabling the swapping of\n * a reward token this needs to be set to false.\n */\n bool doSwapRewardToken;\n // Platform to use for Swapping\n SwapPlatform swapPlatform;\n /* How much token can be sold per one harvest call. If the balance of rewards tokens\n * exceeds that limit multiple harvest calls are required to harvest all of the tokens.\n * Set it to MAX_INT to effectively disable the limit.\n */\n uint256 liquidationLimit;\n }\n\n mapping(address => RewardTokenConfig) public rewardTokenConfigs;\n mapping(address => bool) public supportedStrategies;\n\n address public immutable vaultAddress;\n\n /**\n * Address receiving rewards proceeds. Initially the Vault contract later will possibly\n * be replaced by another contract that eases out rewards distribution.\n **/\n address public rewardProceedsAddress;\n\n /**\n * All tokens are swapped to this token before it gets transferred\n * to the `rewardProceedsAddress`. USDT for OUSD and WETH for OETH.\n **/\n address public immutable baseTokenAddress;\n // Cached decimals for `baseTokenAddress`\n uint256 public immutable baseTokenDecimals;\n\n // Uniswap V2 path for reward tokens using Uniswap V2 Router\n mapping(address => address[]) public uniswapV2Path;\n // Uniswap V3 path for reward tokens using Uniswap V3 Router\n mapping(address => bytes) public uniswapV3Path;\n // Pool ID to use for reward tokens on Balancer\n mapping(address => bytes32) public balancerPoolId;\n\n struct CurvePoolIndices {\n // Casted into uint128 and stored in a struct to save gas\n uint128 rewardTokenIndex;\n uint128 baseTokenIndex;\n }\n // Packed indices of assets on the Curve pool\n mapping(address => CurvePoolIndices) public curvePoolIndices;\n\n constructor(address _vaultAddress, address _baseTokenAddress) {\n require(_vaultAddress != address(0));\n require(_baseTokenAddress != address(0));\n\n vaultAddress = _vaultAddress;\n baseTokenAddress = _baseTokenAddress;\n\n // Cache decimals as well\n baseTokenDecimals = Helpers.getDecimals(_baseTokenAddress);\n }\n\n /***************************************\n Configuration\n ****************************************/\n\n /**\n * Set the Address receiving rewards proceeds.\n * @param _rewardProceedsAddress Address of the reward token\n */\n function setRewardProceedsAddress(address _rewardProceedsAddress)\n external\n onlyGovernor\n {\n if (_rewardProceedsAddress == address(0)) {\n revert EmptyAddress();\n }\n\n rewardProceedsAddress = _rewardProceedsAddress;\n emit RewardProceedsAddressChanged(_rewardProceedsAddress);\n }\n\n /**\n * @dev Add/update a reward token configuration that holds harvesting config variables\n * @param _tokenAddress Address of the reward token\n * @param tokenConfig.allowedSlippageBps uint16 maximum allowed slippage denominated in basis points.\n * Example: 300 == 3% slippage\n * @param tokenConfig.harvestRewardBps uint16 amount of reward tokens the caller of the function is rewarded.\n * Example: 100 == 1%\n * @param tokenConfig.swapPlatformAddr Address Address of a UniswapV2 compatible contract to perform\n * the exchange from reward tokens to stablecoin (currently hard-coded to USDT)\n * @param tokenConfig.liquidationLimit uint256 Maximum amount of token to be sold per one swap function call.\n * When value is 0 there is no limit.\n * @param tokenConfig.doSwapRewardToken bool Disables swapping of the token when set to true,\n * does not cause it to revert though.\n * @param tokenConfig.swapPlatform SwapPlatform to use for Swapping\n * @param swapData Additional data required for swapping\n */\n function setRewardTokenConfig(\n address _tokenAddress,\n RewardTokenConfig calldata tokenConfig,\n bytes calldata swapData\n ) external onlyGovernor {\n if (tokenConfig.allowedSlippageBps > 1000) {\n revert InvalidSlippageBps();\n }\n\n if (tokenConfig.harvestRewardBps > 1000) {\n revert InvalidHarvestRewardBps();\n }\n\n address newRouterAddress = tokenConfig.swapPlatformAddr;\n if (newRouterAddress == address(0)) {\n // Swap router address should be non zero address\n revert EmptyAddress();\n }\n\n address oldRouterAddress = rewardTokenConfigs[_tokenAddress]\n .swapPlatformAddr;\n rewardTokenConfigs[_tokenAddress] = tokenConfig;\n\n // Revert if feed does not exist\n // slither-disable-next-line unused-return\n IOracle(IVault(vaultAddress).priceProvider()).price(_tokenAddress);\n\n IERC20 token = IERC20(_tokenAddress);\n // if changing token swap provider cancel existing allowance\n if (\n /* oldRouterAddress == address(0) when there is no pre-existing\n * configuration for said rewards token\n */\n oldRouterAddress != address(0) &&\n oldRouterAddress != newRouterAddress\n ) {\n token.safeApprove(oldRouterAddress, 0);\n }\n\n // Give SwapRouter infinite approval when needed\n if (oldRouterAddress != newRouterAddress) {\n token.safeApprove(newRouterAddress, 0);\n token.safeApprove(newRouterAddress, type(uint256).max);\n }\n\n SwapPlatform _platform = tokenConfig.swapPlatform;\n if (_platform == SwapPlatform.UniswapV2Compatible) {\n uniswapV2Path[_tokenAddress] = _decodeUniswapV2Path(\n swapData,\n _tokenAddress\n );\n } else if (_platform == SwapPlatform.UniswapV3) {\n uniswapV3Path[_tokenAddress] = _decodeUniswapV3Path(\n swapData,\n _tokenAddress\n );\n } else if (_platform == SwapPlatform.Balancer) {\n balancerPoolId[_tokenAddress] = _decodeBalancerPoolId(\n swapData,\n newRouterAddress,\n _tokenAddress\n );\n } else if (_platform == SwapPlatform.Curve) {\n curvePoolIndices[_tokenAddress] = _decodeCurvePoolIndices(\n swapData,\n newRouterAddress,\n _tokenAddress\n );\n } else {\n // Note: This code is unreachable since Solidity reverts when\n // the value is outside the range of defined values of the enum\n // (even if it's under the max length of the base type)\n revert InvalidSwapPlatform(_platform);\n }\n\n emit RewardTokenConfigUpdated(\n _tokenAddress,\n tokenConfig.allowedSlippageBps,\n tokenConfig.harvestRewardBps,\n _platform,\n newRouterAddress,\n swapData,\n tokenConfig.liquidationLimit,\n tokenConfig.doSwapRewardToken\n );\n }\n\n /**\n * @dev Decodes the data passed into Uniswap V2 path and validates\n * it to make sure the path is for `token` to `baseToken`\n *\n * @param data Ecnoded data passed to the `setRewardTokenConfig`\n * @param token The address of the reward token\n * @return path The validated Uniswap V2 path\n */\n function _decodeUniswapV2Path(bytes calldata data, address token)\n internal\n view\n returns (address[] memory path)\n {\n (path) = abi.decode(data, (address[]));\n uint256 len = path.length;\n\n if (len < 2) {\n // Path should have at least two tokens\n revert InvalidUniswapV2PathLength();\n }\n\n // Do some validation\n if (path[0] != token) {\n revert InvalidTokenInSwapPath(path[0]);\n }\n\n if (path[len - 1] != baseTokenAddress) {\n revert InvalidTokenInSwapPath(path[len - 1]);\n }\n }\n\n /**\n * @dev Decodes the data passed into Uniswap V3 path and validates\n * it to make sure the path is for `token` to `baseToken`\n *\n * @param data Ecnoded data passed to the `setRewardTokenConfig`\n * @param token The address of the reward token\n * @return path The validated Uniswap V3 path\n */\n function _decodeUniswapV3Path(bytes calldata data, address token)\n internal\n view\n returns (bytes calldata path)\n {\n path = data;\n\n address decodedAddress = address(uint160(bytes20(data[0:20])));\n\n if (decodedAddress != token) {\n // Invalid Reward Token in swap path\n revert InvalidTokenInSwapPath(decodedAddress);\n }\n\n decodedAddress = address(uint160(bytes20(data[path.length - 20:])));\n if (decodedAddress != baseTokenAddress) {\n // Invalid Base Token in swap path\n revert InvalidTokenInSwapPath(decodedAddress);\n }\n }\n\n /**\n * @dev Decodes the data passed to Balancer Pool ID\n *\n * @param data Ecnoded data passed to the `setRewardTokenConfig`\n * @return poolId The pool ID\n */\n function _decodeBalancerPoolId(\n bytes calldata data,\n address balancerVault,\n address token\n ) internal view returns (bytes32 poolId) {\n (poolId) = abi.decode(data, (bytes32));\n\n if (poolId == bytes32(0)) {\n revert EmptyBalancerPoolId();\n }\n\n IBalancerVault bVault = IBalancerVault(balancerVault);\n\n // Note: this reverts if token is not a pool asset\n // slither-disable-next-line unused-return\n bVault.getPoolTokenInfo(poolId, token);\n\n // slither-disable-next-line unused-return\n bVault.getPoolTokenInfo(poolId, baseTokenAddress);\n }\n\n /**\n * @dev Decodes the data passed to get the pool indices and\n * checks it against the Curve Pool to make sure it's\n * not misconfigured. The indices are packed into a single\n * uint256 for gas savings\n *\n * @param data Ecnoded data passed to the `setRewardTokenConfig`\n * @param poolAddress Curve pool address\n * @param token The address of the reward token\n * @return indices Packed pool asset indices\n */\n function _decodeCurvePoolIndices(\n bytes calldata data,\n address poolAddress,\n address token\n ) internal view returns (CurvePoolIndices memory indices) {\n indices = abi.decode(data, (CurvePoolIndices));\n\n ICurvePool pool = ICurvePool(poolAddress);\n if (token != pool.coins(indices.rewardTokenIndex)) {\n revert InvalidCurvePoolAssetIndex(token);\n }\n if (baseTokenAddress != pool.coins(indices.baseTokenIndex)) {\n revert InvalidCurvePoolAssetIndex(baseTokenAddress);\n }\n }\n\n /**\n * @dev Flags a strategy as supported or not supported one\n * @param _strategyAddress Address of the strategy\n * @param _isSupported Bool marking strategy as supported or not supported\n */\n function setSupportedStrategy(address _strategyAddress, bool _isSupported)\n external\n onlyGovernor\n {\n supportedStrategies[_strategyAddress] = _isSupported;\n emit SupportedStrategyUpdate(_strategyAddress, _isSupported);\n }\n\n /***************************************\n Rewards\n ****************************************/\n\n /**\n * @dev Transfer token to governor. Intended for recovering tokens stuck in\n * contract, i.e. mistaken sends.\n * @param _asset Address for the asset\n * @param _amount Amount of the asset to transfer\n */\n function transferToken(address _asset, uint256 _amount)\n external\n onlyGovernor\n {\n IERC20(_asset).safeTransfer(governor(), _amount);\n }\n\n /**\n * @dev Collect reward tokens from a specific strategy and swap them for\n * base token on the configured swap platform. Can be called by anyone.\n * Rewards incentivizing the caller are sent to the caller of this function.\n * @param _strategyAddr Address of the strategy to collect rewards from\n */\n function harvestAndSwap(address _strategyAddr) external nonReentrant {\n // Remember _harvest function checks for the validity of _strategyAddr\n _harvestAndSwap(_strategyAddr, msg.sender);\n }\n\n /**\n * @dev Collect reward tokens from a specific strategy and swap them for\n * base token on the configured swap platform. Can be called by anyone\n * @param _strategyAddr Address of the strategy to collect rewards from\n * @param _rewardTo Address where to send a share of harvest rewards to as an incentive\n * for executing this function\n */\n function harvestAndSwap(address _strategyAddr, address _rewardTo)\n external\n nonReentrant\n {\n // Remember _harvest function checks for the validity of _strategyAddr\n _harvestAndSwap(_strategyAddr, _rewardTo);\n }\n\n /**\n * @dev Collect reward tokens from a specific strategy and swap them for\n * base token on the configured swap platform\n * @param _strategyAddr Address of the strategy to collect rewards from\n * @param _rewardTo Address where to send a share of harvest rewards to as an incentive\n * for executing this function\n */\n function _harvestAndSwap(address _strategyAddr, address _rewardTo)\n internal\n {\n _harvest(_strategyAddr);\n IStrategy strategy = IStrategy(_strategyAddr);\n address[] memory rewardTokens = strategy.getRewardTokenAddresses();\n IOracle priceProvider = IOracle(IVault(vaultAddress).priceProvider());\n uint256 len = rewardTokens.length;\n for (uint256 i = 0; i < len; ++i) {\n _swap(rewardTokens[i], _rewardTo, priceProvider);\n }\n }\n\n /**\n * @dev Collect reward tokens from a specific strategy and swap them for\n * base token on the configured swap platform\n * @param _strategyAddr Address of the strategy to collect rewards from.\n */\n function _harvest(address _strategyAddr) internal {\n if (!supportedStrategies[_strategyAddr]) {\n revert UnsupportedStrategy(_strategyAddr);\n }\n\n IStrategy strategy = IStrategy(_strategyAddr);\n strategy.collectRewardTokens();\n }\n\n /**\n * @dev Swap a reward token for the base token on the configured\n * swap platform. The token must have a registered price feed\n * with the price provider\n * @param _swapToken Address of the token to swap\n * @param _rewardTo Address where to send the share of harvest rewards to\n * @param _priceProvider Oracle to get prices of the swap token\n */\n function _swap(\n address _swapToken,\n address _rewardTo,\n IOracle _priceProvider\n ) internal virtual {\n uint256 balance = IERC20(_swapToken).balanceOf(address(this));\n\n // No need to swap if the reward token is the base token. eg USDT or WETH.\n // There is also no limit on the transfer. Everything in the harvester will be transferred\n // to the Dripper regardless of the liquidationLimit config.\n if (_swapToken == baseTokenAddress) {\n IERC20(_swapToken).safeTransfer(rewardProceedsAddress, balance);\n // currently not paying the farmer any rewards as there is no swap\n emit RewardProceedsTransferred(\n baseTokenAddress,\n address(0),\n balance,\n 0\n );\n return;\n }\n\n RewardTokenConfig memory tokenConfig = rewardTokenConfigs[_swapToken];\n\n /* This will trigger a return when reward token configuration has not yet been set\n * or we have temporarily disabled swapping of specific reward token via setting\n * doSwapRewardToken to false.\n */\n if (!tokenConfig.doSwapRewardToken) {\n return;\n }\n\n if (balance == 0) {\n return;\n }\n\n if (tokenConfig.liquidationLimit > 0) {\n balance = Math.min(balance, tokenConfig.liquidationLimit);\n }\n\n // This'll revert if there is no price feed\n uint256 oraclePrice = _priceProvider.price(_swapToken);\n\n // Oracle price is 1e18\n uint256 minExpected = (balance *\n (1e4 - tokenConfig.allowedSlippageBps) * // max allowed slippage\n oraclePrice).scaleBy(\n baseTokenDecimals,\n Helpers.getDecimals(_swapToken)\n ) /\n 1e4 / // fix the max slippage decimal position\n 1e18; // and oracle price decimals position\n\n // Do the swap\n uint256 amountReceived = _doSwap(\n tokenConfig.swapPlatform,\n tokenConfig.swapPlatformAddr,\n _swapToken,\n balance,\n minExpected\n );\n\n if (amountReceived < minExpected) {\n revert SlippageError(amountReceived, minExpected);\n }\n\n emit RewardTokenSwapped(\n _swapToken,\n baseTokenAddress,\n tokenConfig.swapPlatform,\n balance,\n amountReceived\n );\n\n IERC20 baseToken = IERC20(baseTokenAddress);\n uint256 baseTokenBalance = baseToken.balanceOf(address(this));\n if (baseTokenBalance < amountReceived) {\n // Note: It's possible to bypass this check by transferring `baseToken`\n // directly to Harvester before calling the `harvestAndSwap`. However,\n // there's no incentive for an attacker to do that. Doing a balance diff\n // will increase the gas cost significantly\n revert BalanceMismatchAfterSwap(baseTokenBalance, amountReceived);\n }\n\n // Farmer only gets fee from the base amount they helped farm,\n // They do not get anything from anything that already was there\n // on the Harvester\n uint256 farmerFee = amountReceived.mulTruncateScale(\n tokenConfig.harvestRewardBps,\n 1e4\n );\n uint256 protocolYield = baseTokenBalance - farmerFee;\n\n baseToken.safeTransfer(rewardProceedsAddress, protocolYield);\n baseToken.safeTransfer(_rewardTo, farmerFee);\n emit RewardProceedsTransferred(\n baseTokenAddress,\n _rewardTo,\n protocolYield,\n farmerFee\n );\n }\n\n function _doSwap(\n SwapPlatform swapPlatform,\n address routerAddress,\n address rewardTokenAddress,\n uint256 amountIn,\n uint256 minAmountOut\n ) internal returns (uint256 amountOut) {\n if (swapPlatform == SwapPlatform.UniswapV2Compatible) {\n return\n _swapWithUniswapV2(\n routerAddress,\n rewardTokenAddress,\n amountIn,\n minAmountOut\n );\n } else if (swapPlatform == SwapPlatform.UniswapV3) {\n return\n _swapWithUniswapV3(\n routerAddress,\n rewardTokenAddress,\n amountIn,\n minAmountOut\n );\n } else if (swapPlatform == SwapPlatform.Balancer) {\n return\n _swapWithBalancer(\n routerAddress,\n rewardTokenAddress,\n amountIn,\n minAmountOut\n );\n } else if (swapPlatform == SwapPlatform.Curve) {\n return\n _swapWithCurve(\n routerAddress,\n rewardTokenAddress,\n amountIn,\n minAmountOut\n );\n } else {\n // Should never be invoked since we catch invalid values\n // in the `setRewardTokenConfig` function before it's set\n revert InvalidSwapPlatform(swapPlatform);\n }\n }\n\n /**\n * @dev Swaps the token to `baseToken` with Uniswap V2\n *\n * @param routerAddress Uniswap V2 Router address\n * @param swapToken Address of the tokenIn\n * @param amountIn Amount of `swapToken` to swap\n * @param minAmountOut Minimum expected amount of `baseToken`\n *\n * @return amountOut Amount of `baseToken` received after the swap\n */\n function _swapWithUniswapV2(\n address routerAddress,\n address swapToken,\n uint256 amountIn,\n uint256 minAmountOut\n ) internal returns (uint256 amountOut) {\n address[] memory path = uniswapV2Path[swapToken];\n\n uint256[] memory amounts = IUniswapV2Router(routerAddress)\n .swapExactTokensForTokens(\n amountIn,\n minAmountOut,\n path,\n address(this),\n block.timestamp\n );\n\n amountOut = amounts[amounts.length - 1];\n }\n\n /**\n * @dev Swaps the token to `baseToken` with Uniswap V3\n *\n * @param routerAddress Uniswap V3 Router address\n * @param swapToken Address of the tokenIn\n * @param amountIn Amount of `swapToken` to swap\n * @param minAmountOut Minimum expected amount of `baseToken`\n *\n * @return amountOut Amount of `baseToken` received after the swap\n */\n function _swapWithUniswapV3(\n address routerAddress,\n address swapToken,\n uint256 amountIn,\n uint256 minAmountOut\n ) internal returns (uint256 amountOut) {\n bytes memory path = uniswapV3Path[swapToken];\n\n IUniswapV3Router.ExactInputParams memory params = IUniswapV3Router\n .ExactInputParams({\n path: path,\n recipient: address(this),\n deadline: block.timestamp,\n amountIn: amountIn,\n amountOutMinimum: minAmountOut\n });\n amountOut = IUniswapV3Router(routerAddress).exactInput(params);\n }\n\n /**\n * @dev Swaps the token to `baseToken` on Balancer\n *\n * @param balancerVaultAddress BalancerVaultAddress\n * @param swapToken Address of the tokenIn\n * @param amountIn Amount of `swapToken` to swap\n * @param minAmountOut Minimum expected amount of `baseToken`\n *\n * @return amountOut Amount of `baseToken` received after the swap\n */\n function _swapWithBalancer(\n address balancerVaultAddress,\n address swapToken,\n uint256 amountIn,\n uint256 minAmountOut\n ) internal returns (uint256 amountOut) {\n bytes32 poolId = balancerPoolId[swapToken];\n\n IBalancerVault.SingleSwap memory singleSwap = IBalancerVault\n .SingleSwap({\n poolId: poolId,\n kind: IBalancerVault.SwapKind.GIVEN_IN,\n assetIn: swapToken,\n assetOut: baseTokenAddress,\n amount: amountIn,\n userData: hex\"\"\n });\n\n IBalancerVault.FundManagement memory fundMgmt = IBalancerVault\n .FundManagement({\n sender: address(this),\n fromInternalBalance: false,\n recipient: payable(address(this)),\n toInternalBalance: false\n });\n\n amountOut = IBalancerVault(balancerVaultAddress).swap(\n singleSwap,\n fundMgmt,\n minAmountOut,\n block.timestamp\n );\n }\n\n /**\n * @dev Swaps the token to `baseToken` on Curve\n *\n * @param poolAddress Curve Pool Address\n * @param swapToken Address of the tokenIn\n * @param amountIn Amount of `swapToken` to swap\n * @param minAmountOut Minimum expected amount of `baseToken`\n *\n * @return amountOut Amount of `baseToken` received after the swap\n */\n function _swapWithCurve(\n address poolAddress,\n address swapToken,\n uint256 amountIn,\n uint256 minAmountOut\n ) internal returns (uint256 amountOut) {\n CurvePoolIndices memory indices = curvePoolIndices[swapToken];\n\n // Note: Not all CurvePools return the `amountOut`, make sure\n // to use only pool that do. Otherwise the swap would revert\n // always\n amountOut = ICurvePool(poolAddress).exchange(\n uint256(indices.rewardTokenIndex),\n uint256(indices.baseTokenIndex),\n amountIn,\n minAmountOut\n );\n }\n}\n" + }, + "contracts/harvest/Dripper.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\n\n/**\n * @title OUSD Dripper\n *\n * The dripper contract smooths out the yield from point-in-time yield events\n * and spreads the yield out over a configurable time period. This ensures a\n * continuous per block yield to makes users happy as their next rebase\n * amount is always moving up. Also, this makes historical day to day yields\n * smooth, rather than going from a near zero day, to a large APY day, then\n * back to a near zero day again.\n *\n *\n * Design notes\n * - USDT has a smaller resolution than the number of seconds\n * in a week, which can make per block payouts have a rounding error. However\n * the total effect is not large - cents per day, and this money is\n * not lost, just distributed in the future. While we could use a higher\n * decimal precision for the drip perBlock, we chose simpler code.\n * - By calculating the changing drip rates on collects only, harvests and yield\n * events don't have to call anything on this contract or pay any extra gas.\n * Collect() is already be paying for a single write, since it has to reset\n * the lastCollect time.\n * - By having a collectAndRebase method, and having our external systems call\n * that, the OUSD vault does not need any changes, not even to know the address\n * of the dripper.\n * - A rejected design was to retro-calculate the drip rate on each collect,\n * based on the balance at the time of the collect. While this would have\n * required less state, and would also have made the contract respond more quickly\n * to new income, it would break the predictability that is this contract's entire\n * purpose. If we did this, the amount of fundsAvailable() would make sharp increases\n * when funds were deposited.\n * - When the dripper recalculates the rate, it targets spending the balance over\n * the duration. This means that every time that collect is called, if no\n * new funds have been deposited the duration is being pushed back and the\n * rate decreases. This is expected, and ends up following a smoother but\n * longer curve the more collect() is called without incoming yield.\n *\n */\n\ncontract Dripper is Governable {\n using SafeERC20 for IERC20;\n\n struct Drip {\n uint64 lastCollect; // overflows 262 billion years after the sun dies\n uint192 perBlock; // drip rate per block\n }\n\n address immutable vault; // OUSD vault\n address immutable token; // token to drip out\n uint256 public dripDuration; // in seconds\n Drip public drip; // active drip parameters\n\n constructor(address _vault, address _token) {\n vault = _vault;\n token = _token;\n }\n\n /// @notice How much funds have dripped out already and are currently\n // available to be sent to the vault.\n /// @return The amount that would be sent if a collect was called\n function availableFunds() external view returns (uint256) {\n uint256 balance = IERC20(token).balanceOf(address(this));\n return _availableFunds(balance, drip);\n }\n\n /// @notice Collect all dripped funds and send to vault.\n /// Recalculate new drip rate.\n function collect() external {\n _collect();\n }\n\n /// @notice Collect all dripped funds, send to vault, recalculate new drip\n /// rate, and rebase OUSD.\n function collectAndRebase() external {\n _collect();\n IVault(vault).rebase();\n }\n\n /// @dev Change the drip duration. Governor only.\n /// @param _durationSeconds the number of seconds to drip out the entire\n /// balance over if no collects were called during that time.\n function setDripDuration(uint256 _durationSeconds) external onlyGovernor {\n require(_durationSeconds > 0, \"duration must be non-zero\");\n dripDuration = _durationSeconds;\n _collect(); // duration change take immediate effect\n }\n\n /// @dev Transfer out ERC20 tokens held by the contract. Governor only.\n /// @param _asset ERC20 token address\n /// @param _amount amount to transfer\n function transferToken(address _asset, uint256 _amount)\n external\n onlyGovernor\n {\n IERC20(_asset).safeTransfer(governor(), _amount);\n }\n\n /// @dev Calculate available funds by taking the lower of either the\n /// currently dripped out funds or the balance available.\n /// Uses passed in parameters to calculate with for gas savings.\n /// @param _balance current balance in contract\n /// @param _drip current drip parameters\n function _availableFunds(uint256 _balance, Drip memory _drip)\n internal\n view\n returns (uint256)\n {\n uint256 elapsed = block.timestamp - _drip.lastCollect;\n uint256 allowed = (elapsed * _drip.perBlock);\n return (allowed > _balance) ? _balance : allowed;\n }\n\n /// @dev Sends the currently dripped funds to be vault, and sets\n /// the new drip rate based on the new balance.\n function _collect() internal {\n // Calculate send\n uint256 balance = IERC20(token).balanceOf(address(this));\n uint256 amountToSend = _availableFunds(balance, drip);\n uint256 remaining = balance - amountToSend;\n // Calculate new drip perBlock\n // Gas savings by setting entire struct at one time\n drip = Drip({\n perBlock: uint192(remaining / dripDuration),\n lastCollect: uint64(block.timestamp)\n });\n // Send funds\n IERC20(token).safeTransfer(vault, amountToSend);\n }\n}\n" + }, + "contracts/harvest/Harvester.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { BaseHarvester } from \"./BaseHarvester.sol\";\n\ncontract Harvester is BaseHarvester {\n constructor(address _vault, address _usdtAddress)\n BaseHarvester(_vault, _usdtAddress)\n {}\n}\n" + }, + "contracts/harvest/OETHDripper.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { Dripper } from \"./Dripper.sol\";\n\n/**\n * @title OETH Dripper Contract\n * @author Origin Protocol Inc\n */\ncontract OETHDripper is Dripper {\n constructor(address _vault, address _token) Dripper(_vault, _token) {}\n}\n" + }, + "contracts/harvest/OETHHarvester.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { BaseHarvester } from \"./BaseHarvester.sol\";\n\ncontract OETHHarvester is BaseHarvester {\n constructor(address _vault, address _wethAddress)\n BaseHarvester(_vault, _wethAddress)\n {}\n}\n" + }, + "contracts/interfaces/balancer/IBalancerVault.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"../../utils/InitializableAbstractStrategy.sol\";\n\ninterface IBalancerVault {\n enum WeightedPoolJoinKind {\n INIT,\n EXACT_TOKENS_IN_FOR_BPT_OUT,\n TOKEN_IN_FOR_EXACT_BPT_OUT,\n ALL_TOKENS_IN_FOR_EXACT_BPT_OUT,\n ADD_TOKEN\n }\n\n enum WeightedPoolExitKind {\n EXACT_BPT_IN_FOR_ONE_TOKEN_OUT,\n EXACT_BPT_IN_FOR_TOKENS_OUT,\n BPT_IN_FOR_EXACT_TOKENS_OUT,\n REMOVE_TOKEN\n }\n\n /**\n * @dev Called by users to join a Pool, which transfers tokens from `sender` into the Pool's balance. This will\n * trigger custom Pool behavior, which will typically grant something in return to `recipient` - often tokenized\n * Pool shares.\n *\n * If the caller is not `sender`, it must be an authorized relayer for them.\n *\n * The `assets` and `maxAmountsIn` arrays must have the same length, and each entry indicates the maximum amount\n * to send for each asset. The amounts to send are decided by the Pool and not the Vault: it just enforces\n * these maximums.\n *\n * If joining a Pool that holds WETH, it is possible to send ETH directly: the Vault will do the wrapping. To enable\n * this mechanism, the IAsset sentinel value (the zero address) must be passed in the `assets` array instead of the\n * WETH address. Note that it is not possible to combine ETH and WETH in the same join. Any excess ETH will be sent\n * back to the caller (not the sender, which is important for relayers).\n *\n * `assets` must have the same length and order as the array returned by `getPoolTokens`. This prevents issues when\n * interacting with Pools that register and deregister tokens frequently. If sending ETH however, the array must be\n * sorted *before* replacing the WETH address with the ETH sentinel value (the zero address), which means the final\n * `assets` array might not be sorted. Pools with no registered tokens cannot be joined.\n *\n * If `fromInternalBalance` is true, the caller's Internal Balance will be preferred: ERC20 transfers will only\n * be made for the difference between the requested amount and Internal Balance (if any). Note that ETH cannot be\n * withdrawn from Internal Balance: attempting to do so will trigger a revert.\n *\n * This causes the Vault to call the `IBasePool.onJoinPool` hook on the Pool's contract, where Pools implement\n * their own custom logic. This typically requires additional information from the user (such as the expected number\n * of Pool shares). This can be encoded in the `userData` argument, which is ignored by the Vault and passed\n * directly to the Pool's contract, as is `recipient`.\n *\n * Emits a `PoolBalanceChanged` event.\n */\n function joinPool(\n bytes32 poolId,\n address sender,\n address recipient,\n JoinPoolRequest memory request\n ) external payable;\n\n struct JoinPoolRequest {\n address[] assets;\n uint256[] maxAmountsIn;\n bytes userData;\n bool fromInternalBalance;\n }\n\n /**\n * @dev Called by users to exit a Pool, which transfers tokens from the Pool's balance to `recipient`. This will\n * trigger custom Pool behavior, which will typically ask for something in return from `sender` - often tokenized\n * Pool shares. The amount of tokens that can be withdrawn is limited by the Pool's `cash` balance (see\n * `getPoolTokenInfo`).\n *\n * If the caller is not `sender`, it must be an authorized relayer for them.\n *\n * The `tokens` and `minAmountsOut` arrays must have the same length, and each entry in these indicates the minimum\n * token amount to receive for each token contract. The amounts to send are decided by the Pool and not the Vault:\n * it just enforces these minimums.\n *\n * If exiting a Pool that holds WETH, it is possible to receive ETH directly: the Vault will do the unwrapping. To\n * enable this mechanism, the IAsset sentinel value (the zero address) must be passed in the `assets` array instead\n * of the WETH address. Note that it is not possible to combine ETH and WETH in the same exit.\n *\n * `assets` must have the same length and order as the array returned by `getPoolTokens`. This prevents issues when\n * interacting with Pools that register and deregister tokens frequently. If receiving ETH however, the array must\n * be sorted *before* replacing the WETH address with the ETH sentinel value (the zero address), which means the\n * final `assets` array might not be sorted. Pools with no registered tokens cannot be exited.\n *\n * If `toInternalBalance` is true, the tokens will be deposited to `recipient`'s Internal Balance. Otherwise,\n * an ERC20 transfer will be performed. Note that ETH cannot be deposited to Internal Balance: attempting to\n * do so will trigger a revert.\n *\n * `minAmountsOut` is the minimum amount of tokens the user expects to get out of the Pool, for each token in the\n * `tokens` array. This array must match the Pool's registered tokens.\n *\n * This causes the Vault to call the `IBasePool.onExitPool` hook on the Pool's contract, where Pools implement\n * their own custom logic. This typically requires additional information from the user (such as the expected number\n * of Pool shares to return). This can be encoded in the `userData` argument, which is ignored by the Vault and\n * passed directly to the Pool's contract.\n *\n * Emits a `PoolBalanceChanged` event.\n */\n function exitPool(\n bytes32 poolId,\n address sender,\n address payable recipient,\n ExitPoolRequest memory request\n ) external;\n\n struct ExitPoolRequest {\n address[] assets;\n uint256[] minAmountsOut;\n bytes userData;\n bool toInternalBalance;\n }\n\n /**\n * @dev Returns a Pool's registered tokens, the total balance for each, and the latest block when *any* of\n * the tokens' `balances` changed.\n *\n * The order of the `tokens` array is the same order that will be used in `joinPool`, `exitPool`, as well as in all\n * Pool hooks (where applicable). Calls to `registerTokens` and `deregisterTokens` may change this order.\n *\n * If a Pool only registers tokens once, and these are sorted in ascending order, they will be stored in the same\n * order as passed to `registerTokens`.\n *\n * Total balances include both tokens held by the Vault and those withdrawn by the Pool's Asset Managers. These are\n * the amounts used by joins, exits and swaps. For a detailed breakdown of token balances, use `getPoolTokenInfo`\n * instead.\n */\n function getPoolTokens(bytes32 poolId)\n external\n view\n returns (\n IERC20[] memory tokens,\n uint256[] memory balances,\n uint256 lastChangeBlock\n );\n\n /**\n * @dev Performs a set of user balance operations, which involve Internal Balance (deposit, withdraw or transfer)\n * and plain ERC20 transfers using the Vault's allowance. This last feature is particularly useful for relayers, as\n * it lets integrators reuse a user's Vault allowance.\n *\n * For each operation, if the caller is not `sender`, it must be an authorized relayer for them.\n */\n function manageUserBalance(UserBalanceOp[] memory ops) external payable;\n\n struct UserBalanceOp {\n UserBalanceOpKind kind;\n address asset;\n uint256 amount;\n address sender;\n address payable recipient;\n }\n\n enum UserBalanceOpKind {\n DEPOSIT_INTERNAL,\n WITHDRAW_INTERNAL,\n TRANSFER_INTERNAL,\n TRANSFER_EXTERNAL\n }\n\n enum SwapKind {\n GIVEN_IN,\n GIVEN_OUT\n }\n\n struct SingleSwap {\n bytes32 poolId;\n SwapKind kind;\n address assetIn;\n address assetOut;\n uint256 amount;\n bytes userData;\n }\n\n struct FundManagement {\n address sender;\n bool fromInternalBalance;\n address payable recipient;\n bool toInternalBalance;\n }\n\n function swap(\n SingleSwap calldata singleSwap,\n FundManagement calldata funds,\n uint256 limit,\n uint256 deadline\n ) external returns (uint256 amountCalculated);\n\n function getPoolTokenInfo(bytes32 poolId, address token)\n external\n view\n returns (\n uint256 cash,\n uint256 managed,\n uint256 lastChangeBlock,\n address assetManager\n );\n}\n" + }, + "contracts/interfaces/balancer/IMetaStablePool.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IRateProvider } from \"./IRateProvider.sol\";\n\ninterface IMetaStablePool {\n function getRateProviders()\n external\n view\n returns (IRateProvider[] memory providers);\n}\n" + }, + "contracts/interfaces/balancer/IRateProvider.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see .\n\npragma solidity ^0.8.0;\n\ninterface IRateProvider {\n function getRate() external view returns (uint256);\n}\n" + }, + "contracts/interfaces/IBasicToken.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IBasicToken {\n function symbol() external view returns (string memory);\n\n function decimals() external view returns (uint8);\n}\n" + }, + "contracts/interfaces/IComptroller.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IComptroller {\n // Claim all the COMP accrued by specific holders in specific markets for their supplies and/or borrows\n function claimComp(\n address[] memory holders,\n address[] memory cTokens,\n bool borrowers,\n bool suppliers\n ) external;\n\n function oracle() external view returns (address);\n}\n" + }, + "contracts/interfaces/IDepositContract.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IDepositContract {\n /// @notice A processed deposit event.\n event DepositEvent(\n bytes pubkey,\n bytes withdrawal_credentials,\n bytes amount,\n bytes signature,\n bytes index\n );\n\n /// @notice Submit a Phase 0 DepositData object.\n /// @param pubkey A BLS12-381 public key.\n /// @param withdrawal_credentials Commitment to a public key for withdrawals.\n /// @param signature A BLS12-381 signature.\n /// @param deposit_data_root The SHA-256 hash of the SSZ-encoded DepositData object.\n /// Used as a protection against malformed input.\n function deposit(\n bytes calldata pubkey,\n bytes calldata withdrawal_credentials,\n bytes calldata signature,\n bytes32 deposit_data_root\n ) external payable;\n\n /// @notice Query the current deposit root hash.\n /// @return The deposit root hash.\n function get_deposit_root() external view returns (bytes32);\n\n /// @notice Query the current deposit count.\n /// @return The deposit count encoded as a little endian 64-bit number.\n function get_deposit_count() external view returns (bytes memory);\n}\n" + }, + "contracts/interfaces/IDripper.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IDripper {\n /// @notice How much funds have dripped out already and are currently\n // available to be sent to the vault.\n /// @return The amount that would be sent if a collect was called\n function availableFunds() external view returns (uint256);\n\n /// @notice Collect all dripped funds and send to vault.\n /// Recalculate new drip rate.\n function collect() external;\n\n /// @notice Collect all dripped funds, send to vault, recalculate new drip\n /// rate, and rebase mToken.\n function collectAndRebase() external;\n}\n" + }, + "contracts/interfaces/IFraxETHMinter.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IFraxETHMinter {\n function submitAndDeposit(address recipient)\n external\n payable\n returns (uint256 shares);\n}\n" + }, + "contracts/interfaces/IGetExchangeRateToken.sol": { + "content": "pragma solidity ^0.8.0;\n\ninterface IGetExchangeRateToken {\n function getExchangeRate() external view returns (uint256 _exchangeRate);\n}\n" + }, + "contracts/interfaces/IOracle.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IOracle {\n /**\n * @dev returns the asset price in USD, in 8 decimal digits.\n *\n * The version of priceProvider deployed for OETH has 18 decimal digits\n */\n function price(address asset) external view returns (uint256);\n}\n" + }, + "contracts/interfaces/IOUSD.sol": { + "content": "pragma solidity ^0.8.0;\n\ninterface IOUSD {\n event Approval(\n address indexed owner,\n address indexed spender,\n uint256 value\n );\n event GovernorshipTransferred(\n address indexed previousGovernor,\n address indexed newGovernor\n );\n event PendingGovernorshipTransfer(\n address indexed previousGovernor,\n address indexed newGovernor\n );\n event TotalSupplyUpdatedHighres(\n uint256 totalSupply,\n uint256 rebasingCredits,\n uint256 rebasingCreditsPerToken\n );\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n function _totalSupply() external view returns (uint256);\n\n function allowance(address _owner, address _spender)\n external\n view\n returns (uint256);\n\n function approve(address _spender, uint256 _value) external returns (bool);\n\n function balanceOf(address _account) external view returns (uint256);\n\n function burn(address account, uint256 amount) external;\n\n function changeSupply(uint256 _newTotalSupply) external;\n\n function claimGovernance() external;\n\n function creditsBalanceOf(address _account)\n external\n view\n returns (uint256, uint256);\n\n function creditsBalanceOfHighres(address _account)\n external\n view\n returns (\n uint256,\n uint256,\n bool\n );\n\n function decimals() external view returns (uint8);\n\n function decreaseAllowance(address _spender, uint256 _subtractedValue)\n external\n returns (bool);\n\n function governor() external view returns (address);\n\n function increaseAllowance(address _spender, uint256 _addedValue)\n external\n returns (bool);\n\n function initialize(\n string memory _nameArg,\n string memory _symbolArg,\n address _vaultAddress\n ) external;\n\n function isGovernor() external view returns (bool);\n\n function isUpgraded(address) external view returns (uint256);\n\n function mint(address _account, uint256 _amount) external;\n\n function name() external view returns (string memory);\n\n function nonRebasingCreditsPerToken(address)\n external\n view\n returns (uint256);\n\n function nonRebasingSupply() external view returns (uint256);\n\n function rebaseOptIn() external;\n\n function rebaseOptOut() external;\n\n function rebaseState(address) external view returns (uint8);\n\n function rebasingCredits() external view returns (uint256);\n\n function rebasingCreditsHighres() external view returns (uint256);\n\n function rebasingCreditsPerToken() external view returns (uint256);\n\n function rebasingCreditsPerTokenHighres() external view returns (uint256);\n\n function symbol() external view returns (string memory);\n\n function totalSupply() external view returns (uint256);\n\n function transfer(address _to, uint256 _value) external returns (bool);\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) external returns (bool);\n\n function transferGovernance(address _newGovernor) external;\n\n function vaultAddress() external view returns (address);\n}\n" + }, + "contracts/interfaces/ISfrxETH.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface ISfrxETH {\n event Approval(\n address indexed owner,\n address indexed spender,\n uint256 amount\n );\n event Deposit(\n address indexed caller,\n address indexed owner,\n uint256 assets,\n uint256 shares\n );\n event NewRewardsCycle(uint32 indexed cycleEnd, uint256 rewardAmount);\n event Transfer(address indexed from, address indexed to, uint256 amount);\n event Withdraw(\n address indexed caller,\n address indexed receiver,\n address indexed owner,\n uint256 assets,\n uint256 shares\n );\n\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n\n function allowance(address, address) external view returns (uint256);\n\n function approve(address spender, uint256 amount) external returns (bool);\n\n function asset() external view returns (address);\n\n function balanceOf(address) external view returns (uint256);\n\n function convertToAssets(uint256 shares) external view returns (uint256);\n\n function convertToShares(uint256 assets) external view returns (uint256);\n\n function decimals() external view returns (uint8);\n\n function deposit(uint256 assets, address receiver)\n external\n returns (uint256 shares);\n\n function depositWithSignature(\n uint256 assets,\n address receiver,\n uint256 deadline,\n bool approveMax,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external returns (uint256 shares);\n\n function lastRewardAmount() external view returns (uint192);\n\n function lastSync() external view returns (uint32);\n\n function maxDeposit(address) external view returns (uint256);\n\n function maxMint(address) external view returns (uint256);\n\n function maxRedeem(address owner) external view returns (uint256);\n\n function maxWithdraw(address owner) external view returns (uint256);\n\n function mint(uint256 shares, address receiver)\n external\n returns (uint256 assets);\n\n function name() external view returns (string memory);\n\n function nonces(address) external view returns (uint256);\n\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n function previewDeposit(uint256 assets) external view returns (uint256);\n\n function previewMint(uint256 shares) external view returns (uint256);\n\n function previewRedeem(uint256 shares) external view returns (uint256);\n\n function previewWithdraw(uint256 assets) external view returns (uint256);\n\n function pricePerShare() external view returns (uint256);\n\n function redeem(\n uint256 shares,\n address receiver,\n address owner\n ) external returns (uint256 assets);\n\n function rewardsCycleEnd() external view returns (uint32);\n\n function rewardsCycleLength() external view returns (uint32);\n\n function symbol() external view returns (string memory);\n\n function syncRewards() external;\n\n function totalAssets() external view returns (uint256);\n\n function totalSupply() external view returns (uint256);\n\n function transfer(address to, uint256 amount) external returns (bool);\n\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n\n function withdraw(\n uint256 assets,\n address receiver,\n address owner\n ) external returns (uint256 shares);\n}\n" + }, + "contracts/interfaces/ISSVNetwork.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nstruct Cluster {\n uint32 validatorCount;\n uint64 networkFeeIndex;\n uint64 index;\n bool active;\n uint256 balance;\n}\n\ninterface ISSVNetwork {\n /**********/\n /* Errors */\n /**********/\n\n error CallerNotOwner(); // 0x5cd83192\n error CallerNotWhitelisted(); // 0x8c6e5d71\n error FeeTooLow(); // 0x732f9413\n error FeeExceedsIncreaseLimit(); // 0x958065d9\n error NoFeeDeclared(); // 0x1d226c30\n error ApprovalNotWithinTimeframe(); // 0x97e4b518\n error OperatorDoesNotExist(); // 0x961e3e8c\n error InsufficientBalance(); // 0xf4d678b8\n error ValidatorDoesNotExist(); // 0xe51315d2\n error ClusterNotLiquidatable(); // 0x60300a8d\n error InvalidPublicKeyLength(); // 0x637297a4\n error InvalidOperatorIdsLength(); // 0x38186224\n error ClusterAlreadyEnabled(); // 0x3babafd2\n error ClusterIsLiquidated(); // 0x95a0cf33\n error ClusterDoesNotExists(); // 0x185e2b16\n error IncorrectClusterState(); // 0x12e04c87\n error UnsortedOperatorsList(); // 0xdd020e25\n error NewBlockPeriodIsBelowMinimum(); // 0x6e6c9cac\n error ExceedValidatorLimit(); // 0x6df5ab76\n error TokenTransferFailed(); // 0x045c4b02\n error SameFeeChangeNotAllowed(); // 0xc81272f8\n error FeeIncreaseNotAllowed(); // 0x410a2b6c\n error NotAuthorized(); // 0xea8e4eb5\n error OperatorsListNotUnique(); // 0xa5a1ff5d\n error OperatorAlreadyExists(); // 0x289c9494\n error TargetModuleDoesNotExist(); // 0x8f9195fb\n error MaxValueExceeded(); // 0x91aa3017\n error FeeTooHigh(); // 0xcd4e6167\n error PublicKeysSharesLengthMismatch(); // 0x9ad467b8\n error IncorrectValidatorStateWithData(bytes publicKey); // 0x89307938\n error ValidatorAlreadyExistsWithData(bytes publicKey); // 0x388e7999\n error EmptyPublicKeysList(); // df83e679\n\n // legacy errors\n error ValidatorAlreadyExists(); // 0x8d09a73e\n error IncorrectValidatorState(); // 0x2feda3c1\n\n event AdminChanged(address previousAdmin, address newAdmin);\n event BeaconUpgraded(address indexed beacon);\n event ClusterDeposited(\n address indexed owner,\n uint64[] operatorIds,\n uint256 value,\n Cluster cluster\n );\n event ClusterLiquidated(\n address indexed owner,\n uint64[] operatorIds,\n Cluster cluster\n );\n event ClusterReactivated(\n address indexed owner,\n uint64[] operatorIds,\n Cluster cluster\n );\n event ClusterWithdrawn(\n address indexed owner,\n uint64[] operatorIds,\n uint256 value,\n Cluster cluster\n );\n event DeclareOperatorFeePeriodUpdated(uint64 value);\n event ExecuteOperatorFeePeriodUpdated(uint64 value);\n event FeeRecipientAddressUpdated(\n address indexed owner,\n address recipientAddress\n );\n event Initialized(uint8 version);\n event LiquidationThresholdPeriodUpdated(uint64 value);\n event MinimumLiquidationCollateralUpdated(uint256 value);\n event NetworkEarningsWithdrawn(uint256 value, address recipient);\n event NetworkFeeUpdated(uint256 oldFee, uint256 newFee);\n event OperatorAdded(\n uint64 indexed operatorId,\n address indexed owner,\n bytes publicKey,\n uint256 fee\n );\n event OperatorFeeDeclarationCancelled(\n address indexed owner,\n uint64 indexed operatorId\n );\n event OperatorFeeDeclared(\n address indexed owner,\n uint64 indexed operatorId,\n uint256 blockNumber,\n uint256 fee\n );\n event OperatorFeeExecuted(\n address indexed owner,\n uint64 indexed operatorId,\n uint256 blockNumber,\n uint256 fee\n );\n event OperatorFeeIncreaseLimitUpdated(uint64 value);\n event OperatorMaximumFeeUpdated(uint64 maxFee);\n event OperatorRemoved(uint64 indexed operatorId);\n event OperatorWhitelistUpdated(\n uint64 indexed operatorId,\n address whitelisted\n );\n event OperatorWithdrawn(\n address indexed owner,\n uint64 indexed operatorId,\n uint256 value\n );\n event OwnershipTransferStarted(\n address indexed previousOwner,\n address indexed newOwner\n );\n event OwnershipTransferred(\n address indexed previousOwner,\n address indexed newOwner\n );\n event Upgraded(address indexed implementation);\n event ValidatorAdded(\n address indexed owner,\n uint64[] operatorIds,\n bytes publicKey,\n bytes shares,\n Cluster cluster\n );\n event ValidatorExited(\n address indexed owner,\n uint64[] operatorIds,\n bytes publicKey\n );\n event ValidatorRemoved(\n address indexed owner,\n uint64[] operatorIds,\n bytes publicKey,\n Cluster cluster\n );\n\n fallback() external;\n\n function acceptOwnership() external;\n\n function cancelDeclaredOperatorFee(uint64 operatorId) external;\n\n function declareOperatorFee(uint64 operatorId, uint256 fee) external;\n\n function deposit(\n address clusterOwner,\n uint64[] memory operatorIds,\n uint256 amount,\n Cluster memory cluster\n ) external;\n\n function executeOperatorFee(uint64 operatorId) external;\n\n function exitValidator(bytes memory publicKey, uint64[] memory operatorIds)\n external;\n\n function bulkExitValidator(\n bytes[] calldata publicKeys,\n uint64[] calldata operatorIds\n ) external;\n\n function getVersion() external pure returns (string memory version);\n\n function initialize(\n address token_,\n address ssvOperators_,\n address ssvClusters_,\n address ssvDAO_,\n address ssvViews_,\n uint64 minimumBlocksBeforeLiquidation_,\n uint256 minimumLiquidationCollateral_,\n uint32 validatorsPerOperatorLimit_,\n uint64 declareOperatorFeePeriod_,\n uint64 executeOperatorFeePeriod_,\n uint64 operatorMaxFeeIncrease_\n ) external;\n\n function liquidate(\n address clusterOwner,\n uint64[] memory operatorIds,\n Cluster memory cluster\n ) external;\n\n function owner() external view returns (address);\n\n function pendingOwner() external view returns (address);\n\n function proxiableUUID() external view returns (bytes32);\n\n function reactivate(\n uint64[] memory operatorIds,\n uint256 amount,\n Cluster memory cluster\n ) external;\n\n function reduceOperatorFee(uint64 operatorId, uint256 fee) external;\n\n function registerOperator(bytes memory publicKey, uint256 fee)\n external\n returns (uint64 id);\n\n function registerValidator(\n bytes memory publicKey,\n uint64[] memory operatorIds,\n bytes memory sharesData,\n uint256 amount,\n Cluster memory cluster\n ) external;\n\n function bulkRegisterValidator(\n bytes[] calldata publicKeys,\n uint64[] calldata operatorIds,\n bytes[] calldata sharesData,\n uint256 amount,\n Cluster memory cluster\n ) external;\n\n function removeOperator(uint64 operatorId) external;\n\n function removeValidator(\n bytes memory publicKey,\n uint64[] memory operatorIds,\n Cluster memory cluster\n ) external;\n\n function bulkRemoveValidator(\n bytes[] calldata publicKeys,\n uint64[] calldata operatorIds,\n Cluster memory cluster\n ) external;\n\n function renounceOwnership() external;\n\n function setFeeRecipientAddress(address recipientAddress) external;\n\n function setOperatorWhitelist(uint64 operatorId, address whitelisted)\n external;\n\n function transferOwnership(address newOwner) external;\n\n function updateDeclareOperatorFeePeriod(uint64 timeInSeconds) external;\n\n function updateExecuteOperatorFeePeriod(uint64 timeInSeconds) external;\n\n function updateLiquidationThresholdPeriod(uint64 blocks) external;\n\n function updateMaximumOperatorFee(uint64 maxFee) external;\n\n function updateMinimumLiquidationCollateral(uint256 amount) external;\n\n function updateModule(uint8 moduleId, address moduleAddress) external;\n\n function updateNetworkFee(uint256 fee) external;\n\n function updateOperatorFeeIncreaseLimit(uint64 percentage) external;\n\n function upgradeTo(address newImplementation) external;\n\n function upgradeToAndCall(address newImplementation, bytes memory data)\n external\n payable;\n\n function withdraw(\n uint64[] memory operatorIds,\n uint256 amount,\n Cluster memory cluster\n ) external;\n\n function withdrawAllOperatorEarnings(uint64 operatorId) external;\n\n function withdrawNetworkEarnings(uint256 amount) external;\n\n function withdrawOperatorEarnings(uint64 operatorId, uint256 amount)\n external;\n}\n" + }, + "contracts/interfaces/IStrategy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title Platform interface to integrate with lending platform like Compound, AAVE etc.\n */\ninterface IStrategy {\n /**\n * @dev Deposit the given asset to platform\n * @param _asset asset address\n * @param _amount Amount to deposit\n */\n function deposit(address _asset, uint256 _amount) external;\n\n /**\n * @dev Deposit the entire balance of all supported assets in the Strategy\n * to the platform\n */\n function depositAll() external;\n\n /**\n * @dev Withdraw given asset from Lending platform\n */\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external;\n\n /**\n * @dev Liquidate all assets in strategy and return them to Vault.\n */\n function withdrawAll() external;\n\n /**\n * @dev Returns the current balance of the given asset.\n */\n function checkBalance(address _asset)\n external\n view\n returns (uint256 balance);\n\n /**\n * @dev Returns bool indicating whether strategy supports asset.\n */\n function supportsAsset(address _asset) external view returns (bool);\n\n /**\n * @dev Collect reward tokens from the Strategy.\n */\n function collectRewardTokens() external;\n\n /**\n * @dev The address array of the reward tokens for the Strategy.\n */\n function getRewardTokenAddresses() external view returns (address[] memory);\n}\n" + }, + "contracts/interfaces/ISwapper.sol": { + "content": "pragma solidity ^0.8.0;\n\ninterface ISwapper {\n /**\n * @param fromAsset The token address of the asset being sold.\n * @param toAsset The token address of the asset being purchased.\n * @param fromAssetAmount The amount of assets being sold.\n * @param minToAssetAmmount The minimum amount of assets to be purchased.\n * @param data tx.data returned from 1Inch's /v5.0/1/swap API\n */\n function swap(\n address fromAsset,\n address toAsset,\n uint256 fromAssetAmount,\n uint256 minToAssetAmmount,\n bytes calldata data\n ) external returns (uint256 toAssetAmount);\n}\n" + }, + "contracts/interfaces/IVault.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { VaultStorage } from \"../vault/VaultStorage.sol\";\n\ninterface IVault {\n event AssetSupported(address _asset);\n event AssetDefaultStrategyUpdated(address _asset, address _strategy);\n event AssetAllocated(address _asset, address _strategy, uint256 _amount);\n event StrategyApproved(address _addr);\n event StrategyRemoved(address _addr);\n event Mint(address _addr, uint256 _value);\n event Redeem(address _addr, uint256 _value);\n event CapitalPaused();\n event CapitalUnpaused();\n event RebasePaused();\n event RebaseUnpaused();\n event VaultBufferUpdated(uint256 _vaultBuffer);\n event RedeemFeeUpdated(uint256 _redeemFeeBps);\n event PriceProviderUpdated(address _priceProvider);\n event AllocateThresholdUpdated(uint256 _threshold);\n event RebaseThresholdUpdated(uint256 _threshold);\n event StrategistUpdated(address _address);\n event MaxSupplyDiffChanged(uint256 maxSupplyDiff);\n event YieldDistribution(address _to, uint256 _yield, uint256 _fee);\n event TrusteeFeeBpsChanged(uint256 _basis);\n event TrusteeAddressChanged(address _address);\n event SwapperChanged(address _address);\n event SwapAllowedUndervalueChanged(uint256 _basis);\n event SwapSlippageChanged(address _asset, uint256 _basis);\n event Swapped(\n address indexed _fromAsset,\n address indexed _toAsset,\n uint256 _fromAssetAmount,\n uint256 _toAssetAmount\n );\n event DripperChanged(address indexed _dripper);\n event WithdrawalRequested(\n address indexed _withdrawer,\n uint256 indexed _requestId,\n uint256 _amount,\n uint256 _queued\n );\n event WithdrawalClaimed(\n address indexed _withdrawer,\n uint256 indexed _requestId,\n uint256 _amount\n );\n event WithdrawalClaimable(uint256 _claimable, uint256 _newClaimable);\n\n // Governable.sol\n function transferGovernance(address _newGovernor) external;\n\n function claimGovernance() external;\n\n function governor() external view returns (address);\n\n // VaultAdmin.sol\n function setPriceProvider(address _priceProvider) external;\n\n function priceProvider() external view returns (address);\n\n function setRedeemFeeBps(uint256 _redeemFeeBps) external;\n\n function redeemFeeBps() external view returns (uint256);\n\n function setVaultBuffer(uint256 _vaultBuffer) external;\n\n function vaultBuffer() external view returns (uint256);\n\n function setAutoAllocateThreshold(uint256 _threshold) external;\n\n function autoAllocateThreshold() external view returns (uint256);\n\n function setRebaseThreshold(uint256 _threshold) external;\n\n function rebaseThreshold() external view returns (uint256);\n\n function setStrategistAddr(address _address) external;\n\n function strategistAddr() external view returns (address);\n\n function setMaxSupplyDiff(uint256 _maxSupplyDiff) external;\n\n function maxSupplyDiff() external view returns (uint256);\n\n function setTrusteeAddress(address _address) external;\n\n function trusteeAddress() external view returns (address);\n\n function setTrusteeFeeBps(uint256 _basis) external;\n\n function trusteeFeeBps() external view returns (uint256);\n\n function ousdMetaStrategy() external view returns (address);\n\n function setSwapper(address _swapperAddr) external;\n\n function setSwapAllowedUndervalue(uint16 _percentageBps) external;\n\n function setOracleSlippage(address _asset, uint16 _allowedOracleSlippageBps)\n external;\n\n function supportAsset(address _asset, uint8 _supportsAsset) external;\n\n function approveStrategy(address _addr) external;\n\n function removeStrategy(address _addr) external;\n\n function setAssetDefaultStrategy(address _asset, address _strategy)\n external;\n\n function assetDefaultStrategies(address _asset)\n external\n view\n returns (address);\n\n function pauseRebase() external;\n\n function unpauseRebase() external;\n\n function rebasePaused() external view returns (bool);\n\n function pauseCapital() external;\n\n function unpauseCapital() external;\n\n function capitalPaused() external view returns (bool);\n\n function transferToken(address _asset, uint256 _amount) external;\n\n function priceUnitMint(address asset) external view returns (uint256);\n\n function priceUnitRedeem(address asset) external view returns (uint256);\n\n function withdrawAllFromStrategy(address _strategyAddr) external;\n\n function withdrawAllFromStrategies() external;\n\n function withdrawFromStrategy(\n address _strategyFromAddress,\n address[] calldata _assets,\n uint256[] calldata _amounts\n ) external;\n\n function depositToStrategy(\n address _strategyToAddress,\n address[] calldata _assets,\n uint256[] calldata _amounts\n ) external;\n\n // VaultCore.sol\n function mint(\n address _asset,\n uint256 _amount,\n uint256 _minimumOusdAmount\n ) external;\n\n function mintForStrategy(uint256 _amount) external;\n\n function redeem(uint256 _amount, uint256 _minimumUnitAmount) external;\n\n function burnForStrategy(uint256 _amount) external;\n\n function redeemAll(uint256 _minimumUnitAmount) external;\n\n function allocate() external;\n\n function rebase() external;\n\n function swapCollateral(\n address fromAsset,\n address toAsset,\n uint256 fromAssetAmount,\n uint256 minToAssetAmount,\n bytes calldata data\n ) external returns (uint256 toAssetAmount);\n\n function totalValue() external view returns (uint256 value);\n\n function checkBalance(address _asset) external view returns (uint256);\n\n function calculateRedeemOutputs(uint256 _amount)\n external\n view\n returns (uint256[] memory);\n\n function getAssetCount() external view returns (uint256);\n\n function getAssetConfig(address _asset)\n external\n view\n returns (VaultStorage.Asset memory config);\n\n function getAllAssets() external view returns (address[] memory);\n\n function getStrategyCount() external view returns (uint256);\n\n function swapper() external view returns (address);\n\n function allowedSwapUndervalue() external view returns (uint256);\n\n function getAllStrategies() external view returns (address[] memory);\n\n function isSupportedAsset(address _asset) external view returns (bool);\n\n function netOusdMintForStrategyThreshold() external view returns (uint256);\n\n function setOusdMetaStrategy(address _ousdMetaStrategy) external;\n\n function setNetOusdMintForStrategyThreshold(uint256 _threshold) external;\n\n function netOusdMintedForStrategy() external view returns (int256);\n\n function setDripper(address _dripper) external;\n\n function weth() external view returns (address);\n\n function cacheWETHAssetIndex() external;\n\n function wethAssetIndex() external view returns (uint256);\n\n function initialize(address, address) external;\n\n function setAdminImpl(address) external;\n\n function removeAsset(address _asset) external;\n\n // These are OETH specific functions\n function addWithdrawalQueueLiquidity() external;\n\n function requestWithdrawal(uint256 _amount)\n external\n returns (uint256 requestId, uint256 queued);\n\n function claimWithdrawal(uint256 requestId)\n external\n returns (uint256 amount);\n\n function claimWithdrawals(uint256[] memory requestIds)\n external\n returns (uint256[] memory amounts, uint256 totalAmount);\n\n function withdrawalQueueMetadata()\n external\n view\n returns (VaultStorage.WithdrawalQueueMetadata memory);\n\n function withdrawalRequests(uint256 requestId)\n external\n view\n returns (VaultStorage.WithdrawalRequest memory);\n}\n" + }, + "contracts/interfaces/IWETH9.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IWETH9 {\n event Approval(address indexed src, address indexed guy, uint256 wad);\n event Deposit(address indexed dst, uint256 wad);\n event Transfer(address indexed src, address indexed dst, uint256 wad);\n event Withdrawal(address indexed src, uint256 wad);\n\n function allowance(address, address) external view returns (uint256);\n\n function approve(address guy, uint256 wad) external returns (bool);\n\n function balanceOf(address) external view returns (uint256);\n\n function decimals() external view returns (uint8);\n\n function deposit() external payable;\n\n function name() external view returns (string memory);\n\n function symbol() external view returns (string memory);\n\n function totalSupply() external view returns (uint256);\n\n function transfer(address dst, uint256 wad) external returns (bool);\n\n function transferFrom(\n address src,\n address dst,\n uint256 wad\n ) external returns (bool);\n\n function withdraw(uint256 wad) external;\n}\n" + }, + "contracts/interfaces/IWstETH.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IWstETH {\n /**\n * @notice Get amount of wstETH for a given amount of stETH\n * @param _stETHAmount amount of stETH\n * @return Amount of wstETH for a given stETH amount\n */\n function getWstETHByStETH(uint256 _stETHAmount)\n external\n view\n returns (uint256);\n\n /**\n * @notice Get amount of stETH for a given amount of wstETH\n * @param _wstETHAmount amount of wstETH\n * @return Amount of stETH for a given wstETH amount\n */\n function getStETHByWstETH(uint256 _wstETHAmount)\n external\n view\n returns (uint256);\n\n /**\n * @notice Get amount of stETH for a one wstETH\n * @return Amount of stETH for 1 wstETH\n */\n function stEthPerToken() external view returns (uint256);\n\n /**\n * @notice Get amount of wstETH for a one stETH\n * @return Amount of wstETH for a 1 stETH\n */\n function tokensPerStEth() external view returns (uint256);\n\n /**\n * @notice Exchanges stETH to wstETH\n * @param _stETHAmount amount of stETH to wrap in exchange for wstETH\n * @dev Requirements:\n * - `_stETHAmount` must be non-zero\n * - msg.sender must approve at least `_stETHAmount` stETH to this\n * contract.\n * - msg.sender must have at least `_stETHAmount` of stETH.\n * User should first approve _stETHAmount to the WstETH contract\n * @return Amount of wstETH user receives after wrap\n */\n function wrap(uint256 _stETHAmount) external returns (uint256);\n\n /**\n * @notice Exchanges wstETH to stETH\n * @param _wstETHAmount amount of wstETH to uwrap in exchange for stETH\n * @dev Requirements:\n * - `_wstETHAmount` must be non-zero\n * - msg.sender must have at least `_wstETHAmount` wstETH.\n * @return Amount of stETH user receives after unwrap\n */\n function unwrap(uint256 _wstETHAmount) external returns (uint256);\n}\n" + }, + "contracts/interfaces/morpho/compound/ICompoundOracle.sol": { + "content": "// SPDX-License-Identifier: GNU AGPLv3\npragma solidity ^0.8.0;\n\ninterface ICompoundOracle {\n function getUnderlyingPrice(address) external view returns (uint256);\n}\n" + }, + "contracts/interfaces/morpho/ILens.sol": { + "content": "// SPDX-License-Identifier: GNU AGPLv3\npragma solidity ^0.8.0;\n\nimport \"./compound/ICompoundOracle.sol\";\nimport \"./IMorpho.sol\";\n\ninterface ILens {\n /// STORAGE ///\n\n function MAX_BASIS_POINTS() external view returns (uint256);\n\n function WAD() external view returns (uint256);\n\n function morpho() external view returns (IMorpho);\n\n function comptroller() external view returns (IComptroller);\n\n /// GENERAL ///\n\n function getTotalSupply()\n external\n view\n returns (\n uint256 p2pSupplyAmount,\n uint256 poolSupplyAmount,\n uint256 totalSupplyAmount\n );\n\n function getTotalBorrow()\n external\n view\n returns (\n uint256 p2pBorrowAmount,\n uint256 poolBorrowAmount,\n uint256 totalBorrowAmount\n );\n\n /// MARKETS ///\n\n function isMarketCreated(address _poolToken) external view returns (bool);\n\n function isMarketCreatedAndNotPaused(address _poolToken)\n external\n view\n returns (bool);\n\n function isMarketCreatedAndNotPausedNorPartiallyPaused(address _poolToken)\n external\n view\n returns (bool);\n\n function getAllMarkets()\n external\n view\n returns (address[] memory marketsCreated_);\n\n function getMainMarketData(address _poolToken)\n external\n view\n returns (\n uint256 avgSupplyRatePerBlock,\n uint256 avgBorrowRatePerBlock,\n uint256 p2pSupplyAmount,\n uint256 p2pBorrowAmount,\n uint256 poolSupplyAmount,\n uint256 poolBorrowAmount\n );\n\n function getAdvancedMarketData(address _poolToken)\n external\n view\n returns (\n uint256 p2pSupplyIndex,\n uint256 p2pBorrowIndex,\n uint256 poolSupplyIndex,\n uint256 poolBorrowIndex,\n uint32 lastUpdateBlockNumber,\n uint256 p2pSupplyDelta,\n uint256 p2pBorrowDelta\n );\n\n function getMarketConfiguration(address _poolToken)\n external\n view\n returns (\n address underlying,\n bool isCreated,\n bool p2pDisabled,\n bool isPaused,\n bool isPartiallyPaused,\n uint16 reserveFactor,\n uint16 p2pIndexCursor,\n uint256 collateralFactor\n );\n\n function getTotalMarketSupply(address _poolToken)\n external\n view\n returns (uint256 p2pSupplyAmount, uint256 poolSupplyAmount);\n\n function getTotalMarketBorrow(address _poolToken)\n external\n view\n returns (uint256 p2pBorrowAmount, uint256 poolBorrowAmount);\n\n /// INDEXES ///\n\n function getCurrentP2PSupplyIndex(address _poolToken)\n external\n view\n returns (uint256);\n\n function getCurrentP2PBorrowIndex(address _poolToken)\n external\n view\n returns (uint256);\n\n function getCurrentPoolIndexes(address _poolToken)\n external\n view\n returns (\n uint256 currentPoolSupplyIndex,\n uint256 currentPoolBorrowIndex\n );\n\n function getIndexes(address _poolToken, bool _computeUpdatedIndexes)\n external\n view\n returns (\n uint256 p2pSupplyIndex,\n uint256 p2pBorrowIndex,\n uint256 poolSupplyIndex,\n uint256 poolBorrowIndex\n );\n\n /// USERS ///\n\n function getEnteredMarkets(address _user)\n external\n view\n returns (address[] memory enteredMarkets);\n\n function getUserHealthFactor(\n address _user,\n address[] calldata _updatedMarkets\n ) external view returns (uint256);\n\n function getUserBalanceStates(\n address _user,\n address[] calldata _updatedMarkets\n )\n external\n view\n returns (\n uint256 collateralValue,\n uint256 debtValue,\n uint256 maxDebtValue\n );\n\n function getCurrentSupplyBalanceInOf(address _poolToken, address _user)\n external\n view\n returns (\n uint256 balanceOnPool,\n uint256 balanceInP2P,\n uint256 totalBalance\n );\n\n function getCurrentBorrowBalanceInOf(address _poolToken, address _user)\n external\n view\n returns (\n uint256 balanceOnPool,\n uint256 balanceInP2P,\n uint256 totalBalance\n );\n\n function getUserMaxCapacitiesForAsset(address _user, address _poolToken)\n external\n view\n returns (uint256 withdrawable, uint256 borrowable);\n\n function getUserHypotheticalBalanceStates(\n address _user,\n address _poolToken,\n uint256 _withdrawnAmount,\n uint256 _borrowedAmount\n ) external view returns (uint256 debtValue, uint256 maxDebtValue);\n\n function getUserLiquidityDataForAsset(\n address _user,\n address _poolToken,\n bool _computeUpdatedIndexes,\n ICompoundOracle _oracle\n ) external view returns (Types.AssetLiquidityData memory assetData);\n\n function isLiquidatable(address _user, address[] memory _updatedMarkets)\n external\n view\n returns (bool);\n\n function computeLiquidationRepayAmount(\n address _user,\n address _poolTokenBorrowed,\n address _poolTokenCollateral,\n address[] calldata _updatedMarkets\n ) external view returns (uint256 toRepay);\n\n /// RATES ///\n\n function getAverageSupplyRatePerBlock(address _poolToken)\n external\n view\n returns (\n uint256 avgSupplyRatePerBlock,\n uint256 p2pSupplyAmount,\n uint256 poolSupplyAmount\n );\n\n function getAverageBorrowRatePerBlock(address _poolToken)\n external\n view\n returns (\n uint256 avgBorrowRatePerBlock,\n uint256 p2pBorrowAmount,\n uint256 poolBorrowAmount\n );\n\n function getNextUserSupplyRatePerBlock(\n address _poolToken,\n address _user,\n uint256 _amount\n )\n external\n view\n returns (\n uint256 nextSupplyRatePerBlock,\n uint256 balanceOnPool,\n uint256 balanceInP2P,\n uint256 totalBalance\n );\n\n function getNextUserBorrowRatePerBlock(\n address _poolToken,\n address _user,\n uint256 _amount\n )\n external\n view\n returns (\n uint256 nextBorrowRatePerBlock,\n uint256 balanceOnPool,\n uint256 balanceInP2P,\n uint256 totalBalance\n );\n\n function getCurrentUserSupplyRatePerBlock(address _poolToken, address _user)\n external\n view\n returns (uint256);\n\n function getCurrentUserBorrowRatePerBlock(address _poolToken, address _user)\n external\n view\n returns (uint256);\n\n function getRatesPerBlock(address _poolToken)\n external\n view\n returns (\n uint256 p2pSupplyRate,\n uint256 p2pBorrowRate,\n uint256 poolSupplyRate,\n uint256 poolBorrowRate\n );\n\n /// REWARDS ///\n\n function getUserUnclaimedRewards(\n address[] calldata _poolTokens,\n address _user\n ) external view returns (uint256 unclaimedRewards);\n\n function getAccruedSupplierComp(\n address _supplier,\n address _poolToken,\n uint256 _balance\n ) external view returns (uint256);\n\n function getAccruedBorrowerComp(\n address _borrower,\n address _poolToken,\n uint256 _balance\n ) external view returns (uint256);\n\n function getCurrentCompSupplyIndex(address _poolToken)\n external\n view\n returns (uint256);\n\n function getCurrentCompBorrowIndex(address _poolToken)\n external\n view\n returns (uint256);\n}\n" + }, + "contracts/interfaces/morpho/IMorpho.sol": { + "content": "// SPDX-License-Identifier: GNU AGPLv3\npragma solidity ^0.8.0;\n\nimport \"./Types.sol\";\nimport \"../IComptroller.sol\";\nimport \"./compound/ICompoundOracle.sol\";\n\n// prettier-ignore\ninterface IMorpho {\n function comptroller() external view returns (IComptroller);\n function supply(address _poolTokenAddress, address _onBehalf, uint256 _amount) external;\n function supply(address _poolTokenAddress, address _onBehalf, uint256 _amount, uint256 _maxGasForMatching) external;\n function withdraw(address _poolTokenAddress, uint256 _amount) external;\n function claimRewards(\n address[] calldata _cTokenAddresses,\n bool _tradeForMorphoToken\n ) external returns (uint256 claimedAmount);\n}\n" + }, + "contracts/interfaces/morpho/Types.sol": { + "content": "// SPDX-License-Identifier: GNU AGPLv3\npragma solidity ^0.8.0;\n\n/// @title Types.\n/// @author Morpho Labs.\n/// @custom:contact security@morpho.xyz\n/// @dev Common types and structs used in Moprho contracts.\nlibrary Types {\n /// ENUMS ///\n\n enum PositionType {\n SUPPLIERS_IN_P2P,\n SUPPLIERS_ON_POOL,\n BORROWERS_IN_P2P,\n BORROWERS_ON_POOL\n }\n\n /// STRUCTS ///\n\n struct SupplyBalance {\n uint256 inP2P; // In supplier's peer-to-peer unit, a unit that grows in underlying value, to keep track of the interests earned by suppliers in peer-to-peer. Multiply by the peer-to-peer supply index to get the underlying amount.\n uint256 onPool; // In cToken. Multiply by the pool supply index to get the underlying amount.\n }\n\n struct BorrowBalance {\n uint256 inP2P; // In borrower's peer-to-peer unit, a unit that grows in underlying value, to keep track of the interests paid by borrowers in peer-to-peer. Multiply by the peer-to-peer borrow index to get the underlying amount.\n uint256 onPool; // In cdUnit, a unit that grows in value, to keep track of the debt increase when borrowers are on Compound. Multiply by the pool borrow index to get the underlying amount.\n }\n\n // Max gas to consume during the matching process for supply, borrow, withdraw and repay functions.\n struct MaxGasForMatching {\n uint64 supply;\n uint64 borrow;\n uint64 withdraw;\n uint64 repay;\n }\n\n struct Delta {\n uint256 p2pSupplyDelta; // Difference between the stored peer-to-peer supply amount and the real peer-to-peer supply amount (in pool supply unit).\n uint256 p2pBorrowDelta; // Difference between the stored peer-to-peer borrow amount and the real peer-to-peer borrow amount (in pool borrow unit).\n uint256 p2pSupplyAmount; // Sum of all stored peer-to-peer supply (in peer-to-peer supply unit).\n uint256 p2pBorrowAmount; // Sum of all stored peer-to-peer borrow (in peer-to-peer borrow unit).\n }\n\n struct AssetLiquidityData {\n uint256 collateralValue; // The collateral value of the asset.\n uint256 maxDebtValue; // The maximum possible debt value of the asset.\n uint256 debtValue; // The debt value of the asset.\n uint256 underlyingPrice; // The price of the token.\n uint256 collateralFactor; // The liquidation threshold applied on this token.\n }\n\n struct LiquidityData {\n uint256 collateralValue; // The collateral value.\n uint256 maxDebtValue; // The maximum debt value possible.\n uint256 debtValue; // The debt value.\n }\n\n // Variables are packed together to save gas (will not exceed their limit during Morpho's lifetime).\n struct LastPoolIndexes {\n uint32 lastUpdateBlockNumber; // The last time the peer-to-peer indexes were updated.\n uint112 lastSupplyPoolIndex; // Last pool supply index.\n uint112 lastBorrowPoolIndex; // Last pool borrow index.\n }\n\n struct MarketParameters {\n uint16 reserveFactor; // Proportion of the interest earned by users sent to the DAO for each market, in basis point (100% = 10 000). The value is set at market creation.\n uint16 p2pIndexCursor; // Position of the peer-to-peer rate in the pool's spread. Determine the weights of the weighted arithmetic average in the indexes computations ((1 - p2pIndexCursor) * r^S + p2pIndexCursor * r^B) (in basis point).\n }\n\n struct MarketStatus {\n bool isCreated; // Whether or not this market is created.\n bool isPaused; // Whether the market is paused or not (all entry points on Morpho are frozen; supply, borrow, withdraw, repay and liquidate).\n bool isPartiallyPaused; // Whether the market is partially paused or not (only supply and borrow are frozen).\n }\n}\n" + }, + "contracts/interfaces/uniswap/IUniswapV2Router02.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IUniswapV2Router {\n function WETH() external pure returns (address);\n\n function swapExactTokensForTokens(\n uint256 amountIn,\n uint256 amountOutMin,\n address[] calldata path,\n address to,\n uint256 deadline\n ) external returns (uint256[] memory amounts);\n\n function addLiquidity(\n address tokenA,\n address tokenB,\n uint256 amountADesired,\n uint256 amountBDesired,\n uint256 amountAMin,\n uint256 amountBMin,\n address to,\n uint256 deadline\n )\n external\n returns (\n uint256 amountA,\n uint256 amountB,\n uint256 liquidity\n );\n}\n" + }, + "contracts/interfaces/uniswap/IUniswapV3Router.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n// -- Solididy v0.5.x compatible interface\ninterface IUniswapV3Router {\n struct ExactInputParams {\n bytes path;\n address recipient;\n uint256 deadline;\n uint256 amountIn;\n uint256 amountOutMinimum;\n }\n\n /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path\n /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata\n /// @return amountOut The amount of the received token\n function exactInput(ExactInputParams calldata params)\n external\n payable\n returns (uint256 amountOut);\n}\n" + }, + "contracts/mocks/MintableERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ninterface IMintableERC20 {\n function mint(uint256 value) external;\n\n function mintTo(address to, uint256 value) external;\n}\n\n/**\n * @title MintableERC20\n * @dev Exposes the mint function of ERC20 for tests\n */\nabstract contract MintableERC20 is IMintableERC20, ERC20 {\n /**\n * @dev Function to mint tokens\n * @param _value The amount of tokens to mint.\n */\n function mint(uint256 _value) public virtual override {\n _mint(msg.sender, _value);\n }\n\n /**\n * @dev Function to mint tokens\n * @param _to Address to mint to.\n * @param _value The amount of tokens to mint.\n */\n function mintTo(address _to, uint256 _value) public virtual override {\n _mint(_to, _value);\n }\n}\n" + }, + "contracts/mocks/MockBalancerVault.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IBalancerVault } from \"../interfaces/balancer/IBalancerVault.sol\";\nimport { MintableERC20 } from \"./MintableERC20.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\n\n// import \"hardhat/console.sol\";\n\ncontract MockBalancerVault {\n using StableMath for uint256;\n uint256 public slippage = 1 ether;\n bool public transferDisabled = false;\n bool public slippageErrorDisabled = false;\n\n function swap(\n IBalancerVault.SingleSwap calldata singleSwap,\n IBalancerVault.FundManagement calldata funds,\n uint256 minAmountOut,\n uint256\n ) external returns (uint256 amountCalculated) {\n amountCalculated = (minAmountOut * slippage) / 1 ether;\n if (!slippageErrorDisabled) {\n require(amountCalculated >= minAmountOut, \"Slippage error\");\n }\n IERC20(singleSwap.assetIn).transferFrom(\n funds.sender,\n address(this),\n singleSwap.amount\n );\n if (!transferDisabled) {\n MintableERC20(singleSwap.assetOut).mintTo(\n funds.recipient,\n amountCalculated\n );\n }\n }\n\n function setSlippage(uint256 _slippage) external {\n slippage = _slippage;\n }\n\n function getPoolTokenInfo(bytes32 poolId, address token)\n external\n view\n returns (\n uint256,\n uint256,\n uint256,\n address\n )\n {}\n\n function disableTransfer() external {\n transferDisabled = true;\n }\n\n function disableSlippageError() external {\n slippageErrorDisabled = true;\n }\n}\n" + }, + "contracts/mocks/MockEvilDAI.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\n\ncontract MockEvilDAI is MintableERC20 {\n address host;\n address realCoin;\n\n constructor(address _host, address _realCoin) ERC20(\"DAI\", \"DAI\") {\n host = _host;\n realCoin = _realCoin;\n }\n\n function transferFrom(\n // solhint-disable-next-line no-unused-vars\n address _from,\n // solhint-disable-next-line no-unused-vars\n address _to,\n uint256 _amount\n ) public override returns (bool) {\n // call mint again!\n if (_amount != 69) {\n IVault(host).mint(address(this), 69, 0);\n }\n return true;\n }\n}\n" + }, + "contracts/mocks/MockEvilReentrantContract.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { IOracle } from \"../interfaces/IOracle.sol\";\nimport { IRateProvider } from \"../interfaces/balancer/IRateProvider.sol\";\n\nimport { IBalancerVault } from \"../interfaces/balancer/IBalancerVault.sol\";\nimport { IERC20 } from \"../utils/InitializableAbstractStrategy.sol\";\n\nimport { StableMath } from \"../utils/StableMath.sol\";\n\ncontract MockEvilReentrantContract {\n using StableMath for uint256;\n\n IBalancerVault public immutable balancerVault;\n IERC20 public immutable reth;\n IERC20 public immutable weth;\n IVault public immutable oethVault;\n address public immutable poolAddress;\n bytes32 public immutable balancerPoolId;\n\n constructor(\n address _balancerVault,\n address _oethVault,\n address _reth,\n address _weth,\n address _poolAddress,\n bytes32 _poolId\n ) {\n balancerVault = IBalancerVault(_balancerVault);\n oethVault = IVault(_oethVault);\n reth = IERC20(_reth);\n weth = IERC20(_weth);\n poolAddress = _poolAddress;\n balancerPoolId = _poolId;\n }\n\n function doEvilStuff() public {\n address priceProvider = oethVault.priceProvider();\n uint256 rethPrice = IOracle(priceProvider).price(address(reth));\n\n // 1. Join pool\n uint256[] memory amounts = new uint256[](2);\n amounts[0] = uint256(10 ether);\n amounts[1] = rethPrice * 10;\n\n address[] memory assets = new address[](2);\n assets[0] = address(reth);\n assets[1] = address(weth);\n\n uint256 minBPT = getBPTExpected(assets, amounts).mulTruncate(\n 0.99 ether\n );\n\n bytes memory joinUserData = abi.encode(\n IBalancerVault.WeightedPoolJoinKind.EXACT_TOKENS_IN_FOR_BPT_OUT,\n amounts,\n minBPT\n );\n\n IBalancerVault.JoinPoolRequest memory joinRequest = IBalancerVault\n .JoinPoolRequest(assets, amounts, joinUserData, false);\n\n balancerVault.joinPool(\n balancerPoolId,\n address(this),\n address(this),\n joinRequest\n );\n\n uint256 bptTokenBalance = IERC20(poolAddress).balanceOf(address(this));\n\n // 2. Redeem as ETH\n bytes memory exitUserData = abi.encode(\n IBalancerVault.WeightedPoolExitKind.EXACT_BPT_IN_FOR_ONE_TOKEN_OUT,\n bptTokenBalance,\n 1\n );\n\n assets[1] = address(0); // Receive ETH instead of WETH\n uint256[] memory exitAmounts = new uint256[](2);\n exitAmounts[1] = 15 ether;\n IBalancerVault.ExitPoolRequest memory exitRequest = IBalancerVault\n .ExitPoolRequest(assets, exitAmounts, exitUserData, false);\n\n balancerVault.exitPool(\n balancerPoolId,\n address(this),\n payable(address(this)),\n exitRequest\n );\n bptTokenBalance = IERC20(poolAddress).balanceOf(address(this));\n }\n\n function getBPTExpected(address[] memory _assets, uint256[] memory _amounts)\n internal\n view\n virtual\n returns (uint256 bptExpected)\n {\n // Get the oracle from the OETH Vault\n address priceProvider = oethVault.priceProvider();\n\n for (uint256 i = 0; i < _assets.length; ++i) {\n uint256 strategyAssetMarketPrice = IOracle(priceProvider).price(\n _assets[i]\n );\n // convert asset amount to ETH amount\n bptExpected =\n bptExpected +\n _amounts[i].mulTruncate(strategyAssetMarketPrice);\n }\n\n uint256 bptRate = IRateProvider(poolAddress).getRate();\n // Convert ETH amount to BPT amount\n bptExpected = bptExpected.divPrecisely(bptRate);\n }\n\n function approveAllTokens() public {\n // Approve all tokens\n weth.approve(address(oethVault), type(uint256).max);\n reth.approve(poolAddress, type(uint256).max);\n weth.approve(poolAddress, type(uint256).max);\n reth.approve(address(balancerVault), type(uint256).max);\n weth.approve(address(balancerVault), type(uint256).max);\n }\n\n receive() external payable {\n // 3. Try to mint OETH\n oethVault.mint(address(weth), 1 ether, 0.9 ether);\n }\n}\n" + }, + "contracts/mocks/MockNonRebasing.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { IVault } from \"../interfaces/IVault.sol\";\n\nimport { OUSD } from \"../token/OUSD.sol\";\n\ncontract MockNonRebasing {\n OUSD oUSD;\n\n function setOUSD(address _oUSDAddress) public {\n oUSD = OUSD(_oUSDAddress);\n }\n\n function rebaseOptIn() public {\n oUSD.rebaseOptIn();\n }\n\n function rebaseOptOut() public {\n oUSD.rebaseOptOut();\n }\n\n function transfer(address _to, uint256 _value) public {\n oUSD.transfer(_to, _value);\n }\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) public {\n oUSD.transferFrom(_from, _to, _value);\n }\n\n function increaseAllowance(address _spender, uint256 _addedValue) public {\n oUSD.increaseAllowance(_spender, _addedValue);\n }\n\n function mintOusd(\n address _vaultContract,\n address _asset,\n uint256 _amount\n ) public {\n IVault(_vaultContract).mint(_asset, _amount, 0);\n }\n\n function redeemOusd(address _vaultContract, uint256 _amount) public {\n IVault(_vaultContract).redeem(_amount, 0);\n }\n\n function approveFor(\n address _contract,\n address _spender,\n uint256 _addedValue\n ) public {\n IERC20(_contract).approve(_spender, _addedValue);\n }\n}\n" + }, + "contracts/mocks/MockOETHVault.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { OETHVaultCore } from \"../vault/OETHVaultCore.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport \"../utils/Helpers.sol\";\n\ncontract MockOETHVault is OETHVaultCore {\n using StableMath for uint256;\n\n constructor(address _weth) OETHVaultCore(_weth) {}\n\n function supportAsset(address asset) external {\n assets[asset] = Asset({\n isSupported: true,\n unitConversion: UnitConversion(0),\n decimals: 18,\n allowedOracleSlippageBps: 0\n });\n\n allAssets.push(asset);\n }\n}\n" + }, + "contracts/mocks/MockRebornMinter.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n// solhint-disable-next-line no-console\nimport \"hardhat/console.sol\";\n\ncontract Sanctum {\n address public asset;\n address public vault;\n address public reborner;\n bool public shouldAttack = false;\n uint256 public targetMethod;\n address public ousdContract;\n\n constructor(address _asset, address _vault) {\n asset = _asset;\n vault = _vault;\n }\n\n function deploy(uint256 salt, bytes memory bytecode)\n public\n returns (address addr)\n {\n // solhint-disable-next-line no-inline-assembly\n assembly {\n addr := create2(0, add(bytecode, 0x20), mload(bytecode), salt)\n }\n require(addr != address(0), \"Create2: Failed on deploy\");\n }\n\n function computeAddress(uint256 salt, bytes memory bytecode)\n public\n view\n returns (address)\n {\n bytes32 bytecodeHashHash = keccak256(bytecode);\n bytes32 _data = keccak256(\n abi.encodePacked(\n bytes1(0xff),\n address(this),\n salt,\n bytecodeHashHash\n )\n );\n return address(bytes20(_data << 96));\n }\n\n function setShouldAttack(bool _shouldAttack) public {\n shouldAttack = _shouldAttack;\n }\n\n function setTargetMethod(uint256 target) public {\n targetMethod = target;\n }\n\n function setOUSDAddress(address _ousdContract) public {\n ousdContract = _ousdContract;\n }\n}\n\ncontract Reborner {\n Sanctum sanctum;\n bool logging = false;\n\n constructor(address _sanctum) {\n log(\"We are created...\");\n sanctum = Sanctum(_sanctum);\n if (sanctum.shouldAttack()) {\n log(\"We are attacking now...\");\n\n uint256 target = sanctum.targetMethod();\n\n if (target == 1) {\n redeem();\n } else if (target == 2) {\n transfer();\n } else {\n mint();\n }\n }\n }\n\n function mint() public {\n log(\"We are attempting to mint..\");\n address asset = sanctum.asset();\n address vault = sanctum.vault();\n IERC20(asset).approve(vault, 1e18);\n IVault(vault).mint(asset, 1e18, 0);\n log(\"We are now minting..\");\n }\n\n function redeem() public {\n log(\"We are attempting to redeem..\");\n address vault = sanctum.vault();\n IVault(vault).redeem(1e18, 1e18);\n log(\"We are now redeeming..\");\n }\n\n function transfer() public {\n log(\"We are attempting to transfer..\");\n address ousd = sanctum.ousdContract();\n require(IERC20(ousd).transfer(address(1), 1e18), \"transfer failed\");\n log(\"We are now transfering..\");\n }\n\n function bye() public {\n log(\"We are now destructing..\");\n selfdestruct(payable(msg.sender));\n }\n\n function log(string memory message) internal view {\n if (logging) {\n // solhint-disable-next-line no-console\n console.log(message);\n }\n }\n}\n" + }, + "contracts/mocks/MockVault.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { VaultCore } from \"../vault/VaultCore.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { VaultInitializer } from \"../vault/VaultInitializer.sol\";\nimport \"../utils/Helpers.sol\";\n\ncontract MockVault is VaultCore {\n using StableMath for uint256;\n\n uint256 storedTotalValue;\n\n function setTotalValue(uint256 _value) public {\n storedTotalValue = _value;\n }\n\n function totalValue() external view override returns (uint256) {\n return storedTotalValue;\n }\n\n function _totalValue() internal view override returns (uint256) {\n return storedTotalValue;\n }\n\n function _checkBalance(address _asset)\n internal\n view\n override\n returns (uint256 balance)\n {\n // Avoids rounding errors by returning the total value\n // in a single currency\n if (allAssets[0] == _asset) {\n uint256 decimals = Helpers.getDecimals(_asset);\n return storedTotalValue.scaleBy(decimals, 18);\n } else {\n return 0;\n }\n }\n\n function setMaxSupplyDiff(uint256 _maxSupplyDiff) external onlyGovernor {\n maxSupplyDiff = _maxSupplyDiff;\n }\n}\n" + }, + "contracts/strategies/AaveStrategy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title OUSD Aave Strategy\n * @notice Investment strategy for investing stablecoins via Aave\n * @author Origin Protocol Inc\n */\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport \"./IAave.sol\";\nimport { IERC20, InitializableAbstractStrategy } from \"../utils/InitializableAbstractStrategy.sol\";\n\nimport { IAaveStakedToken } from \"./IAaveStakeToken.sol\";\nimport { IAaveIncentivesController } from \"./IAaveIncentivesController.sol\";\n\ncontract AaveStrategy is InitializableAbstractStrategy {\n using SafeERC20 for IERC20;\n\n uint16 constant referralCode = 92;\n\n IAaveIncentivesController public incentivesController;\n IAaveStakedToken public stkAave;\n\n /**\n * @param _stratConfig The platform and OToken vault addresses\n */\n constructor(BaseStrategyConfig memory _stratConfig)\n InitializableAbstractStrategy(_stratConfig)\n {}\n\n /**\n * Initializer for setting up strategy internal state. This overrides the\n * InitializableAbstractStrategy initializer as AAVE needs several extra\n * addresses for the rewards program.\n * @param _rewardTokenAddresses Address of the AAVE token\n * @param _assets Addresses of supported assets\n * @param _pTokens Platform Token corresponding addresses\n * @param _incentivesAddress Address of the AAVE incentives controller\n * @param _stkAaveAddress Address of the stkAave contract\n */\n function initialize(\n address[] calldata _rewardTokenAddresses, // AAVE\n address[] calldata _assets,\n address[] calldata _pTokens,\n address _incentivesAddress,\n address _stkAaveAddress\n ) external onlyGovernor initializer {\n incentivesController = IAaveIncentivesController(_incentivesAddress);\n stkAave = IAaveStakedToken(_stkAaveAddress);\n InitializableAbstractStrategy._initialize(\n _rewardTokenAddresses,\n _assets,\n _pTokens\n );\n }\n\n /**\n * @dev Deposit asset into Aave\n * @param _asset Address of asset to deposit\n * @param _amount Amount of asset to deposit\n */\n function deposit(address _asset, uint256 _amount)\n external\n override\n onlyVault\n nonReentrant\n {\n _deposit(_asset, _amount);\n }\n\n /**\n * @dev Deposit asset into Aave\n * @param _asset Address of asset to deposit\n * @param _amount Amount of asset to deposit\n */\n function _deposit(address _asset, uint256 _amount) internal {\n require(_amount > 0, \"Must deposit something\");\n // Following line also doubles as a check that we are depositing\n // an asset that we support.\n emit Deposit(_asset, _getATokenFor(_asset), _amount);\n _getLendingPool().deposit(_asset, _amount, address(this), referralCode);\n }\n\n /**\n * @dev Deposit the entire balance of any supported asset into Aave\n */\n function depositAll() external override onlyVault nonReentrant {\n for (uint256 i = 0; i < assetsMapped.length; i++) {\n uint256 balance = IERC20(assetsMapped[i]).balanceOf(address(this));\n if (balance > 0) {\n _deposit(assetsMapped[i], balance);\n }\n }\n }\n\n /**\n * @dev Withdraw asset from Aave\n * @param _recipient Address to receive withdrawn asset\n * @param _asset Address of asset to withdraw\n * @param _amount Amount of asset to withdraw\n */\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external override onlyVault nonReentrant {\n require(_amount > 0, \"Must withdraw something\");\n require(_recipient != address(0), \"Must specify recipient\");\n\n emit Withdrawal(_asset, _getATokenFor(_asset), _amount);\n uint256 actual = _getLendingPool().withdraw(\n _asset,\n _amount,\n address(this)\n );\n require(actual == _amount, \"Did not withdraw enough\");\n IERC20(_asset).safeTransfer(_recipient, _amount);\n }\n\n /**\n * @dev Remove all assets from platform and send them to Vault contract.\n */\n function withdrawAll() external override onlyVaultOrGovernor nonReentrant {\n for (uint256 i = 0; i < assetsMapped.length; i++) {\n // Redeem entire balance of aToken\n IERC20 asset = IERC20(assetsMapped[i]);\n address aToken = _getATokenFor(assetsMapped[i]);\n uint256 balance = IERC20(aToken).balanceOf(address(this));\n if (balance > 0) {\n uint256 actual = _getLendingPool().withdraw(\n address(asset),\n balance,\n address(this)\n );\n require(actual == balance, \"Did not withdraw enough\");\n\n uint256 assetBalance = asset.balanceOf(address(this));\n // Transfer entire balance to Vault\n asset.safeTransfer(vaultAddress, assetBalance);\n\n emit Withdrawal(address(asset), aToken, assetBalance);\n }\n }\n }\n\n /**\n * @dev Get the total asset value held in the platform\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n external\n view\n override\n returns (uint256 balance)\n {\n // Balance is always with token aToken decimals\n address aToken = _getATokenFor(_asset);\n balance = IERC20(aToken).balanceOf(address(this));\n }\n\n /**\n * @dev Returns bool indicating whether asset is supported by strategy\n * @param _asset Address of the asset\n */\n function supportsAsset(address _asset) public view override returns (bool) {\n return assetToPToken[_asset] != address(0);\n }\n\n /**\n * @dev Approve the spending of all assets by their corresponding aToken,\n * if for some reason is it necessary.\n */\n function safeApproveAllTokens()\n external\n override\n onlyGovernor\n nonReentrant\n {\n address lendingPool = address(_getLendingPool());\n // approve the pool to spend the Asset\n for (uint256 i = 0; i < assetsMapped.length; i++) {\n address asset = assetsMapped[i];\n // Safe approval\n IERC20(asset).safeApprove(lendingPool, 0);\n IERC20(asset).safeApprove(lendingPool, type(uint256).max);\n }\n }\n\n /**\n * @dev Internal method to respond to the addition of new asset / aTokens\n We need to give the AAVE lending pool approval to transfer the\n asset.\n * @param _asset Address of the asset to approve\n * @param _aToken Address of the aToken\n */\n // solhint-disable-next-line no-unused-vars\n function _abstractSetPToken(address _asset, address _aToken)\n internal\n override\n {\n address lendingPool = address(_getLendingPool());\n IERC20(_asset).safeApprove(lendingPool, 0);\n IERC20(_asset).safeApprove(lendingPool, type(uint256).max);\n }\n\n /**\n * @dev Get the aToken wrapped in the IERC20 interface for this asset.\n * Fails if the pToken doesn't exist in our mappings.\n * @param _asset Address of the asset\n * @return Corresponding aToken to this asset\n */\n function _getATokenFor(address _asset) internal view returns (address) {\n address aToken = assetToPToken[_asset];\n require(aToken != address(0), \"aToken does not exist\");\n return aToken;\n }\n\n /**\n * @dev Get the current address of the Aave lending pool, which is the gateway to\n * depositing.\n * @return Current lending pool implementation\n */\n function _getLendingPool() internal view returns (IAaveLendingPool) {\n address lendingPool = ILendingPoolAddressesProvider(platformAddress)\n .getLendingPool();\n require(lendingPool != address(0), \"Lending pool does not exist\");\n return IAaveLendingPool(lendingPool);\n }\n\n /**\n * @dev Collect stkAave, convert it to AAVE send to Vault.\n */\n function collectRewardTokens()\n external\n override\n onlyHarvester\n nonReentrant\n {\n if (address(stkAave) == address(0)) {\n return;\n }\n\n // Check staked AAVE cooldown timer\n uint256 cooldown = stkAave.stakersCooldowns(address(this));\n uint256 windowStart = cooldown + stkAave.COOLDOWN_SECONDS();\n uint256 windowEnd = windowStart + stkAave.UNSTAKE_WINDOW();\n\n // If inside the unlock window, then we can redeem stkAave\n // for AAVE and send it to the vault.\n if (block.timestamp > windowStart && block.timestamp <= windowEnd) {\n // Redeem to AAVE\n uint256 stkAaveBalance = stkAave.balanceOf(address(this));\n stkAave.redeem(address(this), stkAaveBalance);\n\n // Transfer AAVE to harvesterAddress\n uint256 aaveBalance = IERC20(rewardTokenAddresses[0]).balanceOf(\n address(this)\n );\n if (aaveBalance > 0) {\n IERC20(rewardTokenAddresses[0]).safeTransfer(\n harvesterAddress,\n aaveBalance\n );\n }\n }\n\n // Collect available rewards and restart the cooldown timer, if either of\n // those should be run.\n if (block.timestamp > windowStart || cooldown == 0) {\n uint256 assetsLen = assetsMapped.length;\n // aToken addresses for incentives controller\n address[] memory aTokens = new address[](assetsLen);\n for (uint256 i = 0; i < assetsLen; ++i) {\n aTokens[i] = _getATokenFor(assetsMapped[i]);\n }\n\n // 1. If we have rewards availabile, collect them\n uint256 pendingRewards = incentivesController.getRewardsBalance(\n aTokens,\n address(this)\n );\n if (pendingRewards > 0) {\n // Because getting more stkAAVE from the incentives controller\n // with claimRewards() may push the stkAAVE cooldown time\n // forward, it is called after stakedAAVE has been turned into\n // AAVE.\n uint256 collected = incentivesController.claimRewards(\n aTokens,\n pendingRewards,\n address(this)\n );\n require(collected == pendingRewards, \"AAVE reward difference\");\n }\n\n // 2. Start cooldown counting down.\n if (stkAave.balanceOf(address(this)) > 0) {\n // Protected with if since cooldown call would revert\n // if no stkAave balance.\n stkAave.cooldown();\n }\n }\n }\n}\n" + }, + "contracts/strategies/balancer/BalancerMetaPoolStrategy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title OETH Balancer MetaStablePool Strategy\n * @author Origin Protocol Inc\n */\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { BaseAuraStrategy, BaseBalancerStrategy } from \"./BaseAuraStrategy.sol\";\nimport { IBalancerVault } from \"../../interfaces/balancer/IBalancerVault.sol\";\nimport { IRateProvider } from \"../../interfaces/balancer/IRateProvider.sol\";\nimport { IMetaStablePool } from \"../../interfaces/balancer/IMetaStablePool.sol\";\nimport { IERC20, InitializableAbstractStrategy } from \"../../utils/InitializableAbstractStrategy.sol\";\nimport { StableMath } from \"../../utils/StableMath.sol\";\n\ncontract BalancerMetaPoolStrategy is BaseAuraStrategy {\n using SafeERC20 for IERC20;\n using StableMath for uint256;\n\n constructor(\n BaseStrategyConfig memory _stratConfig,\n BaseBalancerConfig memory _balancerConfig,\n address _auraRewardPoolAddress\n )\n InitializableAbstractStrategy(_stratConfig)\n BaseBalancerStrategy(_balancerConfig)\n BaseAuraStrategy(_auraRewardPoolAddress)\n {}\n\n /**\n * @notice There are no plans to configure BalancerMetaPool as a default\n * asset strategy. For that reason there is no need to support this\n * functionality.\n */\n function deposit(address, uint256)\n external\n override\n onlyVault\n nonReentrant\n {\n revert(\"Not supported\");\n }\n\n /**\n * @notice There are no plans to configure BalancerMetaPool as a default\n * asset strategy. For that reason there is no need to support this\n * functionality.\n */\n function deposit(address[] calldata, uint256[] calldata)\n external\n onlyVault\n nonReentrant\n {\n revert(\"Not supported\");\n }\n\n /**\n * @notice Deposits all supported assets in this strategy contract to the Balancer pool.\n */\n function depositAll() external override onlyVault nonReentrant {\n uint256 assetsLength = assetsMapped.length;\n address[] memory strategyAssets = new address[](assetsLength);\n uint256[] memory strategyAmounts = new uint256[](assetsLength);\n\n // For each vault collateral asset\n for (uint256 i = 0; i < assetsLength; ++i) {\n strategyAssets[i] = assetsMapped[i];\n // Get the asset balance in this strategy contract\n strategyAmounts[i] = IERC20(strategyAssets[i]).balanceOf(\n address(this)\n );\n }\n _deposit(strategyAssets, strategyAmounts);\n }\n\n /*\n * _deposit doesn't require a read-only re-entrancy protection since during the deposit\n * the function enters the Balancer Vault Context. If this function were called as part of\n * the attacking contract (while intercepting execution flow upon receiving ETH) the read-only\n * protection of the Balancer Vault would be triggered. Since the attacking contract would\n * already be in the Balancer Vault context and wouldn't be able to enter it again.\n */\n function _deposit(\n address[] memory _strategyAssets,\n uint256[] memory _strategyAmounts\n ) internal {\n require(\n _strategyAssets.length == _strategyAmounts.length,\n \"Array length missmatch\"\n );\n\n (IERC20[] memory tokens, , ) = balancerVault.getPoolTokens(\n balancerPoolId\n );\n\n uint256[] memory strategyAssetAmountsToPoolAssetAmounts = new uint256[](\n _strategyAssets.length\n );\n address[] memory strategyAssetsToPoolAssets = new address[](\n _strategyAssets.length\n );\n\n for (uint256 i = 0; i < _strategyAssets.length; ++i) {\n address strategyAsset = _strategyAssets[i];\n uint256 strategyAmount = _strategyAmounts[i];\n\n require(\n assetToPToken[strategyAsset] != address(0),\n \"Unsupported asset\"\n );\n strategyAssetsToPoolAssets[i] = _toPoolAsset(strategyAsset);\n\n if (strategyAmount > 0) {\n emit Deposit(strategyAsset, platformAddress, strategyAmount);\n\n // wrap rebasing assets like stETH and frxETH to wstETH and sfrxETH\n (, strategyAssetAmountsToPoolAssetAmounts[i]) = _wrapPoolAsset(\n strategyAsset,\n strategyAmount\n );\n }\n }\n\n uint256[] memory amountsIn = new uint256[](tokens.length);\n address[] memory poolAssets = new address[](tokens.length);\n for (uint256 i = 0; i < tokens.length; ++i) {\n // Convert IERC20 type to address\n poolAssets[i] = address(tokens[i]);\n\n // For each of the mapped assets\n for (uint256 j = 0; j < strategyAssetsToPoolAssets.length; ++j) {\n // If the pool asset is the same as the mapped asset\n if (poolAssets[i] == strategyAssetsToPoolAssets[j]) {\n amountsIn[i] = strategyAssetAmountsToPoolAssetAmounts[j];\n }\n }\n }\n\n uint256 minBPT = _getBPTExpected(\n strategyAssetsToPoolAssets,\n strategyAssetAmountsToPoolAssetAmounts\n );\n uint256 minBPTwDeviation = minBPT.mulTruncate(\n 1e18 - maxDepositDeviation\n );\n\n /* EXACT_TOKENS_IN_FOR_BPT_OUT:\n * User sends precise quantities of tokens, and receives an\n * estimated but unknown (computed at run time) quantity of BPT.\n *\n * ['uint256', 'uint256[]', 'uint256']\n * [EXACT_TOKENS_IN_FOR_BPT_OUT, amountsIn, minimumBPT]\n */\n bytes memory userData = abi.encode(\n IBalancerVault.WeightedPoolJoinKind.EXACT_TOKENS_IN_FOR_BPT_OUT,\n amountsIn,\n minBPTwDeviation\n );\n\n IBalancerVault.JoinPoolRequest memory request = IBalancerVault\n .JoinPoolRequest(poolAssets, amountsIn, userData, false);\n\n // Add the pool assets in this strategy to the balancer pool\n balancerVault.joinPool(\n balancerPoolId,\n address(this),\n address(this),\n request\n );\n\n // Deposit the Balancer Pool Tokens (BPT) into Aura\n _lpDepositAll();\n }\n\n /**\n * @notice Withdraw a Vault collateral asset from the Balancer pool.\n * @param _recipient Address to receive the Vault collateral assets. Typically is the Vault.\n * @param _strategyAsset Address of the Vault collateral asset\n * @param _strategyAmount The amount of Vault collateral assets to withdraw\n */\n function withdraw(\n address _recipient,\n address _strategyAsset,\n uint256 _strategyAmount\n ) external override onlyVault nonReentrant {\n address[] memory strategyAssets = new address[](1);\n uint256[] memory strategyAmounts = new uint256[](1);\n strategyAssets[0] = _strategyAsset;\n strategyAmounts[0] = _strategyAmount;\n\n _withdraw(_recipient, strategyAssets, strategyAmounts);\n }\n\n /**\n * @notice Withdraw multiple Vault collateral asset from the Balancer pool.\n * @param _recipient Address to receive the Vault collateral assets. Typically is the Vault.\n * @param _strategyAssets Addresses of the Vault collateral assets\n * @param _strategyAmounts The amounts of Vault collateral assets to withdraw\n */\n function withdraw(\n address _recipient,\n address[] calldata _strategyAssets,\n uint256[] calldata _strategyAmounts\n ) external onlyVault nonReentrant {\n _withdraw(_recipient, _strategyAssets, _strategyAmounts);\n }\n\n /**\n * @dev Withdraw multiple Vault collateral asset from the Balancer pool.\n * @param _recipient Address to receive the Vault collateral assets. Typically is the Vault.\n * @param _strategyAssets Addresses of the Vault collateral assets\n * @param _strategyAmounts The amounts of Vault collateral assets to withdraw\n *\n * _withdrawal doesn't require a read-only re-entrancy protection since during the withdrawal\n * the function enters the Balancer Vault Context. If this function were called as part of\n * the attacking contract (while intercepting execution flow upon receiving ETH) the read-only\n * protection of the Balancer Vault would be triggered. Since the attacking contract would\n * already be in the Balancer Vault context and wouldn't be able to enter it again.\n */\n function _withdraw(\n address _recipient,\n address[] memory _strategyAssets,\n uint256[] memory _strategyAmounts\n ) internal {\n require(\n _strategyAssets.length == _strategyAmounts.length,\n \"Invalid input arrays\"\n );\n\n for (uint256 i = 0; i < _strategyAssets.length; ++i) {\n require(\n assetToPToken[_strategyAssets[i]] != address(0),\n \"Unsupported asset\"\n );\n }\n\n // STEP 1 - Calculate the Balancer pool assets and amounts from the vault collateral assets\n\n // Get all the supported balancer pool assets\n (IERC20[] memory tokens, , ) = balancerVault.getPoolTokens(\n balancerPoolId\n );\n // Calculate the balancer pool assets and amounts to withdraw\n uint256[] memory poolAssetsAmountsOut = new uint256[](tokens.length);\n address[] memory poolAssets = new address[](tokens.length);\n // Is the wrapped asset amount indexed by the assets array, not the order of the Balancer pool tokens\n // eg wstETH and sfrxETH amounts, not the stETH and frxETH amounts\n uint256[] memory strategyAssetsToPoolAssetsAmounts = new uint256[](\n _strategyAssets.length\n );\n\n // For each of the Balancer pool assets\n for (uint256 i = 0; i < tokens.length; ++i) {\n poolAssets[i] = address(tokens[i]);\n\n // Convert the Balancer pool asset back to a vault collateral asset\n address strategyAsset = _fromPoolAsset(poolAssets[i]);\n\n // for each of the vault assets\n for (uint256 j = 0; j < _strategyAssets.length; ++j) {\n // If the vault asset equals the vault asset mapped from the Balancer pool asset\n if (_strategyAssets[j] == strategyAsset) {\n (, poolAssetsAmountsOut[i]) = _toPoolAsset(\n strategyAsset,\n _strategyAmounts[j]\n );\n strategyAssetsToPoolAssetsAmounts[j] = poolAssetsAmountsOut[\n i\n ];\n\n /* Because of the potential Balancer rounding error mentioned below\n * the contract might receive 1-2 WEI smaller amount than required\n * in the withdraw user data encoding. If slightly lesser token amount\n * is received the strategy can not unwrap the pool asset as it is\n * smaller than expected.\n *\n * For that reason we `overshoot` the required tokens expected to\n * circumvent the error\n */\n if (poolAssetsAmountsOut[i] > 0) {\n poolAssetsAmountsOut[i] += 2;\n }\n }\n }\n }\n\n // STEP 2 - Calculate the max about of Balancer Pool Tokens (BPT) to withdraw\n\n // Estimate the required amount of Balancer Pool Tokens (BPT) for the assets\n uint256 maxBPTtoWithdraw = _getBPTExpected(\n poolAssets,\n /* all non 0 values are overshot by 2 WEI and with the expected mainnet\n * ~1% withdrawal deviation, the 2 WEI aren't important\n */\n poolAssetsAmountsOut\n );\n // Increase BPTs by the max allowed deviation\n // Any excess BPTs will be left in this strategy contract\n maxBPTtoWithdraw = maxBPTtoWithdraw.mulTruncate(\n 1e18 + maxWithdrawalDeviation\n );\n\n // STEP 3 - Withdraw the Balancer Pool Tokens (BPT) from Aura to this strategy contract\n\n // Withdraw BPT from Aura allowing for BPTs left in this strategy contract from previous withdrawals\n _lpWithdraw(\n maxBPTtoWithdraw - IERC20(platformAddress).balanceOf(address(this))\n );\n\n // STEP 4 - Withdraw the balancer pool assets from the pool\n\n /* Custom asset exit: BPT_IN_FOR_EXACT_TOKENS_OUT:\n * User sends an estimated but unknown (computed at run time) quantity of BPT,\n * and receives precise quantities of specified tokens.\n *\n * ['uint256', 'uint256[]', 'uint256']\n * [BPT_IN_FOR_EXACT_TOKENS_OUT, amountsOut, maxBPTAmountIn]\n */\n bytes memory userData = abi.encode(\n IBalancerVault.WeightedPoolExitKind.BPT_IN_FOR_EXACT_TOKENS_OUT,\n poolAssetsAmountsOut,\n maxBPTtoWithdraw\n );\n\n IBalancerVault.ExitPoolRequest memory request = IBalancerVault\n .ExitPoolRequest(\n poolAssets,\n /* We specify the exact amount of a tokens we are expecting in the encoded\n * userData, for that reason we don't need to specify the amountsOut here.\n *\n * Also Balancer has a rounding issue that can make a transaction fail:\n * https://github.com/balancer/balancer-v2-monorepo/issues/2541\n * which is an extra reason why this field is empty.\n */\n new uint256[](tokens.length),\n userData,\n false\n );\n\n balancerVault.exitPool(\n balancerPoolId,\n address(this),\n /* Payable keyword is required because of the IBalancerVault interface even though\n * this strategy shall never be receiving native ETH\n */\n payable(address(this)),\n request\n );\n\n // STEP 5 - Re-deposit any left over BPT tokens back into Aura\n /* When concluding how much of BPT we need to withdraw from Aura we overshoot by\n * roughly around 1% (initial mainnet setting of maxWithdrawalDeviation). After exiting\n * the pool strategy could have left over BPT tokens that are not earning boosted yield.\n * We re-deploy those back in.\n */\n _lpDepositAll();\n\n // STEP 6 - Unswap balancer pool assets to vault collateral assets and send to the vault.\n\n // For each of the specified assets\n for (uint256 i = 0; i < _strategyAssets.length; ++i) {\n // Unwrap assets like wstETH and sfrxETH to rebasing assets stETH and frxETH\n if (strategyAssetsToPoolAssetsAmounts[i] > 0) {\n _unwrapPoolAsset(\n _strategyAssets[i],\n strategyAssetsToPoolAssetsAmounts[i]\n );\n }\n\n // Transfer the vault collateral assets to the recipient, which is typically the vault\n if (_strategyAmounts[i] > 0) {\n IERC20(_strategyAssets[i]).safeTransfer(\n _recipient,\n _strategyAmounts[i]\n );\n\n emit Withdrawal(\n _strategyAssets[i],\n platformAddress,\n _strategyAmounts[i]\n );\n }\n }\n }\n\n /**\n * @notice Withdraws all supported Vault collateral assets from the Balancer pool\n * and send to the OToken's Vault.\n *\n * Is only executable by the OToken's Vault or the Governor.\n */\n function withdrawAll() external override onlyVaultOrGovernor nonReentrant {\n // STEP 1 - Withdraw all Balancer Pool Tokens (BPT) from Aura to this strategy contract\n\n _lpWithdrawAll();\n // Get the BPTs withdrawn from Aura plus any that were already in this strategy contract\n uint256 BPTtoWithdraw = IERC20(platformAddress).balanceOf(\n address(this)\n );\n // Get the balancer pool assets and their total balances\n (IERC20[] memory tokens, , ) = balancerVault.getPoolTokens(\n balancerPoolId\n );\n uint256[] memory minAmountsOut = new uint256[](tokens.length);\n address[] memory poolAssets = new address[](tokens.length);\n for (uint256 i = 0; i < tokens.length; ++i) {\n poolAssets[i] = address(tokens[i]);\n }\n\n // STEP 2 - Withdraw the Balancer pool assets from the pool\n /* Proportional exit: EXACT_BPT_IN_FOR_TOKENS_OUT:\n * User sends a precise quantity of BPT, and receives an estimated but unknown\n * (computed at run time) quantity of a single token\n *\n * ['uint256', 'uint256']\n * [EXACT_BPT_IN_FOR_TOKENS_OUT, bptAmountIn]\n *\n * It is ok to pass an empty minAmountsOut since tilting the pool in any direction\n * when doing a proportional exit can only be beneficial to the strategy. Since\n * it will receive more of the underlying tokens for the BPT traded in.\n */\n bytes memory userData = abi.encode(\n IBalancerVault.WeightedPoolExitKind.EXACT_BPT_IN_FOR_TOKENS_OUT,\n BPTtoWithdraw\n );\n\n IBalancerVault.ExitPoolRequest memory request = IBalancerVault\n .ExitPoolRequest(poolAssets, minAmountsOut, userData, false);\n\n balancerVault.exitPool(\n balancerPoolId,\n address(this),\n /* Payable keyword is required because of the IBalancerVault interface even though\n * this strategy shall never be receiving native ETH\n */\n payable(address(this)),\n request\n );\n\n // STEP 3 - Convert the balancer pool assets to the vault collateral assets and send to the vault\n // For each of the Balancer pool assets\n for (uint256 i = 0; i < tokens.length; ++i) {\n address poolAsset = address(tokens[i]);\n // Convert the balancer pool asset to the strategy asset\n address strategyAsset = _fromPoolAsset(poolAsset);\n // Get the balancer pool assets withdraw from the pool plus any that were already in this strategy contract\n uint256 poolAssetAmount = IERC20(poolAsset).balanceOf(\n address(this)\n );\n\n // Unwrap assets like wstETH and sfrxETH to rebasing assets stETH and frxETH\n uint256 unwrappedAmount = 0;\n if (poolAssetAmount > 0) {\n unwrappedAmount = _unwrapPoolAsset(\n strategyAsset,\n poolAssetAmount\n );\n }\n\n // Transfer the vault collateral assets to the vault\n if (unwrappedAmount > 0) {\n IERC20(strategyAsset).safeTransfer(\n vaultAddress,\n unwrappedAmount\n );\n emit Withdrawal(\n strategyAsset,\n platformAddress,\n unwrappedAmount\n );\n }\n }\n }\n\n /**\n * @notice Approves the Balancer Vault to transfer poolAsset counterparts\n * of all of the supported assets from this strategy. E.g. stETH is a supported\n * strategy and Balancer Vault gets unlimited approval to transfer wstETH.\n *\n * If Balancer pool uses a wrapped version of a supported asset then also approve\n * unlimited usage of an asset to the contract responsible for wrapping.\n *\n * Approve unlimited spending by Balancer Vault and Aura reward pool of the\n * pool BPT tokens.\n *\n * Is only executable by the Governor.\n */\n function safeApproveAllTokens()\n external\n override\n onlyGovernor\n nonReentrant\n {\n uint256 assetCount = assetsMapped.length;\n for (uint256 i = 0; i < assetCount; ++i) {\n _abstractSetPToken(assetsMapped[i], platformAddress);\n }\n _approveBase();\n }\n\n // solhint-disable-next-line no-unused-vars\n function _abstractSetPToken(address _asset, address) internal override {\n address poolAsset = _toPoolAsset(_asset);\n if (_asset == stETH) {\n // slither-disable-next-line unused-return\n IERC20(stETH).approve(wstETH, type(uint256).max);\n } else if (_asset == frxETH) {\n // slither-disable-next-line unused-return\n IERC20(frxETH).approve(sfrxETH, type(uint256).max);\n }\n _approveAsset(poolAsset);\n }\n\n /**\n * @dev Approves the Balancer Vault to transfer an asset from\n * this strategy. The assets could be a Vault collateral asset\n * like WETH or rETH; or a Balancer pool asset that wraps the vault asset\n * like wstETH or sfrxETH.\n */\n function _approveAsset(address _asset) internal {\n IERC20 asset = IERC20(_asset);\n // slither-disable-next-line unused-return\n asset.approve(address(balancerVault), type(uint256).max);\n }\n\n /**\n * @notice Returns the rate supplied by the Balancer configured rate\n * provider. Rate is used to normalize the token to common underlying\n * pool denominator. (ETH for ETH Liquid staking derivatives)\n *\n * @param _asset Address of the Balancer pool asset\n * @return rate of the corresponding asset\n */\n function _getRateProviderRate(address _asset)\n internal\n view\n override\n returns (uint256)\n {\n IMetaStablePool pool = IMetaStablePool(platformAddress);\n IRateProvider[] memory providers = pool.getRateProviders();\n (IERC20[] memory tokens, , ) = balancerVault.getPoolTokens(\n balancerPoolId\n );\n\n uint256 providersLength = providers.length;\n for (uint256 i = 0; i < providersLength; ++i) {\n // _assets and corresponding rate providers are all in the same order\n if (address(tokens[i]) == _asset) {\n // rate provider doesn't exist, defaults to 1e18\n if (address(providers[i]) == address(0)) {\n return 1e18;\n }\n return providers[i].getRate();\n }\n }\n\n // should never happen\n assert(false);\n }\n}\n" + }, + "contracts/strategies/balancer/BaseAuraStrategy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title OETH Base Balancer Abstract Strategy\n * @author Origin Protocol Inc\n */\n\nimport { BaseBalancerStrategy } from \"./BaseBalancerStrategy.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20 } from \"../../utils/InitializableAbstractStrategy.sol\";\nimport { IERC4626 } from \"../../../lib/openzeppelin/interfaces/IERC4626.sol\";\nimport { StableMath } from \"../../utils/StableMath.sol\";\nimport { IRewardStaking } from \"../IRewardStaking.sol\";\n\nabstract contract BaseAuraStrategy is BaseBalancerStrategy {\n using SafeERC20 for IERC20;\n using StableMath for uint256;\n\n /// @notice Address of the Aura rewards pool\n address public immutable auraRewardPoolAddress;\n\n // renamed from __reserved to not shadow BaseBalancerStrategy.__reserved,\n int256[50] private __reserved_baseAuraStrategy;\n\n constructor(address _auraRewardPoolAddress) {\n auraRewardPoolAddress = _auraRewardPoolAddress;\n }\n\n /**\n * @dev Deposit all Balancer Pool Tokens (BPT) in this strategy contract\n * to the Aura rewards pool.\n */\n function _lpDepositAll() internal virtual override {\n uint256 bptBalance = IERC20(platformAddress).balanceOf(address(this));\n uint256 auraLp = IERC4626(auraRewardPoolAddress).deposit(\n bptBalance,\n address(this)\n );\n require(bptBalance == auraLp, \"Aura LP != BPT\");\n }\n\n /**\n * @dev Withdraw `numBPTTokens` Balancer Pool Tokens (BPT) from\n * the Aura rewards pool to this strategy contract.\n * @param numBPTTokens Number of Balancer Pool Tokens (BPT) to withdraw\n */\n function _lpWithdraw(uint256 numBPTTokens) internal virtual override {\n IRewardStaking(auraRewardPoolAddress).withdrawAndUnwrap(\n numBPTTokens,\n true // also claim reward tokens\n );\n }\n\n /**\n * @dev Withdraw all Balancer Pool Tokens (BPT) from\n * the Aura rewards pool to this strategy contract.\n */\n function _lpWithdrawAll() internal virtual override {\n // Get all the strategy's BPTs in Aura\n // maxRedeem is implemented as balanceOf(address) in Aura\n uint256 bptBalance = IERC4626(auraRewardPoolAddress).maxRedeem(\n address(this)\n );\n\n IRewardStaking(auraRewardPoolAddress).withdrawAndUnwrap(\n bptBalance,\n true // also claim reward tokens\n );\n }\n\n /**\n * @notice Collects BAL and AURA tokens from the rewards pool.\n */\n function collectRewardTokens()\n external\n virtual\n override\n onlyHarvester\n nonReentrant\n {\n /* Similar to Convex, calling this function collects both of the\n * accrued BAL and AURA tokens.\n */\n IRewardStaking(auraRewardPoolAddress).getReward();\n _collectRewardTokens();\n }\n\n /// @notice Balancer Pool Tokens (BPT) in the Balancer pool and the Aura rewards pool.\n function _getBalancerPoolTokens()\n internal\n view\n override\n returns (uint256 balancerPoolTokens)\n {\n balancerPoolTokens =\n IERC20(platformAddress).balanceOf(address(this)) +\n // maxRedeem is implemented as balanceOf(address) in Aura\n IERC4626(auraRewardPoolAddress).maxRedeem(address(this));\n }\n\n function _approveBase() internal virtual override {\n super._approveBase();\n\n IERC20 pToken = IERC20(platformAddress);\n pToken.safeApprove(auraRewardPoolAddress, type(uint256).max);\n }\n}\n" + }, + "contracts/strategies/balancer/BaseBalancerStrategy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title OETH Base Balancer Abstract Strategy\n * @author Origin Protocol Inc\n */\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20, InitializableAbstractStrategy } from \"../../utils/InitializableAbstractStrategy.sol\";\nimport { IBalancerVault } from \"../../interfaces/balancer/IBalancerVault.sol\";\nimport { IRateProvider } from \"../../interfaces/balancer/IRateProvider.sol\";\nimport { VaultReentrancyLib } from \"./VaultReentrancyLib.sol\";\nimport { IOracle } from \"../../interfaces/IOracle.sol\";\nimport { IWstETH } from \"../../interfaces/IWstETH.sol\";\nimport { IERC4626 } from \"../../../lib/openzeppelin/interfaces/IERC4626.sol\";\nimport { StableMath } from \"../../utils/StableMath.sol\";\n\nabstract contract BaseBalancerStrategy is InitializableAbstractStrategy {\n using SafeERC20 for IERC20;\n using StableMath for uint256;\n\n address public immutable rETH;\n address public immutable stETH;\n address public immutable wstETH;\n address public immutable frxETH;\n address public immutable sfrxETH;\n\n /// @notice Address of the Balancer vault\n IBalancerVault public immutable balancerVault;\n /// @notice Balancer pool identifier\n bytes32 public immutable balancerPoolId;\n\n // Max withdrawal deviation denominated in 1e18 (1e18 == 100%)\n uint256 public maxWithdrawalDeviation;\n // Max deposit deviation denominated in 1e18 (1e18 == 100%)\n uint256 public maxDepositDeviation;\n\n int256[48] private __reserved;\n\n struct BaseBalancerConfig {\n address rEthAddress; // Address of the rETH token\n address stEthAddress; // Address of the stETH token\n address wstEthAddress; // Address of the wstETH token\n address frxEthAddress; // Address of the frxEth token\n address sfrxEthAddress; // Address of the sfrxEth token\n address balancerVaultAddress; // Address of the Balancer vault\n bytes32 balancerPoolId; // Balancer pool identifier\n }\n\n event MaxWithdrawalDeviationUpdated(\n uint256 _prevMaxDeviationPercentage,\n uint256 _newMaxDeviationPercentage\n );\n event MaxDepositDeviationUpdated(\n uint256 _prevMaxDeviationPercentage,\n uint256 _newMaxDeviationPercentage\n );\n\n /**\n * @dev Ensure we are not in a Vault context when this function is called, by attempting a no-op internal\n * balance operation. If we are already in a Vault transaction (e.g., a swap, join, or exit), the Vault's\n * reentrancy protection will cause this function to revert.\n *\n * Use this modifier with any function that can cause a state change in a pool and is either public itself,\n * or called by a public function *outside* a Vault operation (e.g., join, exit, or swap).\n *\n * This is to protect against Balancer's read-only re-entrancy vulnerability:\n * https://www.notion.so/originprotocol/Balancer-read-only-reentrancy-c686e72c82414ef18fa34312bb02e11b\n */\n modifier whenNotInBalancerVaultContext() {\n VaultReentrancyLib.ensureNotInVaultContext(balancerVault);\n _;\n }\n\n constructor(BaseBalancerConfig memory _balancerConfig) {\n rETH = _balancerConfig.rEthAddress;\n stETH = _balancerConfig.stEthAddress;\n wstETH = _balancerConfig.wstEthAddress;\n frxETH = _balancerConfig.frxEthAddress;\n sfrxETH = _balancerConfig.sfrxEthAddress;\n\n balancerVault = IBalancerVault(_balancerConfig.balancerVaultAddress);\n balancerPoolId = _balancerConfig.balancerPoolId;\n }\n\n /**\n * Initializer for setting up strategy internal state. This overrides the\n * InitializableAbstractStrategy initializer as Balancer's strategies don't fit\n * well within that abstraction.\n * @param _rewardTokenAddresses Address of BAL & AURA\n * @param _assets Addresses of supported assets. MUST be passed in the same\n * order as returned by coins on the pool contract, i.e.\n * WETH, stETH\n * @param _pTokens Platform Token corresponding addresses\n */\n function initialize(\n address[] calldata _rewardTokenAddresses, // BAL & AURA\n address[] calldata _assets,\n address[] calldata _pTokens\n ) external onlyGovernor initializer {\n maxWithdrawalDeviation = 1e16;\n maxDepositDeviation = 1e16;\n\n emit MaxWithdrawalDeviationUpdated(0, maxWithdrawalDeviation);\n emit MaxDepositDeviationUpdated(0, maxDepositDeviation);\n\n IERC20[] memory poolAssets = _getPoolAssets();\n require(\n poolAssets.length == _assets.length,\n \"Pool assets length mismatch\"\n );\n for (uint256 i = 0; i < _assets.length; ++i) {\n address asset = _fromPoolAsset(address(poolAssets[i]));\n require(_assets[i] == asset, \"Pool assets mismatch\");\n }\n\n InitializableAbstractStrategy._initialize(\n _rewardTokenAddresses,\n _assets,\n _pTokens\n );\n _approveBase();\n }\n\n /**\n * @notice Returns bool indicating whether asset is supported by strategy\n * @param _asset Address of the asset\n */\n function supportsAsset(address _asset) public view override returns (bool) {\n return assetToPToken[_asset] != address(0);\n }\n\n /**\n * @notice Get strategy's share of an assets in the Balancer pool.\n * This is not denominated in OUSD/ETH value of the assets in the Balancer pool.\n * @param _asset Address of the Vault collateral asset\n * @return amount the amount of vault collateral assets\n *\n * IMPORTANT if this function is overridden it needs to have a whenNotInBalancerVaultContext\n * modifier on it or it is susceptible to read-only re-entrancy attack\n *\n * @dev it is important that this function is not affected by reporting inflated\n * values of assets in case of any pool manipulation. Such a manipulation could easily\n * exploit the protocol by:\n * - minting OETH\n * - tilting Balancer pool to report higher balances of assets\n * - rebasing() -> all that extra token balances get distributed to OETH holders\n * - tilting pool back\n * - redeeming OETH\n */\n function checkBalance(address _asset)\n external\n view\n virtual\n override\n whenNotInBalancerVaultContext\n returns (uint256 amount)\n {\n require(assetToPToken[_asset] != address(0), \"Unsupported asset\");\n\n uint256 bptBalance = _getBalancerPoolTokens();\n\n /* To calculate the worth of queried asset:\n * - assume that all tokens normalized to their ETH value have an equal split balance\n * in the pool when it is balanced\n * - multiply the BPT amount with the bpt rate to get the ETH denominated amount\n * of strategy's holdings\n * - divide that by the number of tokens we support in the pool to get ETH denominated\n * amount that is applicable to each supported token in the pool.\n *\n * It would be possible to support only 1 asset in the pool (and be exposed to all\n * the assets while holding BPT tokens) and deposit/withdraw/checkBalance using only\n * that asset. TBD: changes to other functions still required if we ever decide to\n * go with such configuration.\n */\n amount = (bptBalance.mulTruncate(\n IRateProvider(platformAddress).getRate()\n ) / assetsMapped.length);\n\n /* If the pool asset is equal to (strategy )_asset it means that a rate\n * provider for that asset exists and that asset is not necessarily\n * pegged to a unit (ETH).\n *\n * Because this function returns the balance of the asset and is not denominated in\n * ETH units we need to convert the ETH denominated amount to asset amount.\n */\n if (_toPoolAsset(_asset) == _asset) {\n amount = amount.divPrecisely(_getRateProviderRate(_asset));\n }\n }\n\n /**\n * @notice Returns the value of all assets managed by this strategy.\n * Uses the Balancer pool's rate (virtual price) to convert the strategy's\n * Balancer Pool Tokens (BPT) to ETH value.\n * @return value The ETH value\n *\n * IMPORTANT if this function is overridden it needs to have a whenNotInBalancerVaultContext\n * modifier on it or it is susceptible to read-only re-entrancy attack\n */\n function checkBalance()\n external\n view\n virtual\n whenNotInBalancerVaultContext\n returns (uint256 value)\n {\n uint256 bptBalance = _getBalancerPoolTokens();\n\n // Convert BPT to ETH value\n value = bptBalance.mulTruncate(\n IRateProvider(platformAddress).getRate()\n );\n }\n\n /// @notice Balancer Pool Tokens (BPT) in the Balancer pool.\n function _getBalancerPoolTokens()\n internal\n view\n virtual\n returns (uint256 balancerPoolTokens)\n {\n balancerPoolTokens = IERC20(platformAddress).balanceOf(address(this));\n }\n\n /* solhint-disable max-line-length */\n /**\n * @notice BPT price is calculated by taking the rate from the rateProvider of the asset in\n * question. If one does not exist it defaults to 1e18. To get the final BPT expected that\n * is multiplied by the underlying asset amount divided by BPT token rate. BPT token rate is\n * similar to Curve's virtual_price and expresses how much has the price of BPT appreciated\n * (e.g. due to swap fees) in relation to the underlying assets\n *\n * Using the above approach makes the strategy vulnerable to a possible MEV attack using\n * flash loan to manipulate the pool before a deposit/withdrawal since the function ignores\n * market values of the assets being priced in BPT.\n *\n * At the time of writing there is no safe on-chain approach to pricing BPT in a way that it\n * would make it invulnerable to MEV pool manipulation. See recent Balancer exploit:\n * https://www.notion.so/originprotocol/Balancer-OETH-strategy-9becdea132704e588782a919d7d471eb?pvs=4#1cf07de12fc64f1888072321e0644348\n *\n * To mitigate MEV possibilities during deposits and withdraws, the VaultValueChecker will use checkBalance before and after the move\n * to ensure the expected changes took place.\n *\n * @param _asset Address of the Balancer pool asset\n * @param _amount Amount of the Balancer pool asset\n * @return bptExpected of BPT expected in exchange for the asset\n *\n * @dev\n * bptAssetPrice = 1e18 (asset peg) * pool_asset_rate\n *\n * bptExpected = bptAssetPrice * asset_amount / BPT_token_rate\n *\n * bptExpected = 1e18 (asset peg) * pool_asset_rate * asset_amount / BPT_token_rate\n * bptExpected = asset_amount * pool_asset_rate / BPT_token_rate\n *\n * further information available here:\n * https://www.notion.so/originprotocol/Balancer-OETH-strategy-9becdea132704e588782a919d7d471eb?pvs=4#ce01495ae70346d8971f5dced809fb83\n */\n /* solhint-enable max-line-length */\n function _getBPTExpected(address _asset, uint256 _amount)\n internal\n view\n virtual\n returns (uint256 bptExpected)\n {\n uint256 bptRate = IRateProvider(platformAddress).getRate();\n uint256 poolAssetRate = _getRateProviderRate(_asset);\n bptExpected = _amount.mulTruncate(poolAssetRate).divPrecisely(bptRate);\n }\n\n function _getBPTExpected(\n address[] memory _assets,\n uint256[] memory _amounts\n ) internal view virtual returns (uint256 bptExpected) {\n require(_assets.length == _amounts.length, \"Assets & amounts mismatch\");\n\n for (uint256 i = 0; i < _assets.length; ++i) {\n uint256 poolAssetRate = _getRateProviderRate(_assets[i]);\n // convert asset amount to ETH amount\n bptExpected += _amounts[i].mulTruncate(poolAssetRate);\n }\n\n uint256 bptRate = IRateProvider(platformAddress).getRate();\n // Convert ETH amount to BPT amount\n bptExpected = bptExpected.divPrecisely(bptRate);\n }\n\n function _lpDepositAll() internal virtual;\n\n function _lpWithdraw(uint256 numBPTTokens) internal virtual;\n\n function _lpWithdrawAll() internal virtual;\n\n /**\n * @notice Balancer returns assets and rateProviders for corresponding assets ordered\n * by numerical order.\n */\n function _getPoolAssets() internal view returns (IERC20[] memory assets) {\n // slither-disable-next-line unused-return\n (assets, , ) = balancerVault.getPoolTokens(balancerPoolId);\n }\n\n /**\n * @dev If an asset is rebasing the Balancer pools have a wrapped versions of assets\n * that the strategy supports. This function converts the pool(wrapped) asset\n * and corresponding amount to strategy asset.\n */\n function _toPoolAsset(address asset, uint256 amount)\n internal\n view\n returns (address poolAsset, uint256 poolAmount)\n {\n if (asset == stETH) {\n poolAsset = wstETH;\n if (amount > 0) {\n poolAmount = IWstETH(wstETH).getWstETHByStETH(amount);\n }\n } else if (asset == frxETH) {\n poolAsset = sfrxETH;\n if (amount > 0) {\n poolAmount = IERC4626(sfrxETH).convertToShares(amount);\n }\n } else {\n poolAsset = asset;\n poolAmount = amount;\n }\n }\n\n /**\n * @dev Converts a Vault collateral asset to a Balancer pool asset.\n * stETH becomes wstETH, frxETH becomes sfrxETH and everything else stays the same.\n * @param asset Address of the Vault collateral asset.\n * @return Address of the Balancer pool asset.\n */\n function _toPoolAsset(address asset) internal view returns (address) {\n if (asset == stETH) {\n return wstETH;\n } else if (asset == frxETH) {\n return sfrxETH;\n }\n return asset;\n }\n\n /**\n * @dev Converts rebasing asset to its wrapped counterpart.\n */\n function _wrapPoolAsset(address asset, uint256 amount)\n internal\n returns (address wrappedAsset, uint256 wrappedAmount)\n {\n if (asset == stETH) {\n wrappedAsset = wstETH;\n if (amount > 0) {\n wrappedAmount = IWstETH(wstETH).wrap(amount);\n }\n } else if (asset == frxETH) {\n wrappedAsset = sfrxETH;\n if (amount > 0) {\n wrappedAmount = IERC4626(sfrxETH).deposit(\n amount,\n address(this)\n );\n }\n } else {\n wrappedAsset = asset;\n wrappedAmount = amount;\n }\n }\n\n /**\n * @dev Converts wrapped asset to its rebasing counterpart.\n */\n function _unwrapPoolAsset(address asset, uint256 amount)\n internal\n returns (uint256 unwrappedAmount)\n {\n if (asset == stETH) {\n unwrappedAmount = IWstETH(wstETH).unwrap(amount);\n } else if (asset == frxETH) {\n unwrappedAmount = IERC4626(sfrxETH).withdraw(\n amount,\n address(this),\n address(this)\n );\n } else {\n unwrappedAmount = amount;\n }\n }\n\n /**\n * @dev If an asset is rebasing the Balancer pools have a wrapped versions of assets\n * that the strategy supports. This function converts the rebasing strategy asset\n * and corresponding amount to wrapped(pool) asset.\n */\n function _fromPoolAsset(address poolAsset, uint256 poolAmount)\n internal\n view\n returns (address asset, uint256 amount)\n {\n if (poolAsset == wstETH) {\n asset = stETH;\n if (poolAmount > 0) {\n amount = IWstETH(wstETH).getStETHByWstETH(poolAmount);\n }\n } else if (poolAsset == sfrxETH) {\n asset = frxETH;\n if (poolAmount > 0) {\n amount = IERC4626(sfrxETH).convertToAssets(poolAmount);\n }\n } else {\n asset = poolAsset;\n amount = poolAmount;\n }\n }\n\n function _fromPoolAsset(address poolAsset)\n internal\n view\n returns (address asset)\n {\n if (poolAsset == wstETH) {\n asset = stETH;\n } else if (poolAsset == sfrxETH) {\n asset = frxETH;\n } else {\n asset = poolAsset;\n }\n }\n\n /**\n * @notice Sets max withdrawal deviation that is considered when removing\n * liquidity from Balancer pools.\n * @param _maxWithdrawalDeviation Max withdrawal deviation denominated in\n * wad (number with 18 decimals): 1e18 == 100%, 1e16 == 1%\n *\n * IMPORTANT Minimum maxWithdrawalDeviation will be 1% (1e16) for production\n * usage. Vault value checker in combination with checkBalance will\n * catch any unexpected manipulation.\n */\n function setMaxWithdrawalDeviation(uint256 _maxWithdrawalDeviation)\n external\n onlyVaultOrGovernorOrStrategist\n {\n require(\n _maxWithdrawalDeviation <= 1e18,\n \"Withdrawal dev. out of bounds\"\n );\n emit MaxWithdrawalDeviationUpdated(\n maxWithdrawalDeviation,\n _maxWithdrawalDeviation\n );\n maxWithdrawalDeviation = _maxWithdrawalDeviation;\n }\n\n /**\n * @notice Sets max deposit deviation that is considered when adding\n * liquidity to Balancer pools.\n * @param _maxDepositDeviation Max deposit deviation denominated in\n * wad (number with 18 decimals): 1e18 == 100%, 1e16 == 1%\n *\n * IMPORTANT Minimum maxDepositDeviation will default to 1% (1e16)\n * for production usage. Vault value checker in combination with\n * checkBalance will catch any unexpected manipulation.\n */\n function setMaxDepositDeviation(uint256 _maxDepositDeviation)\n external\n onlyVaultOrGovernorOrStrategist\n {\n require(_maxDepositDeviation <= 1e18, \"Deposit dev. out of bounds\");\n emit MaxDepositDeviationUpdated(\n maxDepositDeviation,\n _maxDepositDeviation\n );\n maxDepositDeviation = _maxDepositDeviation;\n }\n\n function _approveBase() internal virtual {\n IERC20 pToken = IERC20(platformAddress);\n // Balancer vault for BPT token (required for removing liquidity)\n pToken.safeApprove(address(balancerVault), type(uint256).max);\n }\n\n function _getRateProviderRate(address _asset)\n internal\n view\n virtual\n returns (uint256);\n}\n" + }, + "contracts/strategies/balancer/VaultReentrancyLib.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see .\n\npragma solidity >=0.7.0 <0.9.0;\n\nimport \"../../utils/BalancerErrors.sol\";\nimport { IBalancerVault } from \"../../interfaces/balancer/IBalancerVault.sol\";\n\nlibrary VaultReentrancyLib {\n /**\n * @dev Ensure we are not in a Vault context when this function is called, by attempting a no-op internal\n * balance operation. If we are already in a Vault transaction (e.g., a swap, join, or exit), the Vault's\n * reentrancy protection will cause this function to revert.\n *\n * The exact function call doesn't really matter: we're just trying to trigger the Vault reentrancy check\n * (and not hurt anything in case it works). An empty operation array with no specific operation at all works\n * for that purpose, and is also the least expensive in terms of gas and bytecode size.\n *\n * Call this at the top of any function that can cause a state change in a pool and is either public itself,\n * or called by a public function *outside* a Vault operation (e.g., join, exit, or swap).\n *\n * If this is *not* called in functions that are vulnerable to the read-only reentrancy issue described\n * here (https://forum.balancer.fi/t/reentrancy-vulnerability-scope-expanded/4345), those functions are unsafe,\n * and subject to manipulation that may result in loss of funds.\n */\n function ensureNotInVaultContext(IBalancerVault vault) internal view {\n // Perform the following operation to trigger the Vault's reentrancy guard:\n //\n // IBalancerVault.UserBalanceOp[] memory noop = new IBalancerVault.UserBalanceOp[](0);\n // _vault.manageUserBalance(noop);\n //\n // However, use a static call so that it can be a view function (even though the function is non-view).\n // This allows the library to be used more widely, as some functions that need to be protected might be\n // view.\n //\n // This staticcall always reverts, but we need to make sure it doesn't fail due to a re-entrancy attack.\n // Staticcalls consume all gas forwarded to them on a revert caused by storage modification.\n // By default, almost the entire available gas is forwarded to the staticcall,\n // causing the entire call to revert with an 'out of gas' error.\n //\n // We set the gas limit to 10k for the staticcall to\n // avoid wasting gas when it reverts due to storage modification.\n // `manageUserBalance` is a non-reentrant function in the Vault, so calling it invokes `_enterNonReentrant`\n // in the `ReentrancyGuard` contract, reproduced here:\n //\n // function _enterNonReentrant() private {\n // // If the Vault is actually being reentered, it will revert in the first line, at the `_require` that\n // // checks the reentrancy flag, with \"BAL#400\" (corresponding to Errors.REENTRANCY) in the revertData.\n // // The full revertData will be: `abi.encodeWithSignature(\"Error(string)\", \"BAL#400\")`.\n // _require(_status != _ENTERED, Errors.REENTRANCY);\n //\n // // If the Vault is not being reentered, the check above will pass: but it will *still* revert,\n // // because the next line attempts to modify storage during a staticcall. However, this type of\n // // failure results in empty revertData.\n // _status = _ENTERED;\n // }\n //\n // So based on this analysis, there are only two possible revertData values: empty, or abi.encoded BAL#400.\n //\n // It is of course much more bytecode and gas efficient to check for zero-length revertData than to compare it\n // to the encoded REENTRANCY revertData.\n //\n // While it should be impossible for the call to fail in any other way (especially since it reverts before\n // `manageUserBalance` even gets called), any other error would generate non-zero revertData, so checking for\n // empty data guards against this case too.\n\n (, bytes memory revertData) = address(vault).staticcall{ gas: 10_000 }(\n abi.encodeWithSelector(vault.manageUserBalance.selector, 0)\n );\n\n _require(revertData.length == 0, Errors.REENTRANCY);\n }\n}\n" + }, + "contracts/strategies/BaseCompoundStrategy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title Base Compound Abstract Strategy\n * @author Origin Protocol Inc\n */\n\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { ICERC20 } from \"./ICompound.sol\";\nimport { IComptroller } from \"../interfaces/IComptroller.sol\";\nimport { IERC20, InitializableAbstractStrategy } from \"../utils/InitializableAbstractStrategy.sol\";\n\nabstract contract BaseCompoundStrategy is InitializableAbstractStrategy {\n using SafeERC20 for IERC20;\n\n int256[50] private __reserved;\n\n /**\n * @dev Retuns bool indicating whether asset is supported by strategy\n * @param _asset Address of the asset\n */\n function supportsAsset(address _asset) public view override returns (bool) {\n return assetToPToken[_asset] != address(0);\n }\n\n /**\n * @dev Get the cToken wrapped in the ICERC20 interface for this asset.\n * Fails if the pToken doesn't exist in our mappings.\n * @param _asset Address of the asset\n * @return Corresponding cToken to this asset\n */\n function _getCTokenFor(address _asset) internal view returns (ICERC20) {\n address cToken = assetToPToken[_asset];\n require(cToken != address(0), \"cToken does not exist\");\n return ICERC20(cToken);\n }\n\n /**\n * @dev Converts an underlying amount into cToken amount\n * cTokenAmt = (underlying * 1e18) / exchangeRate\n * @param _cToken cToken for which to change\n * @param _underlying Amount of underlying to convert\n * @return amount Equivalent amount of cTokens\n */\n function _convertUnderlyingToCToken(ICERC20 _cToken, uint256 _underlying)\n internal\n view\n returns (uint256 amount)\n {\n // e.g. 1e18*1e18 / 205316390724364402565641705 = 50e8\n // e.g. 1e8*1e18 / 205316390724364402565641705 = 0.45 or 0\n amount = (_underlying * 1e18) / _cToken.exchangeRateStored();\n }\n}\n" + }, + "contracts/strategies/BaseConvexMetaStrategy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title Curve Convex Strategy\n * @notice Investment strategy for investing stablecoins via Curve 3Pool\n * @author Origin Protocol Inc\n */\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { IRewardStaking } from \"./IRewardStaking.sol\";\nimport { ICurvePool } from \"./ICurvePool.sol\";\nimport { ICurveMetaPool } from \"./ICurveMetaPool.sol\";\nimport { IERC20, BaseCurveStrategy, InitializableAbstractStrategy } from \"./BaseCurveStrategy.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { Helpers } from \"../utils/Helpers.sol\";\n\nabstract contract BaseConvexMetaStrategy is BaseCurveStrategy {\n using StableMath for uint256;\n using SafeERC20 for IERC20;\n\n event MaxWithdrawalSlippageUpdated(\n uint256 _prevMaxSlippagePercentage,\n uint256 _newMaxSlippagePercentage\n );\n\n // used to circumvent the stack too deep issue\n struct InitConfig {\n address cvxDepositorAddress; //Address of the Convex depositor(AKA booster) for this pool\n address metapoolAddress; //Address of the Curve MetaPool\n address metapoolMainToken; //Address of Main metapool token\n address cvxRewardStakerAddress; //Address of the CVX rewards staker\n address metapoolLPToken; //Address of metapool LP token\n uint256 cvxDepositorPTokenId; //Pid of the pool referred to by Depositor and staker\n }\n\n address internal cvxDepositorAddress;\n address internal cvxRewardStakerAddress;\n uint256 internal cvxDepositorPTokenId;\n ICurveMetaPool internal metapool;\n IERC20 internal metapoolMainToken;\n IERC20 internal metapoolLPToken;\n // Ordered list of metapool assets\n address[] internal metapoolAssets;\n // Max withdrawal slippage denominated in 1e18 (1e18 == 100%)\n uint256 public maxWithdrawalSlippage;\n uint128 internal crvCoinIndex;\n uint128 internal mainCoinIndex;\n\n int256[41] private ___reserved;\n\n /**\n * Initializer for setting up strategy internal state. This overrides the\n * InitializableAbstractStrategy initializer as Curve strategies don't fit\n * well within that abstraction.\n * @param _rewardTokenAddresses Address of CRV & CVX\n * @param _assets Addresses of supported assets. MUST be passed in the same\n * order as returned by coins on the pool contract, i.e.\n * DAI, USDC, USDT\n * @param _pTokens Platform Token corresponding addresses\n * @param initConfig Various addresses and info for initialization state\n */\n function initialize(\n address[] calldata _rewardTokenAddresses, // CRV + CVX\n address[] calldata _assets,\n address[] calldata _pTokens,\n InitConfig calldata initConfig\n ) external onlyGovernor initializer {\n require(_assets.length == 3, \"Must have exactly three assets\");\n // Should be set prior to abstract initialize call otherwise\n // abstractSetPToken calls will fail\n cvxDepositorAddress = initConfig.cvxDepositorAddress;\n pTokenAddress = _pTokens[0];\n metapool = ICurveMetaPool(initConfig.metapoolAddress);\n metapoolMainToken = IERC20(initConfig.metapoolMainToken);\n cvxRewardStakerAddress = initConfig.cvxRewardStakerAddress;\n metapoolLPToken = IERC20(initConfig.metapoolLPToken);\n cvxDepositorPTokenId = initConfig.cvxDepositorPTokenId;\n maxWithdrawalSlippage = 1e16;\n\n metapoolAssets = [metapool.coins(0), metapool.coins(1)];\n crvCoinIndex = _getMetapoolCoinIndex(pTokenAddress);\n mainCoinIndex = _getMetapoolCoinIndex(initConfig.metapoolMainToken);\n InitializableAbstractStrategy._initialize(\n _rewardTokenAddresses,\n _assets,\n _pTokens\n );\n _approveBase();\n }\n\n /**\n * @dev Get the total asset value held in the platform\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n public\n view\n virtual\n override\n returns (uint256 balance)\n {\n require(assetToPToken[_asset] != address(0), \"Unsupported asset\");\n balance = 0;\n\n // LP tokens in this contract. This should generally be nothing as we\n // should always stake the full balance in the Gauge, but include for\n // safety\n uint256 contractPTokens = IERC20(pTokenAddress).balanceOf(\n address(this)\n );\n ICurvePool curvePool = ICurvePool(platformAddress);\n if (contractPTokens > 0) {\n uint256 virtual_price = curvePool.get_virtual_price();\n uint256 value = contractPTokens.mulTruncate(virtual_price);\n balance += value;\n }\n\n /* We intentionally omit the metapoolLp tokens held by the metastrategyContract\n * since the contract should never (except in the middle of deposit/withdrawal\n * transaction) hold any amount of those tokens in normal operation. There\n * could be tokens sent to it by a 3rd party and we decide to actively ignore\n * those.\n */\n uint256 metapoolGaugePTokens = IRewardStaking(cvxRewardStakerAddress)\n .balanceOf(address(this));\n\n if (metapoolGaugePTokens > 0) {\n uint256 value = metapoolGaugePTokens.mulTruncate(\n metapool.get_virtual_price()\n );\n balance += value;\n }\n\n uint256 assetDecimals = Helpers.getDecimals(_asset);\n balance = balance.scaleBy(assetDecimals, 18) / THREEPOOL_ASSET_COUNT;\n }\n\n /**\n * @dev This function is completely analogous to _calcCurveTokenAmount[BaseCurveStrategy]\n * and just utilizes different Curve (meta)pool API\n */\n function _calcCurveMetaTokenAmount(uint128 _coinIndex, uint256 _amount)\n internal\n returns (uint256 requiredMetapoolLP)\n {\n uint256[2] memory _amounts = [uint256(0), uint256(0)];\n _amounts[uint256(_coinIndex)] = _amount;\n\n // LP required when removing required asset ignoring fees\n uint256 lpRequiredNoFees = metapool.calc_token_amount(_amounts, false);\n /* LP required if fees would apply to entirety of removed amount\n *\n * fee is 1e10 denominated number: https://curve.readthedocs.io/exchange-pools.html#StableSwap.fee\n */\n uint256 lpRequiredFullFees = lpRequiredNoFees.mulTruncateScale(\n 1e10 + metapool.fee(),\n 1e10\n );\n\n /* asset received when withdrawing full fee applicable LP accounting for\n * slippage and fees\n */\n uint256 assetReceivedForFullLPFees = metapool.calc_withdraw_one_coin(\n lpRequiredFullFees,\n int128(_coinIndex)\n );\n\n // exact amount of LP required\n requiredMetapoolLP =\n (lpRequiredFullFees * _amount) /\n assetReceivedForFullLPFees;\n }\n\n function _approveBase() internal override {\n IERC20 pToken = IERC20(pTokenAddress);\n // 3Pool for LP token (required for removing liquidity)\n pToken.safeApprove(platformAddress, 0);\n pToken.safeApprove(platformAddress, type(uint256).max);\n // Gauge for LP token\n metapoolLPToken.safeApprove(cvxDepositorAddress, 0);\n metapoolLPToken.safeApprove(cvxDepositorAddress, type(uint256).max);\n // Metapool for LP token\n pToken.safeApprove(address(metapool), 0);\n pToken.safeApprove(address(metapool), type(uint256).max);\n // Metapool for Metapool main token\n metapoolMainToken.safeApprove(address(metapool), 0);\n metapoolMainToken.safeApprove(address(metapool), type(uint256).max);\n }\n\n /**\n * @dev Get the index of the coin\n */\n function _getMetapoolCoinIndex(address _asset)\n internal\n view\n returns (uint128)\n {\n for (uint128 i = 0; i < 2; i++) {\n if (metapoolAssets[i] == _asset) return i;\n }\n revert(\"Invalid Metapool asset\");\n }\n\n /**\n * @dev Sets max withdrawal slippage that is considered when removing\n * liquidity from Metapools.\n * @param _maxWithdrawalSlippage Max withdrawal slippage denominated in\n * wad (number with 18 decimals): 1e18 == 100%, 1e16 == 1%\n *\n * IMPORTANT Minimum maxWithdrawalSlippage should actually be 0.1% (1e15)\n * for production usage. Contract allows as low value as 0% for confirming\n * correct behavior in test suite.\n */\n function setMaxWithdrawalSlippage(uint256 _maxWithdrawalSlippage)\n external\n onlyVaultOrGovernorOrStrategist\n {\n require(\n _maxWithdrawalSlippage <= 1e18,\n \"Max withdrawal slippage needs to be between 0% - 100%\"\n );\n emit MaxWithdrawalSlippageUpdated(\n maxWithdrawalSlippage,\n _maxWithdrawalSlippage\n );\n maxWithdrawalSlippage = _maxWithdrawalSlippage;\n }\n\n /**\n * @dev Collect accumulated CRV and CVX and send to Harvester.\n */\n function collectRewardTokens()\n external\n override\n onlyHarvester\n nonReentrant\n {\n // Collect CRV and CVX\n IRewardStaking(cvxRewardStakerAddress).getReward();\n _collectRewardTokens();\n }\n\n /**\n * @dev Returns the largest of two numbers int256 version\n */\n function _max(int256 a, int256 b) internal pure returns (int256) {\n return a >= b ? a : b;\n }\n}\n" + }, + "contracts/strategies/BaseCurveStrategy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title Curve 3Pool Strategy\n * @notice Investment strategy for investing stablecoins via Curve 3Pool\n * @author Origin Protocol Inc\n */\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { ICurvePool } from \"./ICurvePool.sol\";\nimport { IERC20, InitializableAbstractStrategy } from \"../utils/InitializableAbstractStrategy.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { Helpers } from \"../utils/Helpers.sol\";\n\nabstract contract BaseCurveStrategy is InitializableAbstractStrategy {\n using StableMath for uint256;\n using SafeERC20 for IERC20;\n\n uint256 internal constant MAX_SLIPPAGE = 1e16; // 1%, same as the Curve UI\n // number of assets in Curve 3Pool (USDC, DAI, USDT)\n uint256 internal constant THREEPOOL_ASSET_COUNT = 3;\n address internal pTokenAddress;\n\n int256[49] private __reserved;\n\n /**\n * @dev Deposit asset into the Curve 3Pool\n * @param _asset Address of asset to deposit\n * @param _amount Amount of asset to deposit\n */\n function deposit(address _asset, uint256 _amount)\n external\n override\n onlyVault\n nonReentrant\n {\n require(_amount > 0, \"Must deposit something\");\n emit Deposit(_asset, pTokenAddress, _amount);\n\n // 3Pool requires passing deposit amounts for all 3 assets, set to 0 for\n // all\n uint256[3] memory _amounts;\n uint256 poolCoinIndex = _getCoinIndex(_asset);\n // Set the amount on the asset we want to deposit\n _amounts[poolCoinIndex] = _amount;\n ICurvePool curvePool = ICurvePool(platformAddress);\n uint256 assetDecimals = Helpers.getDecimals(_asset);\n uint256 depositValue = _amount.scaleBy(18, assetDecimals).divPrecisely(\n curvePool.get_virtual_price()\n );\n uint256 minMintAmount = depositValue.mulTruncate(\n uint256(1e18) - MAX_SLIPPAGE\n );\n // Do the deposit to 3pool\n curvePool.add_liquidity(_amounts, minMintAmount);\n _lpDepositAll();\n }\n\n function _lpDepositAll() internal virtual;\n\n /**\n * @dev Deposit the entire balance of any supported asset into the Curve 3pool\n */\n function depositAll() external override onlyVault nonReentrant {\n uint256[3] memory _amounts = [uint256(0), uint256(0), uint256(0)];\n uint256 depositValue = 0;\n ICurvePool curvePool = ICurvePool(platformAddress);\n uint256 curveVirtualPrice = curvePool.get_virtual_price();\n\n for (uint256 i = 0; i < assetsMapped.length; i++) {\n address assetAddress = assetsMapped[i];\n uint256 balance = IERC20(assetAddress).balanceOf(address(this));\n if (balance > 0) {\n uint256 poolCoinIndex = _getCoinIndex(assetAddress);\n // Set the amount on the asset we want to deposit\n _amounts[poolCoinIndex] = balance;\n uint256 assetDecimals = Helpers.getDecimals(assetAddress);\n // Get value of deposit in Curve LP token to later determine\n // the minMintAmount argument for add_liquidity\n depositValue =\n depositValue +\n balance.scaleBy(18, assetDecimals).divPrecisely(\n curveVirtualPrice\n );\n emit Deposit(assetAddress, pTokenAddress, balance);\n }\n }\n\n uint256 minMintAmount = depositValue.mulTruncate(\n uint256(1e18) - MAX_SLIPPAGE\n );\n // Do the deposit to 3pool\n curvePool.add_liquidity(_amounts, minMintAmount);\n\n /* In case of Curve Strategy all assets are mapped to the same pToken (3CrvLP). Let\n * descendants further handle the pToken. By either deploying it to the metapool and\n * resulting tokens in Gauge. Or deploying pTokens directly to the Gauge.\n */\n _lpDepositAll();\n }\n\n function _lpWithdraw(uint256 numCrvTokens) internal virtual;\n\n function _lpWithdrawAll() internal virtual;\n\n /**\n * @dev Withdraw asset from Curve 3Pool\n * @param _recipient Address to receive withdrawn asset\n * @param _asset Address of asset to withdraw\n * @param _amount Amount of asset to withdraw\n */\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external override onlyVault nonReentrant {\n require(_amount > 0, \"Invalid amount\");\n\n emit Withdrawal(_asset, pTokenAddress, _amount);\n\n uint256 contractCrv3Tokens = IERC20(pTokenAddress).balanceOf(\n address(this)\n );\n\n uint256 coinIndex = _getCoinIndex(_asset);\n ICurvePool curvePool = ICurvePool(platformAddress);\n\n uint256 requiredCrv3Tokens = _calcCurveTokenAmount(coinIndex, _amount);\n\n // We have enough LP tokens, make sure they are all on this contract\n if (contractCrv3Tokens < requiredCrv3Tokens) {\n _lpWithdraw(requiredCrv3Tokens - contractCrv3Tokens);\n }\n\n uint256[3] memory _amounts = [uint256(0), uint256(0), uint256(0)];\n _amounts[coinIndex] = _amount;\n\n curvePool.remove_liquidity_imbalance(_amounts, requiredCrv3Tokens);\n IERC20(_asset).safeTransfer(_recipient, _amount);\n }\n\n /**\n * @dev Calculate amount of LP required when withdrawing specific amount of one\n * of the underlying assets accounting for fees and slippage.\n *\n * Curve pools unfortunately do not contain a calculation function for\n * amount of LP required when withdrawing a specific amount of one of the\n * underlying tokens and also accounting for fees (Curve's calc_token_amount\n * does account for slippage but not fees).\n *\n * Steps taken to calculate the metric:\n * - get amount of LP required if fees wouldn't apply\n * - increase the LP amount as if fees would apply to the entirety of the underlying\n * asset withdrawal. (when withdrawing only one coin fees apply only to amounts\n * of other assets pool would return in case of balanced removal - since those need\n * to be swapped for the single underlying asset being withdrawn)\n * - get amount of underlying asset withdrawn (this Curve function does consider slippage\n * and fees) when using the increased LP amount. As LP amount is slightly over-increased\n * so is amount of underlying assets returned.\n * - since we know exactly how much asset we require take the rate of LP required for asset\n * withdrawn to get the exact amount of LP.\n */\n function _calcCurveTokenAmount(uint256 _coinIndex, uint256 _amount)\n internal\n returns (uint256 required3Crv)\n {\n ICurvePool curvePool = ICurvePool(platformAddress);\n\n uint256[3] memory _amounts = [uint256(0), uint256(0), uint256(0)];\n _amounts[_coinIndex] = _amount;\n\n // LP required when removing required asset ignoring fees\n uint256 lpRequiredNoFees = curvePool.calc_token_amount(_amounts, false);\n /* LP required if fees would apply to entirety of removed amount\n *\n * fee is 1e10 denominated number: https://curve.readthedocs.io/exchange-pools.html#StableSwap.fee\n */\n uint256 lpRequiredFullFees = lpRequiredNoFees.mulTruncateScale(\n 1e10 + curvePool.fee(),\n 1e10\n );\n\n /* asset received when withdrawing full fee applicable LP accounting for\n * slippage and fees\n */\n uint256 assetReceivedForFullLPFees = curvePool.calc_withdraw_one_coin(\n lpRequiredFullFees,\n int128(uint128(_coinIndex))\n );\n\n // exact amount of LP required\n required3Crv =\n (lpRequiredFullFees * _amount) /\n assetReceivedForFullLPFees;\n }\n\n /**\n * @dev Remove all assets from platform and send them to Vault contract.\n */\n function withdrawAll() external override onlyVaultOrGovernor nonReentrant {\n _lpWithdrawAll();\n // Withdraws are proportional to assets held by 3Pool\n uint256[3] memory minWithdrawAmounts = [\n uint256(0),\n uint256(0),\n uint256(0)\n ];\n\n // Remove liquidity\n ICurvePool threePool = ICurvePool(platformAddress);\n threePool.remove_liquidity(\n IERC20(pTokenAddress).balanceOf(address(this)),\n minWithdrawAmounts\n );\n // Transfer assets out of Vault\n // Note that Curve will provide all 3 of the assets in 3pool even if\n // we have not set PToken addresses for all of them in this strategy\n for (uint256 i = 0; i < assetsMapped.length; i++) {\n IERC20 asset = IERC20(threePool.coins(i));\n asset.safeTransfer(vaultAddress, asset.balanceOf(address(this)));\n }\n }\n\n /**\n * @dev Get the total asset value held in the platform\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n public\n view\n virtual\n override\n returns (uint256 balance)\n {\n require(assetToPToken[_asset] != address(0), \"Unsupported asset\");\n // LP tokens in this contract. This should generally be nothing as we\n // should always stake the full balance in the Gauge, but include for\n // safety\n uint256 totalPTokens = IERC20(pTokenAddress).balanceOf(address(this));\n ICurvePool curvePool = ICurvePool(platformAddress);\n if (totalPTokens > 0) {\n uint256 virtual_price = curvePool.get_virtual_price();\n uint256 value = (totalPTokens * virtual_price) / 1e18;\n uint256 assetDecimals = Helpers.getDecimals(_asset);\n balance = value.scaleBy(assetDecimals, 18) / THREEPOOL_ASSET_COUNT;\n }\n }\n\n /**\n * @dev Retuns bool indicating whether asset is supported by strategy\n * @param _asset Address of the asset\n */\n function supportsAsset(address _asset) public view override returns (bool) {\n return assetToPToken[_asset] != address(0);\n }\n\n /**\n * @dev Approve the spending of all assets by their corresponding pool tokens,\n * if for some reason is it necessary.\n */\n function safeApproveAllTokens()\n external\n override\n onlyGovernor\n nonReentrant\n {\n _approveBase();\n // This strategy is a special case since it only supports one asset\n for (uint256 i = 0; i < assetsMapped.length; i++) {\n _approveAsset(assetsMapped[i]);\n }\n }\n\n /**\n * @dev Call the necessary approvals for the Curve pool and gauge\n * @param _asset Address of the asset\n */\n function _abstractSetPToken(address _asset, address) internal override {\n _approveAsset(_asset);\n }\n\n function _approveAsset(address _asset) internal {\n IERC20 asset = IERC20(_asset);\n // 3Pool for asset (required for adding liquidity)\n asset.safeApprove(platformAddress, 0);\n asset.safeApprove(platformAddress, type(uint256).max);\n }\n\n function _approveBase() internal virtual;\n\n /**\n * @dev Get the index of the coin\n */\n function _getCoinIndex(address _asset) internal view returns (uint256) {\n for (uint256 i = 0; i < 3; i++) {\n if (assetsMapped[i] == _asset) return i;\n }\n revert(\"Invalid 3pool asset\");\n }\n}\n" + }, + "contracts/strategies/CompoundStrategy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title Compound Strategy\n * @notice Investment strategy for Compound like lending platforms. eg Compound and Flux\n * @author Origin Protocol Inc\n */\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { ICERC20 } from \"./ICompound.sol\";\nimport { BaseCompoundStrategy, InitializableAbstractStrategy } from \"./BaseCompoundStrategy.sol\";\nimport { IComptroller } from \"../interfaces/IComptroller.sol\";\nimport { IERC20 } from \"../utils/InitializableAbstractStrategy.sol\";\n\ncontract CompoundStrategy is BaseCompoundStrategy {\n using SafeERC20 for IERC20;\n event SkippedWithdrawal(address asset, uint256 amount);\n\n constructor(BaseStrategyConfig memory _stratConfig)\n InitializableAbstractStrategy(_stratConfig)\n {}\n\n /**\n * @notice initialize function, to set up initial internal state\n * @param _rewardTokenAddresses Address of reward token for platform\n * @param _assets Addresses of initial supported assets\n * @param _pTokens Platform Token corresponding addresses\n */\n function initialize(\n address[] memory _rewardTokenAddresses,\n address[] memory _assets,\n address[] memory _pTokens\n ) external onlyGovernor initializer {\n InitializableAbstractStrategy._initialize(\n _rewardTokenAddresses,\n _assets,\n _pTokens\n );\n }\n\n /**\n * @notice Collect accumulated COMP and send to Harvester.\n */\n function collectRewardTokens()\n external\n virtual\n override\n onlyHarvester\n nonReentrant\n {\n // Claim COMP from Comptroller\n ICERC20 cToken = _getCTokenFor(assetsMapped[0]);\n IComptroller comptroller = IComptroller(cToken.comptroller());\n // Only collect from active cTokens, saves gas\n address[] memory ctokensToCollect = new address[](assetsMapped.length);\n uint256 assetCount = assetsMapped.length;\n for (uint256 i = 0; i < assetCount; ++i) {\n ctokensToCollect[i] = address(_getCTokenFor(assetsMapped[i]));\n }\n // Claim only for this strategy\n address[] memory claimers = new address[](1);\n claimers[0] = address(this);\n // Claim COMP from Comptroller. Only collect for supply, saves gas\n comptroller.claimComp(claimers, ctokensToCollect, false, true);\n // Transfer COMP to Harvester\n IERC20 rewardToken = IERC20(rewardTokenAddresses[0]);\n uint256 balance = rewardToken.balanceOf(address(this));\n emit RewardTokenCollected(\n harvesterAddress,\n rewardTokenAddresses[0],\n balance\n );\n rewardToken.safeTransfer(harvesterAddress, balance);\n }\n\n /**\n * @notice Deposit asset into the underlying platform\n * @param _asset Address of asset to deposit\n * @param _amount Amount of assets to deposit\n */\n function deposit(address _asset, uint256 _amount)\n external\n override\n onlyVault\n nonReentrant\n {\n _deposit(_asset, _amount);\n }\n\n /**\n * @dev Deposit an asset into the underlying platform\n * @param _asset Address of the asset to deposit\n * @param _amount Amount of assets to deposit\n */\n function _deposit(address _asset, uint256 _amount) internal {\n require(_amount > 0, \"Must deposit something\");\n ICERC20 cToken = _getCTokenFor(_asset);\n emit Deposit(_asset, address(cToken), _amount);\n require(cToken.mint(_amount) == 0, \"cToken mint failed\");\n }\n\n /**\n * @notice Deposit the entire balance of any supported asset in the strategy into the underlying platform\n */\n function depositAll() external override onlyVault nonReentrant {\n uint256 assetCount = assetsMapped.length;\n for (uint256 i = 0; i < assetCount; ++i) {\n IERC20 asset = IERC20(assetsMapped[i]);\n uint256 assetBalance = asset.balanceOf(address(this));\n if (assetBalance > 0) {\n _deposit(address(asset), assetBalance);\n }\n }\n }\n\n /**\n * @notice Withdraw an asset from the underlying platform\n * @param _recipient Address to receive withdrawn assets\n * @param _asset Address of the asset to withdraw\n * @param _amount Amount of assets to withdraw\n */\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external override onlyVault nonReentrant {\n require(_amount > 0, \"Must withdraw something\");\n require(_recipient != address(0), \"Must specify recipient\");\n\n ICERC20 cToken = _getCTokenFor(_asset);\n // If redeeming 0 cTokens, just skip, else COMP will revert\n uint256 cTokensToRedeem = _convertUnderlyingToCToken(cToken, _amount);\n if (cTokensToRedeem == 0) {\n emit SkippedWithdrawal(_asset, _amount);\n return;\n }\n\n emit Withdrawal(_asset, address(cToken), _amount);\n require(cToken.redeemUnderlying(_amount) == 0, \"Redeem failed\");\n IERC20(_asset).safeTransfer(_recipient, _amount);\n }\n\n /**\n * @dev Internal method to respond to the addition of new asset / cTokens\n * We need to approve the cToken and give it permission to spend the asset\n * @param _asset Address of the asset to approve. eg DAI\n * @param _pToken The pToken for the approval. eg cDAI or fDAI\n */\n function _abstractSetPToken(address _asset, address _pToken)\n internal\n override\n {\n // Safe approval\n IERC20(_asset).safeApprove(_pToken, 0);\n IERC20(_asset).safeApprove(_pToken, type(uint256).max);\n }\n\n /**\n * @notice Remove all supported assets from the underlying platform and send them to Vault contract.\n */\n function withdrawAll() external override onlyVaultOrGovernor nonReentrant {\n uint256 assetCount = assetsMapped.length;\n for (uint256 i = 0; i < assetCount; ++i) {\n IERC20 asset = IERC20(assetsMapped[i]);\n // Redeem entire balance of cToken\n ICERC20 cToken = _getCTokenFor(address(asset));\n uint256 cTokenBalance = cToken.balanceOf(address(this));\n if (cTokenBalance > 0) {\n require(cToken.redeem(cTokenBalance) == 0, \"Redeem failed\");\n uint256 assetBalance = asset.balanceOf(address(this));\n // Transfer entire balance to Vault\n asset.safeTransfer(vaultAddress, assetBalance);\n\n emit Withdrawal(address(asset), address(cToken), assetBalance);\n }\n }\n }\n\n /**\n * @notice Get the total asset value held in the underlying platform\n * This includes any interest that was generated since depositing.\n * The exchange rate between the cToken and asset gradually increases,\n * causing the cToken to be worth more corresponding asset.\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n external\n view\n override\n returns (uint256 balance)\n {\n // Balance is always with token cToken decimals\n ICERC20 cToken = _getCTokenFor(_asset);\n balance = _checkBalance(cToken);\n }\n\n /**\n * @dev Get the total asset value held in the platform\n * underlying = (cTokenAmt * exchangeRate) / 1e18\n * @param _cToken cToken for which to check balance\n * @return balance Total value of the asset in the platform\n */\n function _checkBalance(ICERC20 _cToken)\n internal\n view\n returns (uint256 balance)\n {\n // e.g. 50e8*205316390724364402565641705 / 1e18 = 1.0265..e18\n balance =\n (_cToken.balanceOf(address(this)) * _cToken.exchangeRateStored()) /\n 1e18;\n }\n\n /**\n * @notice Approve the spending of all assets by their corresponding cToken,\n * if for some reason is it necessary.\n */\n function safeApproveAllTokens() external override {\n uint256 assetCount = assetsMapped.length;\n for (uint256 i = 0; i < assetCount; ++i) {\n IERC20 asset = IERC20(assetsMapped[i]);\n address cToken = assetToPToken[address(asset)];\n // Safe approval\n asset.safeApprove(cToken, 0);\n asset.safeApprove(cToken, type(uint256).max);\n }\n }\n}\n" + }, + "contracts/strategies/ConvexEthMetaStrategy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title Convex Automated Market Maker (AMO) Strategy\n * @notice AMO strategy for the Curve OETH/ETH pool\n * @author Origin Protocol Inc\n */\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/utils/math/Math.sol\";\n\nimport { ICurveETHPoolV1 } from \"./ICurveETHPoolV1.sol\";\nimport { IERC20, InitializableAbstractStrategy } from \"../utils/InitializableAbstractStrategy.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { IWETH9 } from \"../interfaces/IWETH9.sol\";\nimport { IConvexDeposits } from \"./IConvexDeposits.sol\";\nimport { IRewardStaking } from \"./IRewardStaking.sol\";\n\ncontract ConvexEthMetaStrategy is InitializableAbstractStrategy {\n using StableMath for uint256;\n using SafeERC20 for IERC20;\n\n uint256 public constant MAX_SLIPPAGE = 1e16; // 1%, same as the Curve UI\n address public constant ETH_ADDRESS =\n 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n // The following slots have been deprecated with immutable variables\n // slither-disable-next-line constable-states\n address private _deprecated_cvxDepositorAddress;\n // slither-disable-next-line constable-states\n address private _deprecated_cvxRewardStaker;\n // slither-disable-next-line constable-states\n uint256 private _deprecated_cvxDepositorPTokenId;\n // slither-disable-next-line constable-states\n address private _deprecated_curvePool;\n // slither-disable-next-line constable-states\n address private _deprecated_lpToken;\n // slither-disable-next-line constable-states\n address private _deprecated_oeth;\n // slither-disable-next-line constable-states\n address private _deprecated_weth;\n\n // Ordered list of pool assets\n // slither-disable-next-line constable-states\n uint128 private _deprecated_oethCoinIndex;\n // slither-disable-next-line constable-states\n uint128 private _deprecated_ethCoinIndex;\n\n // New immutable variables that must be set in the constructor\n address public immutable cvxDepositorAddress;\n IRewardStaking public immutable cvxRewardStaker;\n uint256 public immutable cvxDepositorPTokenId;\n ICurveETHPoolV1 public immutable curvePool;\n IERC20 public immutable lpToken;\n IERC20 public immutable oeth;\n IWETH9 public immutable weth;\n\n // Ordered list of pool assets\n uint128 public constant oethCoinIndex = 1;\n uint128 public constant ethCoinIndex = 0;\n\n /**\n * @dev Verifies that the caller is the Strategist.\n */\n modifier onlyStrategist() {\n require(\n msg.sender == IVault(vaultAddress).strategistAddr(),\n \"Caller is not the Strategist\"\n );\n _;\n }\n\n /**\n * @dev Checks the Curve pool's balances have improved and the balances\n * have not tipped to the other side.\n * This modifier only works on functions that do a single sided add or remove.\n * The standard deposit function adds to both sides of the pool in a way that\n * the pool's balance is not worsened.\n * Withdrawals are proportional so doesn't change the pools asset balance.\n */\n modifier improvePoolBalance() {\n // Get the asset and OToken balances in the Curve pool\n uint256[2] memory balancesBefore = curvePool.get_balances();\n // diff = ETH balance - OETH balance\n int256 diffBefore = int256(balancesBefore[ethCoinIndex]) -\n int256(balancesBefore[oethCoinIndex]);\n\n _;\n\n // Get the asset and OToken balances in the Curve pool\n uint256[2] memory balancesAfter = curvePool.get_balances();\n // diff = ETH balance - OETH balance\n int256 diffAfter = int256(balancesAfter[ethCoinIndex]) -\n int256(balancesAfter[oethCoinIndex]);\n\n if (diffBefore <= 0) {\n // If the pool was originally imbalanced in favor of OETH, then\n // we want to check that the pool is now more balanced\n require(diffAfter <= 0, \"OTokens overshot peg\");\n require(diffBefore < diffAfter, \"OTokens balance worse\");\n }\n if (diffBefore >= 0) {\n // If the pool was originally imbalanced in favor of ETH, then\n // we want to check that the pool is now more balanced\n require(diffAfter >= 0, \"Assets overshot peg\");\n require(diffAfter < diffBefore, \"Assets balance worse\");\n }\n }\n\n // Used to circumvent the stack too deep issue\n struct ConvexEthMetaConfig {\n address cvxDepositorAddress; //Address of the Convex depositor(AKA booster) for this pool\n address cvxRewardStakerAddress; //Address of the CVX rewards staker\n uint256 cvxDepositorPTokenId; //Pid of the pool referred to by Depositor and staker\n address oethAddress; //Address of OETH token\n address wethAddress; //Address of WETH\n }\n\n constructor(\n BaseStrategyConfig memory _baseConfig,\n ConvexEthMetaConfig memory _convexConfig\n ) InitializableAbstractStrategy(_baseConfig) {\n lpToken = IERC20(_baseConfig.platformAddress);\n curvePool = ICurveETHPoolV1(_baseConfig.platformAddress);\n\n cvxDepositorAddress = _convexConfig.cvxDepositorAddress;\n cvxRewardStaker = IRewardStaking(_convexConfig.cvxRewardStakerAddress);\n cvxDepositorPTokenId = _convexConfig.cvxDepositorPTokenId;\n oeth = IERC20(_convexConfig.oethAddress);\n weth = IWETH9(_convexConfig.wethAddress);\n }\n\n /**\n * Initializer for setting up strategy internal state. This overrides the\n * InitializableAbstractStrategy initializer as Curve strategies don't fit\n * well within that abstraction.\n * @param _rewardTokenAddresses Address of CRV & CVX\n * @param _assets Addresses of supported assets. eg WETH\n */\n function initialize(\n address[] calldata _rewardTokenAddresses, // CRV + CVX\n address[] calldata _assets // WETH\n ) external onlyGovernor initializer {\n require(_assets.length == 1, \"Must have exactly one asset\");\n require(_assets[0] == address(weth), \"Asset not WETH\");\n\n address[] memory pTokens = new address[](1);\n pTokens[0] = address(curvePool);\n\n InitializableAbstractStrategy._initialize(\n _rewardTokenAddresses,\n _assets,\n pTokens\n );\n\n _approveBase();\n }\n\n /***************************************\n Deposit\n ****************************************/\n\n /**\n * @notice Deposit WETH into the Curve pool\n * @param _weth Address of Wrapped ETH (WETH) contract.\n * @param _amount Amount of WETH to deposit.\n */\n function deposit(address _weth, uint256 _amount)\n external\n override\n onlyVault\n nonReentrant\n {\n _deposit(_weth, _amount);\n }\n\n function _deposit(address _weth, uint256 _wethAmount) internal {\n require(_wethAmount > 0, \"Must deposit something\");\n require(_weth == address(weth), \"Can only deposit WETH\");\n weth.withdraw(_wethAmount);\n\n emit Deposit(_weth, address(lpToken), _wethAmount);\n\n // Get the asset and OToken balances in the Curve pool\n uint256[2] memory balances = curvePool.get_balances();\n // safe to cast since min value is at least 0\n uint256 oethToAdd = uint256(\n _max(\n 0,\n int256(balances[ethCoinIndex]) +\n int256(_wethAmount) -\n int256(balances[oethCoinIndex])\n )\n );\n\n /* Add so much OETH so that the pool ends up being balanced. And at minimum\n * add as much OETH as WETH and at maximum twice as much OETH.\n */\n oethToAdd = Math.max(oethToAdd, _wethAmount);\n oethToAdd = Math.min(oethToAdd, _wethAmount * 2);\n\n /* Mint OETH with a strategy that attempts to contribute to stability of OETH/WETH pool. Try\n * to mint so much OETH that after deployment of liquidity pool ends up being balanced.\n *\n * To manage unpredictability minimal OETH minted will always be at least equal or greater\n * to WETH amount deployed. And never larger than twice the WETH amount deployed even if\n * it would have a further beneficial effect on pool stability.\n */\n IVault(vaultAddress).mintForStrategy(oethToAdd);\n\n emit Deposit(address(oeth), address(lpToken), oethToAdd);\n\n uint256[2] memory _amounts;\n _amounts[ethCoinIndex] = _wethAmount;\n _amounts[oethCoinIndex] = oethToAdd;\n\n uint256 valueInLpTokens = (_wethAmount + oethToAdd).divPrecisely(\n curvePool.get_virtual_price()\n );\n uint256 minMintAmount = valueInLpTokens.mulTruncate(\n uint256(1e18) - MAX_SLIPPAGE\n );\n\n // Do the deposit to the Curve pool\n // slither-disable-next-line arbitrary-send\n uint256 lpDeposited = curvePool.add_liquidity{ value: _wethAmount }(\n _amounts,\n minMintAmount\n );\n\n // Deposit the Curve pool's LP tokens into the Convex rewards pool\n require(\n IConvexDeposits(cvxDepositorAddress).deposit(\n cvxDepositorPTokenId,\n lpDeposited,\n true // Deposit with staking\n ),\n \"Depositing LP to Convex not successful\"\n );\n }\n\n /**\n * @notice Deposit the strategy's entire balance of WETH into the Curve pool\n */\n function depositAll() external override onlyVault nonReentrant {\n uint256 balance = weth.balanceOf(address(this));\n if (balance > 0) {\n _deposit(address(weth), balance);\n }\n }\n\n /***************************************\n Withdraw\n ****************************************/\n\n /**\n * @notice Withdraw ETH and OETH from the Curve pool, burn the OETH,\n * convert the ETH to WETH and transfer to the recipient.\n * @param _recipient Address to receive withdrawn asset which is normally the Vault.\n * @param _weth Address of the Wrapped ETH (WETH) contract.\n * @param _amount Amount of WETH to withdraw.\n */\n function withdraw(\n address _recipient,\n address _weth,\n uint256 _amount\n ) external override onlyVault nonReentrant {\n require(_amount > 0, \"Invalid amount\");\n require(_weth == address(weth), \"Can only withdraw WETH\");\n\n emit Withdrawal(_weth, address(lpToken), _amount);\n\n uint256 requiredLpTokens = calcTokenToBurn(_amount);\n\n _lpWithdraw(requiredLpTokens);\n\n /* math in requiredLpTokens should correctly calculate the amount of LP to remove\n * in that the strategy receives enough WETH on balanced removal\n */\n uint256[2] memory _minWithdrawalAmounts = [uint256(0), uint256(0)];\n _minWithdrawalAmounts[ethCoinIndex] = _amount;\n // slither-disable-next-line unused-return\n curvePool.remove_liquidity(requiredLpTokens, _minWithdrawalAmounts);\n\n // Burn all the removed OETH and any that was left in the strategy\n uint256 oethToBurn = oeth.balanceOf(address(this));\n IVault(vaultAddress).burnForStrategy(oethToBurn);\n\n emit Withdrawal(address(oeth), address(lpToken), oethToBurn);\n\n // Transfer WETH to the recipient\n weth.deposit{ value: _amount }();\n require(\n weth.transfer(_recipient, _amount),\n \"Transfer of WETH not successful\"\n );\n }\n\n function calcTokenToBurn(uint256 _wethAmount)\n internal\n view\n returns (uint256 lpToBurn)\n {\n /* The rate between coins in the pool determines the rate at which pool returns\n * tokens when doing balanced removal (remove_liquidity call). And by knowing how much WETH\n * we want we can determine how much of OETH we receive by removing liquidity.\n *\n * Because we are doing balanced removal we should be making profit when removing liquidity in a\n * pool tilted to either side.\n *\n * Important: A downside is that the Strategist / Governor needs to be\n * cognisant of not removing too much liquidity. And while the proposal to remove liquidity\n * is being voted on the pool tilt might change so much that the proposal that has been valid while\n * created is no longer valid.\n */\n\n uint256 poolWETHBalance = curvePool.balances(ethCoinIndex);\n /* K is multiplied by 1e36 which is used for higher precision calculation of required\n * pool LP tokens. Without it the end value can have rounding errors up to precision of\n * 10 digits. This way we move the decimal point by 36 places when doing the calculation\n * and again by 36 places when we are done with it.\n */\n uint256 k = (1e36 * lpToken.totalSupply()) / poolWETHBalance;\n // prettier-ignore\n // slither-disable-next-line divide-before-multiply\n uint256 diff = (_wethAmount + 1) * k;\n lpToBurn = diff / 1e36;\n }\n\n /**\n * @notice Remove all ETH and OETH from the Curve pool, burn the OETH,\n * convert the ETH to WETH and transfer to the Vault contract.\n */\n function withdrawAll() external override onlyVaultOrGovernor nonReentrant {\n uint256 gaugeTokens = cvxRewardStaker.balanceOf(address(this));\n _lpWithdraw(gaugeTokens);\n\n // Withdraws are proportional to assets held by 3Pool\n uint256[2] memory minWithdrawAmounts = [uint256(0), uint256(0)];\n\n // Remove liquidity\n // slither-disable-next-line unused-return\n curvePool.remove_liquidity(\n lpToken.balanceOf(address(this)),\n minWithdrawAmounts\n );\n\n // Burn all OETH\n uint256 oethToBurn = oeth.balanceOf(address(this));\n IVault(vaultAddress).burnForStrategy(oethToBurn);\n\n // Get the strategy contract's ether balance.\n // This includes all that was removed from the Curve pool and\n // any ether that was sitting in the strategy contract before the removal.\n uint256 ethBalance = address(this).balance;\n // Convert all the strategy contract's ether to WETH and transfer to the vault.\n weth.deposit{ value: ethBalance }();\n require(\n weth.transfer(vaultAddress, ethBalance),\n \"Transfer of WETH not successful\"\n );\n\n emit Withdrawal(address(weth), address(lpToken), ethBalance);\n emit Withdrawal(address(oeth), address(lpToken), oethToBurn);\n }\n\n /***************************************\n Curve pool Rebalancing\n ****************************************/\n\n /**\n * @notice Mint OTokens and one-sided add to the Curve pool.\n * This is used when the Curve pool does not have enough OTokens and too many ETH.\n * The OToken/Asset, eg OETH/ETH, price with increase.\n * The amount of assets in the vault is unchanged.\n * The total supply of OTokens is increased.\n * The asset value of the strategy and vault is increased.\n * @param _oTokens The amount of OTokens to be minted and added to the pool.\n */\n function mintAndAddOTokens(uint256 _oTokens)\n external\n onlyStrategist\n nonReentrant\n improvePoolBalance\n {\n IVault(vaultAddress).mintForStrategy(_oTokens);\n\n uint256[2] memory amounts = [uint256(0), uint256(0)];\n amounts[oethCoinIndex] = _oTokens;\n\n // Convert OETH to Curve pool LP tokens\n uint256 valueInLpTokens = (_oTokens).divPrecisely(\n curvePool.get_virtual_price()\n );\n // Apply slippage to LP tokens\n uint256 minMintAmount = valueInLpTokens.mulTruncate(\n uint256(1e18) - MAX_SLIPPAGE\n );\n\n // Add the minted OTokens to the Curve pool\n uint256 lpDeposited = curvePool.add_liquidity(amounts, minMintAmount);\n\n // Deposit the Curve pool LP tokens to the Convex rewards pool\n require(\n IConvexDeposits(cvxDepositorAddress).deposit(\n cvxDepositorPTokenId,\n lpDeposited,\n true // Deposit with staking\n ),\n \"Failed to Deposit LP to Convex\"\n );\n\n emit Deposit(address(oeth), address(lpToken), _oTokens);\n }\n\n /**\n * @notice One-sided remove of OTokens from the Curve pool which are then burned.\n * This is used when the Curve pool has too many OTokens and not enough ETH.\n * The amount of assets in the vault is unchanged.\n * The total supply of OTokens is reduced.\n * The asset value of the strategy and vault is reduced.\n * @param _lpTokens The amount of Curve pool LP tokens to be burned for OTokens.\n */\n function removeAndBurnOTokens(uint256 _lpTokens)\n external\n onlyStrategist\n nonReentrant\n improvePoolBalance\n {\n // Withdraw Curve pool LP tokens from Convex and remove OTokens from the Curve pool\n uint256 oethToBurn = _withdrawAndRemoveFromPool(\n _lpTokens,\n oethCoinIndex\n );\n\n // The vault burns the OTokens from this strategy\n IVault(vaultAddress).burnForStrategy(oethToBurn);\n\n emit Withdrawal(address(oeth), address(lpToken), oethToBurn);\n }\n\n /**\n * @notice One-sided remove of ETH from the Curve pool, convert to WETH\n * and transfer to the vault.\n * This is used when the Curve pool does not have enough OTokens and too many ETH.\n * The OToken/Asset, eg OETH/ETH, price with decrease.\n * The amount of assets in the vault increases.\n * The total supply of OTokens does not change.\n * The asset value of the strategy reduces.\n * The asset value of the vault should be close to the same.\n * @param _lpTokens The amount of Curve pool LP tokens to be burned for ETH.\n * @dev Curve pool LP tokens is used rather than WETH assets as Curve does not\n * have a way to accurately calculate the amount of LP tokens for a required\n * amount of ETH. Curve's `calc_token_amount` functioun does not include fees.\n * A 3rd party libary can be used that takes into account the fees, but this\n * is a gas intensive process. It's easier for the trusted strategist to\n * caclulate the amount of Curve pool LP tokens required off-chain.\n */\n function removeOnlyAssets(uint256 _lpTokens)\n external\n onlyStrategist\n nonReentrant\n improvePoolBalance\n {\n // Withdraw Curve pool LP tokens from Convex and remove ETH from the Curve pool\n uint256 ethAmount = _withdrawAndRemoveFromPool(_lpTokens, ethCoinIndex);\n\n // Convert ETH to WETH and transfer to the vault\n weth.deposit{ value: ethAmount }();\n require(\n weth.transfer(vaultAddress, ethAmount),\n \"Transfer of WETH not successful\"\n );\n\n emit Withdrawal(address(weth), address(lpToken), ethAmount);\n }\n\n /**\n * @dev Remove Curve pool LP tokens from the Convex pool and\n * do a one-sided remove of ETH or OETH from the Curve pool.\n * @param _lpTokens The amount of Curve pool LP tokens to be removed from the Convex pool.\n * @param coinIndex The index of the coin to be removed from the Curve pool. 0 = ETH, 1 = OETH.\n * @return coinsRemoved The amount of ETH or OETH removed from the Curve pool.\n */\n function _withdrawAndRemoveFromPool(uint256 _lpTokens, uint128 coinIndex)\n internal\n returns (uint256 coinsRemoved)\n {\n // Withdraw Curve pool LP tokens from Convex pool\n _lpWithdraw(_lpTokens);\n\n // Convert Curve pool LP tokens to ETH value\n uint256 valueInEth = _lpTokens.mulTruncate(\n curvePool.get_virtual_price()\n );\n // Apply slippage to ETH value\n uint256 minAmount = valueInEth.mulTruncate(\n uint256(1e18) - MAX_SLIPPAGE\n );\n\n // Remove just the ETH from the Curve pool\n coinsRemoved = curvePool.remove_liquidity_one_coin(\n _lpTokens,\n int128(coinIndex),\n minAmount,\n address(this)\n );\n }\n\n /***************************************\n Assets and Rewards\n ****************************************/\n\n /**\n * @notice Collect accumulated CRV and CVX rewards and send to the Harvester.\n */\n function collectRewardTokens()\n external\n override\n onlyHarvester\n nonReentrant\n {\n // Collect CRV and CVX\n cvxRewardStaker.getReward();\n _collectRewardTokens();\n }\n\n function _lpWithdraw(uint256 _wethAmount) internal {\n // withdraw and unwrap with claim takes back the lpTokens\n // and also collects the rewards for deposit\n cvxRewardStaker.withdrawAndUnwrap(_wethAmount, true);\n }\n\n /**\n * @notice Get the total asset value held in the platform\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n public\n view\n override\n returns (uint256 balance)\n {\n require(_asset == address(weth), \"Unsupported asset\");\n\n // Eth balance needed here for the balance check that happens from vault during depositing.\n balance = address(this).balance;\n uint256 lpTokens = cvxRewardStaker.balanceOf(address(this));\n if (lpTokens > 0) {\n balance += (lpTokens * curvePool.get_virtual_price()) / 1e18;\n }\n }\n\n /**\n * @notice Returns bool indicating whether asset is supported by strategy\n * @param _asset Address of the asset\n */\n function supportsAsset(address _asset) public view override returns (bool) {\n return _asset == address(weth);\n }\n\n /***************************************\n Approvals\n ****************************************/\n\n /**\n * @notice Approve the spending of all assets by their corresponding pool tokens,\n * if for some reason is it necessary.\n */\n function safeApproveAllTokens()\n external\n override\n onlyGovernor\n nonReentrant\n {\n _approveBase();\n }\n\n /**\n * @notice Accept unwrapped WETH\n */\n receive() external payable {}\n\n /**\n * @dev Since we are unwrapping WETH before depositing it to Curve\n * there is no need to set an approval for WETH on the Curve\n * pool\n * @param _asset Address of the asset\n * @param _pToken Address of the Curve LP token\n */\n // solhint-disable-next-line no-unused-vars\n function _abstractSetPToken(address _asset, address _pToken)\n internal\n override\n {}\n\n function _approveBase() internal {\n // Approve Curve pool for OETH (required for adding liquidity)\n // No approval is needed for ETH\n // slither-disable-next-line unused-return\n oeth.approve(platformAddress, type(uint256).max);\n\n // Approve Convex deposit contract to transfer Curve pool LP tokens\n // This is needed for deposits if Curve pool LP tokens into the Convex rewards pool\n // slither-disable-next-line unused-return\n lpToken.approve(cvxDepositorAddress, type(uint256).max);\n }\n\n /**\n * @dev Returns the largest of two numbers int256 version\n */\n function _max(int256 a, int256 b) internal pure returns (int256) {\n return a >= b ? a : b;\n }\n}\n" + }, + "contracts/strategies/ConvexGeneralizedMetaStrategy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title Curve Convex Strategy\n * @notice Investment strategy for investing stablecoins via Curve 3Pool\n * @author Origin Protocol Inc\n */\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Strings.sol\";\n\nimport { IRewardStaking } from \"./IRewardStaking.sol\";\nimport { IConvexDeposits } from \"./IConvexDeposits.sol\";\nimport { ICurvePool } from \"./ICurvePool.sol\";\nimport { IERC20, InitializableAbstractStrategy } from \"./BaseCurveStrategy.sol\";\nimport { BaseConvexMetaStrategy } from \"./BaseConvexMetaStrategy.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\n\ncontract ConvexGeneralizedMetaStrategy is BaseConvexMetaStrategy {\n using StableMath for uint256;\n using SafeERC20 for IERC20;\n\n constructor(BaseStrategyConfig memory _stratConfig)\n InitializableAbstractStrategy(_stratConfig)\n {}\n\n /* Take 3pool LP and deposit it to metapool. Take the LP from metapool\n * and deposit them to Convex.\n */\n function _lpDepositAll() internal override {\n IERC20 threePoolLp = IERC20(pTokenAddress);\n ICurvePool curvePool = ICurvePool(platformAddress);\n\n uint256 threePoolLpBalance = threePoolLp.balanceOf(address(this));\n uint256 curve3PoolVirtualPrice = curvePool.get_virtual_price();\n uint256 threePoolLpDollarValue = threePoolLpBalance.mulTruncate(\n curve3PoolVirtualPrice\n );\n\n uint256[2] memory _amounts = [0, threePoolLpBalance];\n\n uint256 metapoolVirtualPrice = metapool.get_virtual_price();\n /**\n * First convert all the deposited tokens to dollar values,\n * then divide by virtual price to convert to metapool LP tokens\n * and apply the max slippage\n */\n uint256 minReceived = threePoolLpDollarValue\n .divPrecisely(metapoolVirtualPrice)\n .mulTruncate(uint256(1e18) - MAX_SLIPPAGE);\n\n uint256 metapoolLp = metapool.add_liquidity(_amounts, minReceived);\n\n bool success = IConvexDeposits(cvxDepositorAddress).deposit(\n cvxDepositorPTokenId,\n metapoolLp,\n true // Deposit with staking\n );\n\n require(success, \"Failed to deposit to Convex\");\n }\n\n /**\n * Withdraw the specified amount of tokens from the gauge. And use all the resulting tokens\n * to remove liquidity from metapool\n * @param num3CrvTokens Number of Convex 3pool LP tokens to withdraw from metapool\n */\n function _lpWithdraw(uint256 num3CrvTokens) internal override {\n uint256 gaugeTokens = IRewardStaking(cvxRewardStakerAddress).balanceOf(\n address(this)\n );\n\n uint256 requiredMetapoolLpTokens = _calcCurveMetaTokenAmount(\n crvCoinIndex,\n num3CrvTokens\n );\n\n require(\n requiredMetapoolLpTokens <= gaugeTokens,\n string(\n bytes.concat(\n bytes(\"Attempting to withdraw \"),\n bytes(Strings.toString(requiredMetapoolLpTokens)),\n bytes(\", metapoolLP but only \"),\n bytes(Strings.toString(gaugeTokens)),\n bytes(\" available.\")\n )\n )\n );\n\n // withdraw and unwrap with claim takes back the lpTokens and also collects the rewards for deposit\n IRewardStaking(cvxRewardStakerAddress).withdrawAndUnwrap(\n requiredMetapoolLpTokens,\n true\n );\n\n if (requiredMetapoolLpTokens > 0) {\n // slither-disable-next-line unused-return\n metapool.remove_liquidity_one_coin(\n requiredMetapoolLpTokens,\n int128(crvCoinIndex),\n num3CrvTokens\n );\n }\n }\n\n function _lpWithdrawAll() internal override {\n uint256 gaugeTokens = IRewardStaking(cvxRewardStakerAddress).balanceOf(\n address(this)\n );\n IRewardStaking(cvxRewardStakerAddress).withdrawAndUnwrap(\n gaugeTokens,\n true\n );\n\n if (gaugeTokens > 0) {\n uint256 burnDollarAmount = gaugeTokens.mulTruncate(\n metapool.get_virtual_price()\n );\n uint256 curve3PoolExpected = burnDollarAmount.divPrecisely(\n ICurvePool(platformAddress).get_virtual_price()\n );\n\n // Always withdraw all of the available metapool LP tokens (similar to how we always deposit all)\n // slither-disable-next-line unused-return\n metapool.remove_liquidity_one_coin(\n gaugeTokens,\n int128(crvCoinIndex),\n curve3PoolExpected -\n curve3PoolExpected.mulTruncate(maxWithdrawalSlippage)\n );\n }\n }\n}\n" + }, + "contracts/strategies/ConvexOUSDMetaStrategy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title Curve Convex Strategy\n * @notice Investment strategy for investing stablecoins via Curve 3Pool\n * @author Origin Protocol Inc\n */\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Strings.sol\";\nimport \"@openzeppelin/contracts/utils/math/Math.sol\";\n\nimport { IRewardStaking } from \"./IRewardStaking.sol\";\nimport { IConvexDeposits } from \"./IConvexDeposits.sol\";\nimport { ICurvePool } from \"./ICurvePool.sol\";\nimport { IERC20, InitializableAbstractStrategy } from \"./BaseCurveStrategy.sol\";\nimport { BaseConvexMetaStrategy } from \"./BaseConvexMetaStrategy.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\n\ncontract ConvexOUSDMetaStrategy is BaseConvexMetaStrategy {\n using StableMath for uint256;\n using SafeERC20 for IERC20;\n\n constructor(BaseStrategyConfig memory _stratConfig)\n InitializableAbstractStrategy(_stratConfig)\n {}\n\n /* Take 3pool LP and mint the corresponding amount of ousd. Deposit and stake that to\n * ousd Curve Metapool. Take the LP from metapool and deposit them to Convex.\n */\n function _lpDepositAll() internal override {\n ICurvePool curvePool = ICurvePool(platformAddress);\n\n uint256 threePoolLpBalance = IERC20(pTokenAddress).balanceOf(\n address(this)\n );\n uint256 curve3PoolVirtualPrice = curvePool.get_virtual_price();\n uint256 threePoolLpDollarValue = threePoolLpBalance.mulTruncate(\n curve3PoolVirtualPrice\n );\n\n // safe to cast since min value is at least 0\n uint256 ousdToAdd = uint256(\n _max(\n 0,\n int256(\n metapool.balances(crvCoinIndex).mulTruncate(\n curve3PoolVirtualPrice\n )\n ) -\n int256(metapool.balances(mainCoinIndex)) +\n int256(threePoolLpDollarValue)\n )\n );\n\n /* Add so much OUSD so that the pool ends up being balanced. And at minimum\n * add twice as much OUSD as 3poolLP and at maximum at twice as\n * much OUSD.\n */\n ousdToAdd = Math.max(ousdToAdd, threePoolLpDollarValue);\n ousdToAdd = Math.min(ousdToAdd, threePoolLpDollarValue * 2);\n\n /* Mint OUSD with a strategy that attempts to contribute to stability of OUSD metapool. Try\n * to mint so much OUSD that after deployment of liquidity pool ends up being balanced.\n *\n * To manage unpredictability minimal OUSD minted will always be at least equal or greater\n * to stablecoin(DAI, USDC, USDT) amount of 3CRVLP deployed. And never larger than twice the\n * stablecoin amount of 3CRVLP deployed even if it would have a further beneficial effect\n * on pool stability.\n */\n if (ousdToAdd > 0) {\n IVault(vaultAddress).mintForStrategy(ousdToAdd);\n }\n\n uint256[2] memory _amounts = [ousdToAdd, threePoolLpBalance];\n\n uint256 metapoolVirtualPrice = metapool.get_virtual_price();\n /**\n * First convert all the deposited tokens to dollar values,\n * then divide by virtual price to convert to metapool LP tokens\n * and apply the max slippage\n */\n uint256 minReceived = (ousdToAdd + threePoolLpDollarValue)\n .divPrecisely(metapoolVirtualPrice)\n .mulTruncate(uint256(1e18) - MAX_SLIPPAGE);\n\n uint256 metapoolLp = metapool.add_liquidity(_amounts, minReceived);\n\n bool success = IConvexDeposits(cvxDepositorAddress).deposit(\n cvxDepositorPTokenId,\n metapoolLp,\n true // Deposit with staking\n );\n\n require(success, \"Failed to deposit to Convex\");\n }\n\n /**\n * Withdraw the specified amount of tokens from the gauge. And use all the resulting tokens\n * to remove liquidity from metapool\n * @param num3CrvTokens Number of 3CRV tokens to withdraw from metapool\n */\n function _lpWithdraw(uint256 num3CrvTokens) internal override {\n ICurvePool curvePool = ICurvePool(platformAddress);\n /* The rate between coins in the metapool determines the rate at which metapool returns\n * tokens when doing balanced removal (remove_liquidity call). And by knowing how much 3crvLp\n * we want we can determine how much of OUSD we receive by removing liquidity.\n *\n * Because we are doing balanced removal we should be making profit when removing liquidity in a\n * pool tilted to either side.\n *\n * Important: A downside is that the Strategist / Governor needs to be\n * cognisant of not removing too much liquidity. And while the proposal to remove liquidity\n * is being voted on the pool tilt might change so much that the proposal that has been valid while\n * created is no longer valid.\n */\n\n uint256 crvPoolBalance = metapool.balances(crvCoinIndex);\n /* K is multiplied by 1e36 which is used for higher precision calculation of required\n * metapool LP tokens. Without it the end value can have rounding errors up to precision of\n * 10 digits. This way we move the decimal point by 36 places when doing the calculation\n * and again by 36 places when we are done with it.\n */\n uint256 k = (1e36 * metapoolLPToken.totalSupply()) / crvPoolBalance;\n // simplifying below to: `uint256 diff = (num3CrvTokens - 1) * k` causes loss of precision\n // prettier-ignore\n // slither-disable-next-line divide-before-multiply\n uint256 diff = crvPoolBalance * k -\n (crvPoolBalance - num3CrvTokens - 1) * k;\n uint256 lpToBurn = diff / 1e36;\n\n uint256 gaugeTokens = IRewardStaking(cvxRewardStakerAddress).balanceOf(\n address(this)\n );\n\n require(\n lpToBurn <= gaugeTokens,\n string(\n bytes.concat(\n bytes(\"Attempting to withdraw \"),\n bytes(Strings.toString(lpToBurn)),\n bytes(\", metapoolLP but only \"),\n bytes(Strings.toString(gaugeTokens)),\n bytes(\" available.\")\n )\n )\n );\n\n // withdraw and unwrap with claim takes back the lpTokens and also collects the rewards for deposit\n IRewardStaking(cvxRewardStakerAddress).withdrawAndUnwrap(\n lpToBurn,\n true\n );\n\n // calculate the min amount of OUSD expected for the specified amount of LP tokens\n uint256 minOUSDAmount = lpToBurn.mulTruncate(\n metapool.get_virtual_price()\n ) -\n num3CrvTokens.mulTruncate(curvePool.get_virtual_price()) -\n 1;\n\n // withdraw the liquidity from metapool\n uint256[2] memory _removedAmounts = metapool.remove_liquidity(\n lpToBurn,\n [minOUSDAmount, num3CrvTokens]\n );\n\n IVault(vaultAddress).burnForStrategy(_removedAmounts[mainCoinIndex]);\n }\n\n function _lpWithdrawAll() internal override {\n IERC20 metapoolErc20 = IERC20(address(metapool));\n uint256 gaugeTokens = IRewardStaking(cvxRewardStakerAddress).balanceOf(\n address(this)\n );\n IRewardStaking(cvxRewardStakerAddress).withdrawAndUnwrap(\n gaugeTokens,\n true\n );\n\n uint256[2] memory _minAmounts = [uint256(0), uint256(0)];\n uint256[2] memory _removedAmounts = metapool.remove_liquidity(\n metapoolErc20.balanceOf(address(this)),\n _minAmounts\n );\n\n IVault(vaultAddress).burnForStrategy(_removedAmounts[mainCoinIndex]);\n }\n}\n" + }, + "contracts/strategies/ConvexStrategy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title Curve Convex Strategy\n * @notice Investment strategy for investing stablecoins via Curve 3Pool\n * @author Origin Protocol Inc\n */\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { ICurvePool } from \"./ICurvePool.sol\";\nimport { IRewardStaking } from \"./IRewardStaking.sol\";\nimport { IConvexDeposits } from \"./IConvexDeposits.sol\";\nimport { IERC20, BaseCurveStrategy, InitializableAbstractStrategy } from \"./BaseCurveStrategy.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { Helpers } from \"../utils/Helpers.sol\";\n\n/*\n * IMPORTANT(!) If ConvexStrategy needs to be re-deployed, it requires new\n * proxy contract with fresh storage slots. Changes in `BaseCurveStrategy`\n * storage slots would break existing implementation.\n *\n * Remove this notice if ConvexStrategy is re-deployed\n */\ncontract ConvexStrategy is BaseCurveStrategy {\n using StableMath for uint256;\n using SafeERC20 for IERC20;\n\n address internal cvxDepositorAddress;\n address internal cvxRewardStakerAddress;\n // slither-disable-next-line constable-states\n address private _deprecated_cvxRewardTokenAddress;\n uint256 internal cvxDepositorPTokenId;\n\n constructor(BaseStrategyConfig memory _stratConfig)\n InitializableAbstractStrategy(_stratConfig)\n {}\n\n /**\n * Initializer for setting up strategy internal state. This overrides the\n * InitializableAbstractStrategy initializer as Curve strategies don't fit\n * well within that abstraction.\n * @param _rewardTokenAddresses Address of CRV & CVX\n * @param _assets Addresses of supported assets. MUST be passed in the same\n * order as returned by coins on the pool contract, i.e.\n * DAI, USDC, USDT\n * @param _pTokens Platform Token corresponding addresses\n * @param _cvxDepositorAddress Address of the Convex depositor(AKA booster) for this pool\n * @param _cvxRewardStakerAddress Address of the CVX rewards staker\n * @param _cvxDepositorPTokenId Pid of the pool referred to by Depositor and staker\n */\n function initialize(\n address[] calldata _rewardTokenAddresses, // CRV + CVX\n address[] calldata _assets,\n address[] calldata _pTokens,\n address _cvxDepositorAddress,\n address _cvxRewardStakerAddress,\n uint256 _cvxDepositorPTokenId\n ) external onlyGovernor initializer {\n require(_assets.length == 3, \"Must have exactly three assets\");\n // Should be set prior to abstract initialize call otherwise\n // abstractSetPToken calls will fail\n cvxDepositorAddress = _cvxDepositorAddress;\n cvxRewardStakerAddress = _cvxRewardStakerAddress;\n cvxDepositorPTokenId = _cvxDepositorPTokenId;\n pTokenAddress = _pTokens[0];\n\n InitializableAbstractStrategy._initialize(\n _rewardTokenAddresses,\n _assets,\n _pTokens\n );\n _approveBase();\n }\n\n function _lpDepositAll() internal override {\n IERC20 pToken = IERC20(pTokenAddress);\n // Deposit with staking\n bool success = IConvexDeposits(cvxDepositorAddress).deposit(\n cvxDepositorPTokenId,\n pToken.balanceOf(address(this)),\n true\n );\n require(success, \"Failed to deposit to Convex\");\n }\n\n function _lpWithdraw(uint256 numCrvTokens) internal override {\n uint256 gaugePTokens = IRewardStaking(cvxRewardStakerAddress).balanceOf(\n address(this)\n );\n\n // Not enough in this contract or in the Gauge, can't proceed\n require(numCrvTokens > gaugePTokens, \"Insufficient 3CRV balance\");\n\n // withdraw and unwrap with claim takes back the lpTokens and also collects the rewards to this\n IRewardStaking(cvxRewardStakerAddress).withdrawAndUnwrap(\n numCrvTokens,\n true\n );\n }\n\n function _lpWithdrawAll() internal override {\n // withdraw and unwrap with claim takes back the lpTokens and also collects the rewards to this\n IRewardStaking(cvxRewardStakerAddress).withdrawAndUnwrap(\n IRewardStaking(cvxRewardStakerAddress).balanceOf(address(this)),\n true\n );\n }\n\n function _approveBase() internal override {\n IERC20 pToken = IERC20(pTokenAddress);\n // 3Pool for LP token (required for removing liquidity)\n pToken.safeApprove(platformAddress, 0);\n pToken.safeApprove(platformAddress, type(uint256).max);\n // Gauge for LP token\n pToken.safeApprove(cvxDepositorAddress, 0);\n pToken.safeApprove(cvxDepositorAddress, type(uint256).max);\n }\n\n /**\n * @dev Get the total asset value held in the platform\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n public\n view\n override\n returns (uint256 balance)\n {\n require(assetToPToken[_asset] != address(0), \"Unsupported asset\");\n // LP tokens in this contract. This should generally be nothing as we\n // should always stake the full balance in the Gauge, but include for\n // safety\n uint256 contractPTokens = IERC20(pTokenAddress).balanceOf(\n address(this)\n );\n uint256 gaugePTokens = IRewardStaking(cvxRewardStakerAddress).balanceOf(\n address(this)\n );\n uint256 totalPTokens = contractPTokens + gaugePTokens;\n\n ICurvePool curvePool = ICurvePool(platformAddress);\n if (totalPTokens > 0) {\n uint256 virtual_price = curvePool.get_virtual_price();\n uint256 value = (totalPTokens * virtual_price) / 1e18;\n uint256 assetDecimals = Helpers.getDecimals(_asset);\n balance = value.scaleBy(assetDecimals, 18) / 3;\n }\n }\n\n /**\n * @dev Collect accumulated CRV and CVX and send to Vault.\n */\n function collectRewardTokens()\n external\n override\n onlyHarvester\n nonReentrant\n {\n // Collect CRV and CVX\n IRewardStaking(cvxRewardStakerAddress).getReward();\n _collectRewardTokens();\n }\n}\n" + }, + "contracts/strategies/FluxStrategy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title Flux Strategy\n * @notice Investment strategy for investing stablecoins via Flux\n * @author Origin Protocol Inc\n */\n\nimport { CompoundStrategy } from \"./CompoundStrategy.sol\";\n\ncontract FluxStrategy is CompoundStrategy {\n constructor(BaseStrategyConfig memory _stratConfig)\n CompoundStrategy(_stratConfig)\n {}\n\n /**\n * @inheritdoc CompoundStrategy\n */\n function collectRewardTokens() external override {\n // Intentionally not adding any modifiers to not increase contract size\n // Flux strategy has no reward tokens\n }\n}\n" + }, + "contracts/strategies/FraxETHStrategy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title OETH FraxETH Strategy\n * @notice Investment WETH and FraxETH into the sFraxETH staking contract\n * @author Origin Protocol Inc\n */\nimport { IERC4626 } from \"../../lib/openzeppelin/interfaces/IERC4626.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IWETH9 } from \"../interfaces/IWETH9.sol\";\nimport { IFraxETHMinter } from \"../interfaces/IFraxETHMinter.sol\";\nimport { Generalized4626Strategy, IERC20, InitializableAbstractStrategy } from \"./Generalized4626Strategy.sol\";\n\ncontract FraxETHStrategy is Generalized4626Strategy {\n using SafeERC20 for IERC20;\n\n address public constant weth = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;\n\n IFraxETHMinter public constant fraxETHMinter =\n IFraxETHMinter(0xbAFA44EFE7901E04E39Dad13167D089C559c1138);\n\n /**\n * @param _baseConfig Base strategy config with platformAddress (sfrxETH) and vaultAddress (OETHVaultProxy)\n * @param _assetToken Address of the ERC-4626 asset token (frxETH)\n */\n constructor(BaseStrategyConfig memory _baseConfig, address _assetToken)\n Generalized4626Strategy(_baseConfig, _assetToken)\n {}\n\n function initialize() external override onlyGovernor initializer {\n address[] memory rewardTokens = new address[](0);\n address[] memory assets = new address[](2);\n address[] memory pTokens = new address[](2);\n\n assets[0] = address(assetToken);\n assets[1] = address(weth);\n pTokens[0] = address(platformAddress);\n pTokens[1] = address(platformAddress);\n\n InitializableAbstractStrategy._initialize(\n rewardTokens,\n assets,\n pTokens\n );\n }\n\n function _deposit(address _asset, uint256 _amount) internal override {\n require(_amount > 0, \"Must deposit something\");\n\n if (_asset == weth) {\n // Unwrap WETH\n IWETH9(weth).withdraw(_amount);\n\n // Deposit ETH for frxETH and stake it\n // slither-disable-next-line unused-return\n fraxETHMinter.submitAndDeposit{ value: _amount }(address(this));\n } else if (_asset == address(assetToken)) {\n // Stake frxETH\n // slither-disable-next-line unused-return\n IERC4626(platformAddress).deposit(_amount, address(this));\n } else {\n revert(\"Unexpected asset address\");\n }\n\n emit Deposit(_asset, address(shareToken), _amount);\n }\n\n /**\n * @dev Retuns bool indicating whether asset is supported by strategy\n * @param _asset Address of the asset\n */\n function supportsAsset(address _asset) public view override returns (bool) {\n return _asset == address(assetToken) || _asset == weth;\n }\n\n /**\n * @dev Get the total asset value held in the platform\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n external\n view\n virtual\n override\n returns (uint256 balance)\n {\n if (_asset == weth) {\n // For WETH, it's always 0\n return 0;\n }\n\n // If it's not WETH, it has to be frxETH\n require(_asset == address(assetToken), \"Unexpected asset address\");\n\n /* We are intentionally not counting the amount of assetToken parked on the\n * contract toward the checkBalance. The deposit and withdraw functions\n * should not result in assetToken being unused and owned by this strategy\n * contract.\n */\n return IERC4626(platformAddress).maxWithdraw(address(this));\n }\n\n /**\n * @dev Deposit the entire balance of assetToken to gain shareToken\n */\n function depositAll() external virtual override onlyVault nonReentrant {\n uint256 balance = assetToken.balanceOf(address(this));\n if (balance > 0) {\n _deposit(address(assetToken), balance);\n }\n\n uint256 wethBalance = IWETH9(weth).balanceOf(address(this));\n if (wethBalance > 0) {\n _deposit(weth, wethBalance);\n }\n }\n\n /**\n * @dev Accept ETH\n */\n receive() external payable {}\n}\n" + }, + "contracts/strategies/FrxEthRedeemStrategy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC721Receiver } from \"@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol\";\n\nimport { IERC20, InitializableAbstractStrategy } from \"../utils/InitializableAbstractStrategy.sol\";\nimport { IWETH9 } from \"../interfaces/IWETH9.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\n\ninterface IFraxEtherRedemptionQueue {\n function burnRedemptionTicketNft(uint256 _nftId, address payable _recipient)\n external;\n\n function enterRedemptionQueue(address _recipient, uint120 _amountToRedeem)\n external\n returns (uint256 _nftId);\n}\n\n/**\n * @title Frax ETH Redeem Strategy\n * @notice This strategy redeems Frax ETH for ETH via the Frax Eth Redemption Queue contract\n * @author Origin Protocol Inc\n */\ncontract FrxEthRedeemStrategy is InitializableAbstractStrategy {\n IWETH9 private constant weth =\n IWETH9(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);\n IERC20 private constant frxETH =\n IERC20(0x5E8422345238F34275888049021821E8E08CAa1f);\n IFraxEtherRedemptionQueue private constant redemptionQueue =\n IFraxEtherRedemptionQueue(0x82bA8da44Cd5261762e629dd5c605b17715727bd);\n uint256 public constant maxRedeemTicket = 250e18;\n uint256 public outstandingRedeems;\n\n event RedeemNFTMinted(uint256 _nftId, uint256 _amount);\n event RedeemNFTBurned(uint256 _nftId);\n\n constructor(BaseStrategyConfig memory _stratConfig)\n InitializableAbstractStrategy(_stratConfig)\n {\n require(maxRedeemTicket < type(uint120).max);\n }\n\n /**\n * @notice initialize function, to set up initial internal state\n * @param _rewardTokenAddresses Address of reward token for platform\n * @param _assets Addresses of initial supported assets\n * @param _pTokens Platform Token corresponding addresses\n */\n function initialize(\n address[] memory _rewardTokenAddresses,\n address[] memory _assets,\n address[] memory _pTokens\n ) external onlyGovernor initializer {\n InitializableAbstractStrategy._initialize(\n _rewardTokenAddresses,\n _assets,\n _pTokens\n );\n safeApproveAllTokens();\n }\n\n /**\n * @notice deposit() function not used for this strategy. Use depositAll() instead.\n */\n function deposit(address, uint256) public override onlyVault nonReentrant {\n // This method no longer used by the VaultAdmin, and we don't want it\n // to be used by VaultCore.\n require(false, \"use depositAll() instead\");\n }\n\n /**\n * @notice Takes all given frxETH and creates new redeem tickets\n */\n function depositAll() external override onlyVault nonReentrant {\n uint256 frxETHStart = frxETH.balanceOf(address(this));\n require(frxETHStart > 0, \"No frxETH to redeem\");\n uint256 frxETHRemaining = frxETHStart;\n\n while (frxETHRemaining > 0) {\n uint256 amount = frxETHRemaining > maxRedeemTicket\n ? maxRedeemTicket\n : frxETHRemaining;\n uint256 nftId = redemptionQueue.enterRedemptionQueue(\n address(this),\n uint120(amount)\n );\n frxETHRemaining -= amount;\n emit RedeemNFTMinted(nftId, amount);\n }\n\n require(\n frxETH.balanceOf(address(this)) == 0,\n \"Not all FraxEth sent to redemption queue\"\n );\n outstandingRedeems += frxETHStart; // Single set for gas reasons\n\n // This strategy claims to support WETH, so it is posible for\n // the vault to transfer WETH to it. This returns any deposited WETH\n // to the vault so that it is not lost for balance tracking purposes.\n uint256 wethBalance = weth.balanceOf(address(this));\n if (wethBalance > 0) {\n // slither-disable-next-line unchecked-transfer\n weth.transfer(vaultAddress, wethBalance);\n }\n\n emit Deposit(address(frxETH), address(redemptionQueue), frxETHStart);\n }\n\n /**\n * @notice Withdraw an asset from the underlying platform\n * @param _recipient Address to receive withdrawn assets\n * @param _asset Address of the asset to withdraw\n * @param _amount Amount of assets to withdraw\n */\n function withdraw(\n // solhint-disable-next-line no-unused-vars\n address _recipient,\n // solhint-disable-next-line no-unused-vars\n address _asset,\n // solhint-disable-next-line no-unused-vars\n uint256 _amount\n ) external override onlyVault nonReentrant {\n // Does nothing - all redeems need to be called manually by the\n // strategist via redeemTickets\n require(false, \"use redeemTickets() instead\");\n }\n\n /**\n * @notice Redeem specific tickets from the Queue.\n * Called by the strategist.\n * @param _nftIds Array of NFT IDs to redeem\n */\n function redeemTickets(uint256[] memory _nftIds, uint256 expectedAmount)\n external\n nonReentrant\n {\n require(\n msg.sender == IVault(vaultAddress).strategistAddr(),\n \"Caller is not the Strategist\"\n );\n uint256 startingBalance = payable(address(this)).balance;\n for (uint256 i = 0; i < _nftIds.length; i++) {\n uint256 nftId = _nftIds[i];\n redemptionQueue.burnRedemptionTicketNft(\n nftId,\n payable(address(this))\n );\n emit RedeemNFTBurned(nftId);\n }\n\n uint256 currentBalance = payable(address(this)).balance;\n uint256 redeemedAmount = currentBalance - startingBalance;\n require(\n expectedAmount == redeemedAmount,\n \"Redeemed amount does not match expected amount\"\n );\n outstandingRedeems -= redeemedAmount;\n weth.deposit{ value: currentBalance }();\n // slither-disable-next-line unchecked-transfer\n weth.transfer(vaultAddress, currentBalance);\n emit Withdrawal(\n address(weth),\n address(redemptionQueue),\n currentBalance\n );\n }\n\n function _abstractSetPToken(address, address) internal override {\n revert(\"No pTokens are used\");\n }\n\n /**\n * @notice Withdraw all assets from this strategy, and transfer to the Vault.\n * In correct operation, this strategy should never hold any assets.\n */\n function withdrawAll() external override onlyVaultOrGovernor nonReentrant {\n if (payable(address(this)).balance > 0) {\n weth.deposit{ value: payable(address(this)).balance }();\n }\n uint256 wethBalance = weth.balanceOf(address(this));\n if (wethBalance > 0) {\n // slither-disable-next-line unchecked-transfer\n weth.transfer(vaultAddress, wethBalance);\n emit Withdrawal(address(weth), address(0), wethBalance);\n }\n uint256 fraxEthBalance = frxETH.balanceOf(address(this));\n if (fraxEthBalance > 0) {\n // slither-disable-next-line unchecked-transfer\n frxETH.transfer(vaultAddress, fraxEthBalance);\n emit Withdrawal(address(frxETH), address(0), fraxEthBalance);\n }\n }\n\n /**\n * @notice Returns the amount of queued FraxEth that will be returned as WETH.\n * We return this as a WETH asset, since that is what it will eventually be returned as.\n * We only return the outstandingRedeems, because the contract itself should never hold any funds.\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n external\n view\n override\n returns (uint256 balance)\n {\n if (_asset == address(weth)) {\n return outstandingRedeems;\n } else if (_asset == address(frxETH)) {\n return 0;\n } else {\n revert(\"Unexpected asset address\");\n }\n }\n\n /**\n * @notice Approve the spending of all assets by their corresponding cToken,\n * if for some reason is it necessary.\n */\n function safeApproveAllTokens() public override {\n // slither-disable-next-line unused-return\n frxETH.approve(address(redemptionQueue), type(uint256).max);\n }\n\n /**\n * @notice Check if an asset is supported.\n * @param _asset Address of the asset\n * @return bool Whether asset is supported\n */\n function supportsAsset(address _asset) public pure override returns (bool) {\n // frxETH can be deposited by the vault and balances are reported in weth\n return _asset == address(frxETH) || _asset == address(weth);\n }\n\n function onERC721Received(\n // solhint-disable-next-line no-unused-vars\n address operator,\n // solhint-disable-next-line no-unused-vars\n address from,\n // solhint-disable-next-line no-unused-vars\n uint256 tokenId,\n // solhint-disable-next-line no-unused-vars\n bytes calldata data\n ) external returns (bytes4) {\n return IERC721Receiver.onERC721Received.selector;\n }\n\n receive() external payable {}\n}\n" + }, + "contracts/strategies/Generalized4626Strategy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title Generalized 4626 Strategy\n * @notice Investment strategy for ERC-4626 Tokenized Vaults\n * @author Origin Protocol Inc\n */\nimport { IERC4626 } from \"../../lib/openzeppelin/interfaces/IERC4626.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20, InitializableAbstractStrategy } from \"../utils/InitializableAbstractStrategy.sol\";\n\ncontract Generalized4626Strategy is InitializableAbstractStrategy {\n using SafeERC20 for IERC20;\n\n /// @dev Replaced with an immutable variable\n // slither-disable-next-line constable-states\n address private _deprecate_shareToken;\n /// @dev Replaced with an immutable variable\n // slither-disable-next-line constable-states\n address private _deprecate_assetToken;\n\n IERC20 public immutable shareToken;\n IERC20 public immutable assetToken;\n\n // For future use\n uint256[50] private __gap;\n\n /**\n * @param _baseConfig Base strategy config with platformAddress (ERC-4626 Vault contract), eg sfrxETH or sDAI,\n * and vaultAddress (OToken Vault contract), eg VaultProxy or OETHVaultProxy\n * @param _assetToken Address of the ERC-4626 asset token. eg frxETH or DAI\n */\n constructor(BaseStrategyConfig memory _baseConfig, address _assetToken)\n InitializableAbstractStrategy(_baseConfig)\n {\n shareToken = IERC20(_baseConfig.platformAddress);\n assetToken = IERC20(_assetToken);\n }\n\n function initialize() external virtual onlyGovernor initializer {\n address[] memory rewardTokens = new address[](0);\n address[] memory assets = new address[](1);\n address[] memory pTokens = new address[](1);\n\n assets[0] = address(assetToken);\n pTokens[0] = address(platformAddress);\n\n InitializableAbstractStrategy._initialize(\n rewardTokens,\n assets,\n pTokens\n );\n }\n\n /**\n * @dev Deposit assets by converting them to shares\n * @param _asset Address of asset to deposit\n * @param _amount Amount of asset to deposit\n */\n function deposit(address _asset, uint256 _amount)\n external\n override\n onlyVault\n nonReentrant\n {\n _deposit(_asset, _amount);\n }\n\n /**\n * @dev Deposit assets by converting them to shares\n * @param _asset Address of asset to deposit\n * @param _amount Amount of asset to deposit\n */\n function _deposit(address _asset, uint256 _amount) internal virtual {\n require(_amount > 0, \"Must deposit something\");\n require(_asset == address(assetToken), \"Unexpected asset address\");\n\n // slither-disable-next-line unused-return\n IERC4626(platformAddress).deposit(_amount, address(this));\n emit Deposit(_asset, address(shareToken), _amount);\n }\n\n /**\n * @dev Deposit the entire balance of assetToken to gain shareToken\n */\n function depositAll() external virtual override onlyVault nonReentrant {\n uint256 balance = assetToken.balanceOf(address(this));\n if (balance > 0) {\n _deposit(address(assetToken), balance);\n }\n }\n\n /**\n * @dev Withdraw asset by burning shares\n * @param _recipient Address to receive withdrawn asset\n * @param _asset Address of asset to withdraw\n * @param _amount Amount of asset to withdraw\n */\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external virtual override onlyVault nonReentrant {\n require(_amount > 0, \"Must withdraw something\");\n require(_recipient != address(0), \"Must specify recipient\");\n require(_asset == address(assetToken), \"Unexpected asset address\");\n\n // slither-disable-next-line unused-return\n IERC4626(platformAddress).withdraw(_amount, _recipient, address(this));\n emit Withdrawal(_asset, address(shareToken), _amount);\n }\n\n /**\n * @dev Internal method to respond to the addition of new asset / share tokens\n */\n function _abstractSetPToken(address, address) internal virtual override {\n _approveBase();\n }\n\n /**\n * @dev Remove all assets from platform and send them to Vault contract.\n */\n function withdrawAll()\n external\n virtual\n override\n onlyVaultOrGovernor\n nonReentrant\n {\n uint256 shareBalance = shareToken.balanceOf(address(this));\n uint256 assetAmount = 0;\n if (shareBalance > 0) {\n assetAmount = IERC4626(platformAddress).redeem(\n shareBalance,\n vaultAddress,\n address(this)\n );\n emit Withdrawal(\n address(assetToken),\n address(shareToken),\n assetAmount\n );\n }\n }\n\n /**\n * @dev Get the total asset value held in the platform\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n external\n view\n virtual\n override\n returns (uint256 balance)\n {\n require(_asset == address(assetToken), \"Unexpected asset address\");\n /* We are intentionally not counting the amount of assetToken parked on the\n * contract toward the checkBalance. The deposit and withdraw functions\n * should not result in assetToken being unused and owned by this strategy\n * contract.\n */\n return IERC4626(platformAddress).maxWithdraw(address(this));\n }\n\n /**\n * @notice Governor approves the the ERC-4626 Tokenized Vault to spend the asset.\n */\n function safeApproveAllTokens() external override onlyGovernor {\n _approveBase();\n }\n\n function _approveBase() internal virtual {\n // Approval the asset to be trasferred to the ERC-4626 Tokenized Vualt.\n // Used by the ERC-4626 deposit() and mint() functions\n // slither-disable-next-line unused-return\n assetToken.approve(platformAddress, type(uint256).max);\n }\n\n /**\n * @dev Retuns bool indicating whether asset is supported by strategy\n * @param _asset Address of the asset\n */\n function supportsAsset(address _asset)\n public\n view\n virtual\n override\n returns (bool)\n {\n return _asset == address(assetToken);\n }\n\n /**\n * @notice is not supported for this strategy as the asset and\n * ERC-4626 Tokenized Vault are set at deploy time.\n * @dev If the ERC-4626 Tokenized Vault needed to be changed, a new\n * contract would need to be deployed and the proxy updated.\n */\n function setPTokenAddress(address, address) external override onlyGovernor {\n revert(\"unsupported function\");\n }\n\n /**\n * @notice is not supported for this strategy as the asset and\n * ERC-4626 Tokenized Vault are set at deploy time.\n * @dev If the ERC-4626 Tokenized Vault needed to be changed, a new\n * contract would need to be deployed and the proxy updated.\n */\n function removePToken(uint256) external override onlyGovernor {\n revert(\"unsupported function\");\n }\n}\n" + }, + "contracts/strategies/IAave.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface for Aaves Lending Pool\n * Documentation: https://developers.aave.com/#lendingpool\n */\ninterface IAaveLendingPool {\n /**\n * @dev Deposits an `amount` of underlying asset into the reserve, receiving in return overlying aTokens.\n * - E.g. User deposits 100 USDC and gets in return 100 aUSDC\n * @param asset The address of the underlying asset to deposit\n * @param amount The amount to be deposited\n * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user\n * wants to receive them on his own wallet, or a different address if the beneficiary of aTokens\n * is a different wallet\n * @param referralCode Code used to register the integrator originating the operation, for potential rewards.\n * 0 if the action is executed directly by the user, without any middle-man\n **/\n function deposit(\n address asset,\n uint256 amount,\n address onBehalfOf,\n uint16 referralCode\n ) external;\n\n /**\n * @dev Withdraws an `amount` of underlying asset from the reserve, burning the equivalent aTokens owned\n * E.g. User has 100 aUSDC, calls withdraw() and receives 100 USDC, burning the 100 aUSDC\n * @param asset The address of the underlying asset to withdraw\n * @param amount The underlying amount to be withdrawn\n * - Send the value type(uint256).max in order to withdraw the whole aToken balance\n * @param to Address that will receive the underlying, same as msg.sender if the user\n * wants to receive it on his own wallet, or a different address if the beneficiary is a\n * different wallet\n * @return The final amount withdrawn\n **/\n function withdraw(\n address asset,\n uint256 amount,\n address to\n ) external returns (uint256);\n}\n\n/**\n * @dev Interface for Aaves Lending Pool\n * Documentation: https://developers.aave.com/#lendingpooladdressesprovider\n */\ninterface ILendingPoolAddressesProvider {\n /**\n * @notice Get the current address for Aave LendingPool\n * @dev Lending pool is the core contract on which to call deposit\n */\n function getLendingPool() external view returns (address);\n}\n" + }, + "contracts/strategies/IAaveIncentivesController.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IAaveIncentivesController {\n event RewardsAccrued(address indexed user, uint256 amount);\n\n event RewardsClaimed(\n address indexed user,\n address indexed to,\n uint256 amount\n );\n\n event RewardsClaimed(\n address indexed user,\n address indexed to,\n address indexed claimer,\n uint256 amount\n );\n\n event ClaimerSet(address indexed user, address indexed claimer);\n\n /*\n * @dev Returns the configuration of the distribution for a certain asset\n * @param asset The address of the reference asset of the distribution\n * @return The asset index, the emission per second and the last updated timestamp\n **/\n function getAssetData(address asset)\n external\n view\n returns (\n uint256,\n uint256,\n uint256\n );\n\n /**\n * @dev Whitelists an address to claim the rewards on behalf of another address\n * @param user The address of the user\n * @param claimer The address of the claimer\n */\n function setClaimer(address user, address claimer) external;\n\n /**\n * @dev Returns the whitelisted claimer for a certain address (0x0 if not set)\n * @param user The address of the user\n * @return The claimer address\n */\n function getClaimer(address user) external view returns (address);\n\n /**\n * @dev Configure assets for a certain rewards emission\n * @param assets The assets to incentivize\n * @param emissionsPerSecond The emission for each asset\n */\n function configureAssets(\n address[] calldata assets,\n uint256[] calldata emissionsPerSecond\n ) external;\n\n /**\n * @dev Called by the corresponding asset on any update that affects the rewards distribution\n * @param asset The address of the user\n * @param userBalance The balance of the user of the asset in the lending pool\n * @param totalSupply The total supply of the asset in the lending pool\n **/\n function handleAction(\n address asset,\n uint256 userBalance,\n uint256 totalSupply\n ) external;\n\n /**\n * @dev Returns the total of rewards of an user, already accrued + not yet accrued\n * @param user The address of the user\n * @return The rewards\n **/\n function getRewardsBalance(address[] calldata assets, address user)\n external\n view\n returns (uint256);\n\n /**\n * @dev Claims reward for an user, on all the assets of the lending pool,\n * accumulating the pending rewards\n * @param amount Amount of rewards to claim\n * @param to Address that will be receiving the rewards\n * @return Rewards claimed\n **/\n function claimRewards(\n address[] calldata assets,\n uint256 amount,\n address to\n ) external returns (uint256);\n\n /**\n * @dev Claims reward for an user on behalf, on all the assets of the\n * lending pool, accumulating the pending rewards. The caller must\n * be whitelisted via \"allowClaimOnBehalf\" function by the RewardsAdmin role manager\n * @param amount Amount of rewards to claim\n * @param user Address to check and claim rewards\n * @param to Address that will be receiving the rewards\n * @return Rewards claimed\n **/\n function claimRewardsOnBehalf(\n address[] calldata assets,\n uint256 amount,\n address user,\n address to\n ) external returns (uint256);\n\n /**\n * @dev returns the unclaimed rewards of the user\n * @param user the address of the user\n * @return the unclaimed user rewards\n */\n function getUserUnclaimedRewards(address user)\n external\n view\n returns (uint256);\n\n /**\n * @dev returns the unclaimed rewards of the user\n * @param user the address of the user\n * @param asset The asset to incentivize\n * @return the user index for the asset\n */\n function getUserAssetData(address user, address asset)\n external\n view\n returns (uint256);\n\n /**\n * @dev for backward compatibility with previous implementation of the Incentives controller\n */\n function REWARD_TOKEN() external view returns (address);\n\n /**\n * @dev for backward compatibility with previous implementation of the Incentives controller\n */\n function PRECISION() external view returns (uint8);\n\n /**\n * @dev Gets the distribution end timestamp of the emissions\n */\n function DISTRIBUTION_END() external view returns (uint256);\n}\n" + }, + "contracts/strategies/IAaveStakeToken.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IAaveStakedToken {\n function COOLDOWN_SECONDS() external returns (uint256);\n\n function UNSTAKE_WINDOW() external returns (uint256);\n\n function balanceOf(address addr) external returns (uint256);\n\n function redeem(address to, uint256 amount) external;\n\n function stakersCooldowns(address addr) external returns (uint256);\n\n function cooldown() external;\n}\n" + }, + "contracts/strategies/ICompound.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @dev Compound C Token interface\n * Documentation: https://compound.finance/developers/ctokens\n */\ninterface ICERC20 {\n /**\n * @notice The mint function transfers an asset into the protocol, which begins accumulating\n * interest based on the current Supply Rate for the asset. The user receives a quantity of\n * cTokens equal to the underlying tokens supplied, divided by the current Exchange Rate.\n * @param mintAmount The amount of the asset to be supplied, in units of the underlying asset.\n * @return 0 on success, otherwise an Error codes\n */\n function mint(uint256 mintAmount) external returns (uint256);\n\n /**\n * @notice Sender redeems cTokens in exchange for the underlying asset\n * @dev Accrues interest whether or not the operation succeeds, unless reverted\n * @param redeemTokens The number of cTokens to redeem into underlying\n * @return uint 0=success, otherwise an error code.\n */\n function redeem(uint256 redeemTokens) external returns (uint256);\n\n /**\n * @notice The redeem underlying function converts cTokens into a specified quantity of the underlying\n * asset, and returns them to the user. The amount of cTokens redeemed is equal to the quantity of\n * underlying tokens received, divided by the current Exchange Rate. The amount redeemed must be less\n * than the user's Account Liquidity and the market's available liquidity.\n * @param redeemAmount The amount of underlying to be redeemed.\n * @return 0 on success, otherwise an error code.\n */\n function redeemUnderlying(uint256 redeemAmount) external returns (uint256);\n\n /**\n * @notice The user's underlying balance, representing their assets in the protocol, is equal to\n * the user's cToken balance multiplied by the Exchange Rate.\n * @param owner The account to get the underlying balance of.\n * @return The amount of underlying currently owned by the account.\n */\n function balanceOfUnderlying(address owner) external returns (uint256);\n\n /**\n * @notice Calculates the exchange rate from the underlying to the CToken\n * @dev This function does not accrue interest before calculating the exchange rate\n * @return Calculated exchange rate scaled by 1e18\n */\n function exchangeRateStored() external view returns (uint256);\n\n /**\n * @notice Get the token balance of the `owner`\n * @param owner The address of the account to query\n * @return The number of tokens owned by `owner`\n */\n function balanceOf(address owner) external view returns (uint256);\n\n /**\n * @notice Get the supply rate per block for supplying the token to Compound.\n */\n function supplyRatePerBlock() external view returns (uint256);\n\n /**\n * @notice Address of the Compound Comptroller.\n */\n function comptroller() external view returns (address);\n}\n" + }, + "contracts/strategies/IConvexDeposits.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IConvexDeposits {\n function deposit(\n uint256 _pid,\n uint256 _amount,\n bool _stake\n ) external returns (bool);\n\n function deposit(\n uint256 _amount,\n bool _lock,\n address _stakeAddress\n ) external;\n}\n" + }, + "contracts/strategies/ICRVMinter.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface ICRVMinter {\n function mint(address gaugeAddress) external;\n}\n" + }, + "contracts/strategies/ICurveETHPoolV1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface ICurveETHPoolV1 {\n event AddLiquidity(\n address indexed provider,\n uint256[2] token_amounts,\n uint256[2] fees,\n uint256 invariant,\n uint256 token_supply\n );\n event ApplyNewFee(uint256 fee);\n event Approval(\n address indexed owner,\n address indexed spender,\n uint256 value\n );\n event CommitNewFee(uint256 new_fee);\n event RampA(\n uint256 old_A,\n uint256 new_A,\n uint256 initial_time,\n uint256 future_time\n );\n event RemoveLiquidity(\n address indexed provider,\n uint256[2] token_amounts,\n uint256[2] fees,\n uint256 token_supply\n );\n event RemoveLiquidityImbalance(\n address indexed provider,\n uint256[2] token_amounts,\n uint256[2] fees,\n uint256 invariant,\n uint256 token_supply\n );\n event RemoveLiquidityOne(\n address indexed provider,\n uint256 token_amount,\n uint256 coin_amount,\n uint256 token_supply\n );\n event StopRampA(uint256 A, uint256 t);\n event TokenExchange(\n address indexed buyer,\n int128 sold_id,\n uint256 tokens_sold,\n int128 bought_id,\n uint256 tokens_bought\n );\n event Transfer(\n address indexed sender,\n address indexed receiver,\n uint256 value\n );\n\n function A() external view returns (uint256);\n\n function A_precise() external view returns (uint256);\n\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n\n function add_liquidity(uint256[2] memory _amounts, uint256 _min_mint_amount)\n external\n payable\n returns (uint256);\n\n function add_liquidity(\n uint256[2] memory _amounts,\n uint256 _min_mint_amount,\n address _receiver\n ) external payable returns (uint256);\n\n function admin_action_deadline() external view returns (uint256);\n\n function admin_balances(uint256 i) external view returns (uint256);\n\n function admin_fee() external view returns (uint256);\n\n function allowance(address arg0, address arg1)\n external\n view\n returns (uint256);\n\n function apply_new_fee() external;\n\n function approve(address _spender, uint256 _value) external returns (bool);\n\n function balanceOf(address arg0) external view returns (uint256);\n\n function balances(uint256 arg0) external view returns (uint256);\n\n function calc_token_amount(uint256[2] memory _amounts, bool _is_deposit)\n external\n view\n returns (uint256);\n\n function calc_withdraw_one_coin(uint256 _burn_amount, int128 i)\n external\n view\n returns (uint256);\n\n function coins(uint256 arg0) external view returns (address);\n\n function commit_new_fee(uint256 _new_fee) external;\n\n function decimals() external view returns (uint256);\n\n function ema_price() external view returns (uint256);\n\n function exchange(\n int128 i,\n int128 j,\n uint256 _dx,\n uint256 _min_dy\n ) external payable returns (uint256);\n\n function exchange(\n int128 i,\n int128 j,\n uint256 _dx,\n uint256 _min_dy,\n address _receiver\n ) external payable returns (uint256);\n\n function fee() external view returns (uint256);\n\n function future_A() external view returns (uint256);\n\n function future_A_time() external view returns (uint256);\n\n function future_fee() external view returns (uint256);\n\n function get_balances() external view returns (uint256[2] memory);\n\n function get_dy(\n int128 i,\n int128 j,\n uint256 dx\n ) external view returns (uint256);\n\n function get_p() external view returns (uint256);\n\n function get_virtual_price() external view returns (uint256);\n\n function initial_A() external view returns (uint256);\n\n function initial_A_time() external view returns (uint256);\n\n function initialize(\n string memory _name,\n string memory _symbol,\n address[4] memory _coins,\n uint256[4] memory _rate_multipliers,\n uint256 _A,\n uint256 _fee\n ) external;\n\n function last_price() external view returns (uint256);\n\n function ma_exp_time() external view returns (uint256);\n\n function ma_last_time() external view returns (uint256);\n\n function name() external view returns (string memory);\n\n function nonces(address arg0) external view returns (uint256);\n\n function permit(\n address _owner,\n address _spender,\n uint256 _value,\n uint256 _deadline,\n uint8 _v,\n bytes32 _r,\n bytes32 _s\n ) external returns (bool);\n\n function price_oracle() external view returns (uint256);\n\n function ramp_A(uint256 _future_A, uint256 _future_time) external;\n\n function remove_liquidity(\n uint256 _burn_amount,\n uint256[2] memory _min_amounts\n ) external returns (uint256[2] memory);\n\n function remove_liquidity(\n uint256 _burn_amount,\n uint256[2] memory _min_amounts,\n address _receiver\n ) external returns (uint256[2] memory);\n\n function remove_liquidity_imbalance(\n uint256[2] memory _amounts,\n uint256 _max_burn_amount\n ) external returns (uint256);\n\n function remove_liquidity_imbalance(\n uint256[2] memory _amounts,\n uint256 _max_burn_amount,\n address _receiver\n ) external returns (uint256);\n\n function remove_liquidity_one_coin(\n uint256 _burn_amount,\n int128 i,\n uint256 _min_received\n ) external returns (uint256);\n\n function remove_liquidity_one_coin(\n uint256 _burn_amount,\n int128 i,\n uint256 _min_received,\n address _receiver\n ) external returns (uint256);\n\n function set_ma_exp_time(uint256 _ma_exp_time) external;\n\n function stop_ramp_A() external;\n\n function symbol() external view returns (string memory);\n\n function totalSupply() external view returns (uint256);\n\n function transfer(address _to, uint256 _value) external returns (bool);\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) external returns (bool);\n\n function version() external view returns (string memory);\n\n function withdraw_admin_fees() external;\n}\n" + }, + "contracts/strategies/ICurveGauge.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface ICurveGauge {\n function balanceOf(address account) external view returns (uint256);\n\n function deposit(uint256 value, address account) external;\n\n function withdraw(uint256 value) external;\n}\n" + }, + "contracts/strategies/ICurveMetaPool.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\ninterface ICurveMetaPool {\n function add_liquidity(uint256[2] calldata amounts, uint256 min_mint_amount)\n external\n returns (uint256);\n\n function get_virtual_price() external view returns (uint256);\n\n function remove_liquidity(uint256 _amount, uint256[2] calldata min_amounts)\n external\n returns (uint256[2] calldata);\n\n function remove_liquidity_one_coin(\n uint256 _token_amount,\n int128 i,\n uint256 min_amount\n ) external returns (uint256);\n\n function remove_liquidity_imbalance(\n uint256[2] calldata amounts,\n uint256 max_burn_amount\n ) external returns (uint256);\n\n function calc_withdraw_one_coin(uint256 _token_amount, int128 i)\n external\n view\n returns (uint256);\n\n function balances(uint256 i) external view returns (uint256);\n\n function calc_token_amount(uint256[2] calldata amounts, bool deposit)\n external\n view\n returns (uint256);\n\n function base_pool() external view returns (address);\n\n function fee() external view returns (uint256);\n\n function coins(uint256 i) external view returns (address);\n\n function exchange(\n int128 i,\n int128 j,\n uint256 dx,\n uint256 min_dy\n ) external returns (uint256);\n\n function get_dy(\n int128 i,\n int128 j,\n uint256 dx\n ) external view returns (uint256);\n}\n" + }, + "contracts/strategies/ICurvePool.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface ICurvePool {\n function get_virtual_price() external view returns (uint256);\n\n function add_liquidity(uint256[3] calldata _amounts, uint256 _min) external;\n\n function balances(uint256) external view returns (uint256);\n\n function calc_token_amount(uint256[3] calldata _amounts, bool _deposit)\n external\n returns (uint256);\n\n function fee() external view returns (uint256);\n\n function remove_liquidity_one_coin(\n uint256 _amount,\n int128 _index,\n uint256 _minAmount\n ) external;\n\n function remove_liquidity(\n uint256 _amount,\n uint256[3] calldata _minWithdrawAmounts\n ) external;\n\n function calc_withdraw_one_coin(uint256 _amount, int128 _index)\n external\n view\n returns (uint256);\n\n function exchange(\n uint256 i,\n uint256 j,\n uint256 dx,\n uint256 min_dy\n ) external returns (uint256);\n\n function coins(uint256 _index) external view returns (address);\n\n function remove_liquidity_imbalance(\n uint256[3] calldata _amounts,\n uint256 maxBurnAmount\n ) external;\n}\n" + }, + "contracts/strategies/IRewardStaking.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IRewardStaking {\n function stakeFor(address, uint256) external;\n\n function stake(uint256) external;\n\n function withdraw(uint256 amount, bool claim) external;\n\n function withdrawAndUnwrap(uint256 amount, bool claim) external;\n\n function earned(address account) external view returns (uint256);\n\n function getReward() external;\n\n function getReward(address _account, bool _claimExtras) external;\n\n function extraRewardsLength() external returns (uint256);\n\n function extraRewards(uint256 _pid) external returns (address);\n\n function rewardToken() external returns (address);\n\n function balanceOf(address account) external view returns (uint256);\n}\n" + }, + "contracts/strategies/LidoWithdrawalStrategy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20, InitializableAbstractStrategy } from \"../utils/InitializableAbstractStrategy.sol\";\nimport { IWETH9 } from \"../interfaces/IWETH9.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\n\ninterface IStETHWithdrawal {\n event WithdrawalRequested(\n uint256 indexed requestId,\n address indexed requestor,\n address indexed owner,\n uint256 amountOfStETH,\n uint256 amountOfShares\n );\n event WithdrawalsFinalized(\n uint256 indexed from,\n uint256 indexed to,\n uint256 amountOfETHLocked,\n uint256 sharesToBurn,\n uint256 timestamp\n );\n event WithdrawalClaimed(\n uint256 indexed requestId,\n address indexed owner,\n address indexed receiver,\n uint256 amountOfETH\n );\n\n struct WithdrawalRequestStatus {\n /// @notice stETH token amount that was locked on withdrawal queue for this request\n uint256 amountOfStETH;\n /// @notice amount of stETH shares locked on withdrawal queue for this request\n uint256 amountOfShares;\n /// @notice address that can claim or transfer this request\n address owner;\n /// @notice timestamp of when the request was created, in seconds\n uint256 timestamp;\n /// @notice true, if request is finalized\n bool isFinalized;\n /// @notice true, if request is claimed. Request is claimable if (isFinalized && !isClaimed)\n bool isClaimed;\n }\n\n function requestWithdrawals(uint256[] calldata _amounts, address _owner)\n external\n returns (uint256[] memory requestIds);\n\n function getLastCheckpointIndex() external view returns (uint256);\n\n function findCheckpointHints(\n uint256[] calldata _requestIds,\n uint256 _firstIndex,\n uint256 _lastIndex\n ) external view returns (uint256[] memory hintIds);\n\n function claimWithdrawals(\n uint256[] calldata _requestIds,\n uint256[] calldata _hints\n ) external;\n\n function getWithdrawalStatus(uint256[] calldata _requestIds)\n external\n view\n returns (WithdrawalRequestStatus[] memory statuses);\n\n function getWithdrawalRequests(address _owner)\n external\n view\n returns (uint256[] memory requestsIds);\n\n function finalize(\n uint256 _lastRequestIdToBeFinalized,\n uint256 _maxShareRate\n ) external payable;\n}\n\n/**\n * @title Lido Withdrawal Strategy\n * @notice This strategy withdraws ETH from stETH via the Lido Withdrawal Queue contract\n * @author Origin Protocol Inc\n */\ncontract LidoWithdrawalStrategy is InitializableAbstractStrategy {\n /// @notice Address of the WETH token\n IWETH9 private constant weth =\n IWETH9(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);\n /// @notice Address of the stETH token\n IERC20 private constant stETH =\n IERC20(0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84);\n /// @notice Address of the Lido Withdrawal Queue contract\n IStETHWithdrawal private constant withdrawalQueue =\n IStETHWithdrawal(0x889edC2eDab5f40e902b864aD4d7AdE8E412F9B1);\n /// @notice Maximum amount of stETH that can be withdrawn in a single request\n uint256 public constant MaxWithdrawalAmount = 1000 ether;\n /// @notice Total amount of stETH that has been requested to be withdrawn for ETH\n uint256 public outstandingWithdrawals;\n\n event WithdrawalRequests(uint256[] requestIds, uint256[] amounts);\n event WithdrawalClaims(uint256[] requestIds, uint256 amount);\n\n constructor(BaseStrategyConfig memory _stratConfig)\n InitializableAbstractStrategy(_stratConfig)\n {}\n\n /**\n * @notice initialize function, to set up initial internal state\n * @param _rewardTokenAddresses Address of reward token for platform\n * @param _assets Addresses of initial supported assets\n * @param _pTokens Platform Token corresponding addresses\n */\n function initialize(\n address[] memory _rewardTokenAddresses,\n address[] memory _assets,\n address[] memory _pTokens\n ) external onlyGovernor initializer {\n InitializableAbstractStrategy._initialize(\n _rewardTokenAddresses,\n _assets,\n _pTokens\n );\n safeApproveAllTokens();\n }\n\n /**\n * @notice deposit() function not used for this strategy. Use depositAll() instead.\n */\n function deposit(address, uint256) public override onlyVault nonReentrant {\n // This method no longer used by the VaultAdmin, and we don't want it\n // to be used by VaultCore.\n require(false, \"use depositAll() instead\");\n }\n\n /**\n * @notice Takes all given stETH and creates Lido withdrawal request\n */\n function depositAll() external override onlyVault nonReentrant {\n uint256 stETHStart = stETH.balanceOf(address(this));\n require(stETHStart > 0, \"No stETH to withdraw\");\n\n uint256 withdrawalLength = (stETHStart / MaxWithdrawalAmount) + 1;\n uint256[] memory amounts = new uint256[](withdrawalLength);\n\n uint256 stETHRemaining = stETHStart;\n uint256 i = 0;\n while (stETHRemaining > MaxWithdrawalAmount) {\n amounts[i++] = MaxWithdrawalAmount;\n stETHRemaining -= MaxWithdrawalAmount;\n }\n amounts[i] = stETHRemaining;\n\n uint256[] memory requestIds = withdrawalQueue.requestWithdrawals(\n amounts,\n address(this)\n );\n\n emit WithdrawalRequests(requestIds, amounts);\n\n // Is there any stETH left except 1 wei from each request?\n // This is because stETH does not transfer all the transfer amount.\n uint256 stEthDust = stETH.balanceOf(address(this));\n require(\n stEthDust <= withdrawalLength,\n \"Not all stEth in withdraw queue\"\n );\n outstandingWithdrawals += stETHStart;\n\n // This strategy claims to support WETH, so it is possible for\n // the vault to transfer WETH to it. This returns any deposited WETH\n // to the vault so that it is not lost for balance tracking purposes.\n uint256 wethBalance = weth.balanceOf(address(this));\n if (wethBalance > 0) {\n // slither-disable-next-line unchecked-transfer\n weth.transfer(vaultAddress, wethBalance);\n }\n\n emit Deposit(address(stETH), address(withdrawalQueue), stETHStart);\n }\n\n /**\n * @notice Withdraw an asset from the underlying platform\n * @param _recipient Address to receive withdrawn assets\n * @param _asset Address of the asset to withdraw\n * @param _amount Amount of assets to withdraw\n */\n function withdraw(\n // solhint-disable-next-line no-unused-vars\n address _recipient,\n // solhint-disable-next-line no-unused-vars\n address _asset,\n // solhint-disable-next-line no-unused-vars\n uint256 _amount\n ) external override onlyVault nonReentrant {\n // Does nothing - all withdrawals need to be called manually using the\n // Strategist calling claimWithdrawals\n revert(\"use claimWithdrawals()\");\n }\n\n /**\n * @notice Claim previously requested withdrawals that have now finalized.\n * Called by the Strategist.\n * @param _requestIds Array of withdrawal request identifiers\n * @param _expectedAmount Total amount of ETH expect to be withdrawn\n */\n function claimWithdrawals(\n uint256[] memory _requestIds,\n uint256 _expectedAmount\n ) external nonReentrant {\n require(\n msg.sender == IVault(vaultAddress).strategistAddr(),\n \"Caller is not the Strategist\"\n );\n uint256 startingBalance = payable(address(this)).balance;\n uint256 lastIndex = withdrawalQueue.getLastCheckpointIndex();\n uint256[] memory hintIds = withdrawalQueue.findCheckpointHints(\n _requestIds,\n 1,\n lastIndex\n );\n withdrawalQueue.claimWithdrawals(_requestIds, hintIds);\n\n uint256 currentBalance = payable(address(this)).balance;\n uint256 withdrawalAmount = currentBalance - startingBalance;\n // Withdrawal amount should be within 2 wei of expected amount\n require(\n withdrawalAmount + 2 >= _expectedAmount &&\n withdrawalAmount <= _expectedAmount,\n \"Withdrawal amount not expected\"\n );\n\n emit WithdrawalClaims(_requestIds, withdrawalAmount);\n\n outstandingWithdrawals -= withdrawalAmount;\n weth.deposit{ value: currentBalance }();\n // slither-disable-next-line unchecked-transfer\n weth.transfer(vaultAddress, currentBalance);\n emit Withdrawal(\n address(weth),\n address(withdrawalQueue),\n currentBalance\n );\n }\n\n /**\n * @notice Withdraw all assets from this strategy, and transfer to the Vault.\n * In correct operation, this strategy should never hold any assets.\n */\n function withdrawAll() external override onlyVaultOrGovernor nonReentrant {\n if (payable(address(this)).balance > 0) {\n weth.deposit{ value: payable(address(this)).balance }();\n }\n uint256 wethBalance = weth.balanceOf(address(this));\n if (wethBalance > 0) {\n // slither-disable-next-line unchecked-transfer\n weth.transfer(vaultAddress, wethBalance);\n emit Withdrawal(address(weth), address(0), wethBalance);\n }\n uint256 stEthBalance = stETH.balanceOf(address(this));\n if (stEthBalance > 0) {\n // slither-disable-next-line unchecked-transfer\n stETH.transfer(vaultAddress, stEthBalance);\n emit Withdrawal(address(stETH), address(0), stEthBalance);\n }\n }\n\n /**\n * @notice Returns the amount of queued stETH that will be returned as WETH.\n * We return this as a WETH asset, since that is what it will eventually be returned as.\n * We only return the outstandingWithdrawals, because the contract itself should never hold any funds.\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n external\n view\n override\n returns (uint256 balance)\n {\n if (_asset == address(weth)) {\n return outstandingWithdrawals;\n } else if (_asset == address(stETH)) {\n return 0;\n } else {\n revert(\"Unexpected asset address\");\n }\n }\n\n /**\n * @notice Approve the spending of all assets by their corresponding cToken,\n * if for some reason is it necessary.\n */\n function safeApproveAllTokens() public override {\n // slither-disable-next-line unused-return\n stETH.approve(address(withdrawalQueue), type(uint256).max);\n }\n\n /**\n * @notice Check if an asset is supported.\n * @param _asset Address of the asset\n * @return bool Whether asset is supported\n */\n function supportsAsset(address _asset) public pure override returns (bool) {\n // stETH can be deposited by the vault and balances are reported in WETH\n return _asset == address(stETH) || _asset == address(weth);\n }\n\n /// @notice Needed to receive ETH when withdrawal requests are claimed\n receive() external payable {}\n\n function _abstractSetPToken(address, address) internal pure override {\n revert(\"No pTokens are used\");\n }\n}\n" + }, + "contracts/strategies/MorphoAaveStrategy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title OUSD Morpho Aave Strategy\n * @notice Investment strategy for investing stablecoins via Morpho (Aave)\n * @author Origin Protocol Inc\n */\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20, InitializableAbstractStrategy } from \"../utils/InitializableAbstractStrategy.sol\";\nimport { IMorpho } from \"../interfaces/morpho/IMorpho.sol\";\nimport { ILens } from \"../interfaces/morpho/ILens.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\n\ncontract MorphoAaveStrategy is InitializableAbstractStrategy {\n address public constant MORPHO = 0x777777c9898D384F785Ee44Acfe945efDFf5f3E0;\n address public constant LENS = 0x507fA343d0A90786d86C7cd885f5C49263A91FF4;\n\n using SafeERC20 for IERC20;\n using StableMath for uint256;\n\n constructor(BaseStrategyConfig memory _stratConfig)\n InitializableAbstractStrategy(_stratConfig)\n {}\n\n /**\n * @dev Initialize function, to set up initial internal state\n * @param _rewardTokenAddresses Address of reward token for platform\n * @param _assets Addresses of initial supported assets\n * @param _pTokens Platform Token corresponding addresses\n */\n function initialize(\n address[] calldata _rewardTokenAddresses,\n address[] calldata _assets,\n address[] calldata _pTokens\n ) external onlyGovernor initializer {\n InitializableAbstractStrategy._initialize(\n _rewardTokenAddresses,\n _assets,\n _pTokens\n );\n }\n\n /**\n * @dev Approve the spending of all assets by main Morpho contract,\n * if for some reason is it necessary.\n */\n function safeApproveAllTokens()\n external\n override\n onlyGovernor\n nonReentrant\n {\n uint256 assetCount = assetsMapped.length;\n for (uint256 i = 0; i < assetCount; i++) {\n address asset = assetsMapped[i];\n\n // Safe approval\n IERC20(asset).safeApprove(MORPHO, 0);\n IERC20(asset).safeApprove(MORPHO, type(uint256).max);\n }\n }\n\n /**\n * @dev Internal method to respond to the addition of new asset\n * We need to approve and allow Morpho to move them\n * @param _asset Address of the asset to approve\n * @param _pToken The pToken for the approval\n */\n // solhint-disable-next-line no-unused-vars\n function _abstractSetPToken(address _asset, address _pToken)\n internal\n override\n {\n IERC20(_asset).safeApprove(MORPHO, 0);\n IERC20(_asset).safeApprove(MORPHO, type(uint256).max);\n }\n\n /**\n * @dev Collect accumulated rewards and send them to Harvester.\n */\n function collectRewardTokens()\n external\n override\n onlyHarvester\n nonReentrant\n {\n // Morpho Aave-v2 doesn't distribute reward tokens\n // solhint-disable-next-line max-line-length\n // Ref: https://developers.morpho.xyz/interact-with-morpho/get-started/interact-with-morpho/claim-rewards#morpho-aave-v2\n }\n\n /**\n * @dev Get the amount of rewards pending to be collected from the protocol\n */\n function getPendingRewards() external view returns (uint256 balance) {\n // Morpho Aave-v2 doesn't distribute reward tokens\n // solhint-disable-next-line max-line-length\n // Ref: https://developers.morpho.xyz/interact-with-morpho/get-started/interact-with-morpho/claim-rewards#morpho-aave-v2\n return 0;\n }\n\n /**\n * @dev Deposit asset into Morpho\n * @param _asset Address of asset to deposit\n * @param _amount Amount of asset to deposit\n */\n function deposit(address _asset, uint256 _amount)\n external\n override\n onlyVault\n nonReentrant\n {\n _deposit(_asset, _amount);\n }\n\n /**\n * @dev Deposit asset into Morpho\n * @param _asset Address of asset to deposit\n * @param _amount Amount of asset to deposit\n */\n function _deposit(address _asset, uint256 _amount) internal {\n require(_amount > 0, \"Must deposit something\");\n\n address pToken = address(_getPTokenFor(_asset));\n\n IMorpho(MORPHO).supply(\n pToken,\n address(this), // the address of the user you want to supply on behalf of\n _amount\n );\n emit Deposit(_asset, pToken, _amount);\n }\n\n /**\n * @dev Deposit the entire balance of any supported asset into Morpho\n */\n function depositAll() external override onlyVault nonReentrant {\n for (uint256 i = 0; i < assetsMapped.length; i++) {\n uint256 balance = IERC20(assetsMapped[i]).balanceOf(address(this));\n if (balance > 0) {\n _deposit(assetsMapped[i], balance);\n }\n }\n }\n\n /**\n * @dev Withdraw asset from Morpho\n * @param _recipient Address to receive withdrawn asset\n * @param _asset Address of asset to withdraw\n * @param _amount Amount of asset to withdraw\n */\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external override onlyVault nonReentrant {\n _withdraw(_recipient, _asset, _amount);\n }\n\n function _withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) internal {\n require(_amount > 0, \"Must withdraw something\");\n require(_recipient != address(0), \"Must specify recipient\");\n\n address pToken = address(_getPTokenFor(_asset));\n\n IMorpho(MORPHO).withdraw(pToken, _amount);\n emit Withdrawal(_asset, pToken, _amount);\n IERC20(_asset).safeTransfer(_recipient, _amount);\n }\n\n /**\n * @dev Remove all assets from platform and send them to Vault contract.\n */\n function withdrawAll() external override onlyVaultOrGovernor nonReentrant {\n for (uint256 i = 0; i < assetsMapped.length; i++) {\n uint256 balance = _checkBalance(assetsMapped[i]);\n if (balance > 0) {\n _withdraw(vaultAddress, assetsMapped[i], balance);\n }\n }\n }\n\n /**\n * @dev Return total value of an asset held in the platform\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n external\n view\n override\n returns (uint256 balance)\n {\n return _checkBalance(_asset);\n }\n\n function _checkBalance(address _asset)\n internal\n view\n returns (uint256 balance)\n {\n address pToken = address(_getPTokenFor(_asset));\n\n // Total value represented by decimal position of underlying token\n (, , balance) = ILens(LENS).getCurrentSupplyBalanceInOf(\n pToken,\n address(this)\n );\n }\n\n /**\n * @dev Retuns bool indicating whether asset is supported by strategy\n * @param _asset Address of the asset\n */\n function supportsAsset(address _asset) public view override returns (bool) {\n return assetToPToken[_asset] != address(0);\n }\n\n /**\n * @dev Get the pToken wrapped in the IERC20 interface for this asset.\n * Fails if the pToken doesn't exist in our mappings.\n * @param _asset Address of the asset\n * @return pToken Corresponding pToken to this asset\n */\n function _getPTokenFor(address _asset) internal view returns (IERC20) {\n address pToken = assetToPToken[_asset];\n require(pToken != address(0), \"pToken does not exist\");\n return IERC20(pToken);\n }\n}\n" + }, + "contracts/strategies/MorphoCompoundStrategy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title OUSD Morpho Compound Strategy\n * @notice Investment strategy for investing stablecoins via Morpho (Compound)\n * @author Origin Protocol Inc\n */\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20, BaseCompoundStrategy, InitializableAbstractStrategy } from \"./BaseCompoundStrategy.sol\";\nimport { IMorpho } from \"../interfaces/morpho/IMorpho.sol\";\nimport { ILens } from \"../interfaces/morpho/ILens.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport \"../utils/Helpers.sol\";\n\ncontract MorphoCompoundStrategy is BaseCompoundStrategy {\n address public constant MORPHO = 0x8888882f8f843896699869179fB6E4f7e3B58888;\n address public constant LENS = 0x930f1b46e1D081Ec1524efD95752bE3eCe51EF67;\n using SafeERC20 for IERC20;\n using StableMath for uint256;\n\n constructor(BaseStrategyConfig memory _stratConfig)\n InitializableAbstractStrategy(_stratConfig)\n {}\n\n /**\n * @dev Initialize function, to set up initial internal state\n * @param _rewardTokenAddresses Address of reward token for platform\n * @param _assets Addresses of initial supported assets\n * @param _pTokens Platform Token corresponding addresses\n */\n function initialize(\n address[] calldata _rewardTokenAddresses,\n address[] calldata _assets,\n address[] calldata _pTokens\n ) external onlyGovernor initializer {\n InitializableAbstractStrategy._initialize(\n _rewardTokenAddresses,\n _assets,\n _pTokens\n );\n }\n\n /**\n * @dev Approve the spending of all assets by main Morpho contract,\n * if for some reason is it necessary.\n */\n function safeApproveAllTokens()\n external\n override\n onlyGovernor\n nonReentrant\n {\n uint256 assetCount = assetsMapped.length;\n for (uint256 i = 0; i < assetCount; i++) {\n address asset = assetsMapped[i];\n\n // Safe approval\n IERC20(asset).safeApprove(MORPHO, 0);\n IERC20(asset).safeApprove(MORPHO, type(uint256).max);\n }\n }\n\n /**\n * @dev Internal method to respond to the addition of new asset\n * We need to approve and allow Morpho to move them\n * @param _asset Address of the asset to approve\n * @param _pToken The pToken for the approval\n */\n // solhint-disable-next-line no-unused-vars\n function _abstractSetPToken(address _asset, address _pToken)\n internal\n override\n {\n IERC20(_asset).safeApprove(MORPHO, 0);\n IERC20(_asset).safeApprove(MORPHO, type(uint256).max);\n }\n\n /**\n * @dev Collect accumulated rewards and send them to Harvester.\n */\n function collectRewardTokens()\n external\n override\n onlyHarvester\n nonReentrant\n {\n /**\n * Gas considerations. We could query Morpho LENS's `getUserUnclaimedRewards` for each\n * cToken separately and only claimRewards where it is economically feasible. Each call\n * (out of 3) costs ~60k gas extra.\n *\n * Each extra cToken in the `poolTokens` of `claimRewards` function makes that call\n * 89-120k more expensive gas wise.\n *\n * With Lens query in case where:\n * - there is only 1 reward token to collect. Net gas usage in best case would be\n * 3*60 - 2*120 = -60k -> saving 60k gas\n * - there are 2 reward tokens to collect. Net gas usage in best case would be\n * 3*60 - 120 = 60k -> more expensive for 60k gas\n * - there are 3 reward tokens to collect. Net gas usage in best case would be\n * 3*60 = 180k -> more expensive for 180k gas\n *\n * For the above reasoning such \"optimization\" is not implemented\n */\n\n address[] memory poolTokens = new address[](assetsMapped.length);\n for (uint256 i = 0; i < assetsMapped.length; i++) {\n poolTokens[i] = assetToPToken[assetsMapped[i]];\n }\n\n // slither-disable-next-line unused-return\n IMorpho(MORPHO).claimRewards(\n poolTokens, // The addresses of the underlying protocol's pools to claim rewards from\n false // Whether to trade the accrued rewards for MORPHO token, with a premium\n );\n\n // Transfer COMP to Harvester\n IERC20 rewardToken = IERC20(rewardTokenAddresses[0]);\n uint256 balance = rewardToken.balanceOf(address(this));\n emit RewardTokenCollected(\n harvesterAddress,\n rewardTokenAddresses[0],\n balance\n );\n rewardToken.safeTransfer(harvesterAddress, balance);\n }\n\n /**\n * @dev Get the amount of rewards pending to be collected from the protocol\n */\n function getPendingRewards() external view returns (uint256 balance) {\n address[] memory poolTokens = new address[](assetsMapped.length);\n for (uint256 i = 0; i < assetsMapped.length; i++) {\n poolTokens[i] = assetToPToken[assetsMapped[i]];\n }\n\n return ILens(LENS).getUserUnclaimedRewards(poolTokens, address(this));\n }\n\n /**\n * @dev Deposit asset into Morpho\n * @param _asset Address of asset to deposit\n * @param _amount Amount of asset to deposit\n */\n function deposit(address _asset, uint256 _amount)\n external\n override\n onlyVault\n nonReentrant\n {\n _deposit(_asset, _amount);\n }\n\n /**\n * @dev Deposit asset into Morpho\n * @param _asset Address of asset to deposit\n * @param _amount Amount of asset to deposit\n */\n function _deposit(address _asset, uint256 _amount) internal {\n require(_amount > 0, \"Must deposit something\");\n\n IMorpho(MORPHO).supply(\n address(_getCTokenFor(_asset)),\n address(this), // the address of the user you want to supply on behalf of\n _amount\n );\n emit Deposit(_asset, address(_getCTokenFor(_asset)), _amount);\n }\n\n /**\n * @dev Deposit the entire balance of any supported asset into Morpho\n */\n function depositAll() external override onlyVault nonReentrant {\n for (uint256 i = 0; i < assetsMapped.length; i++) {\n uint256 balance = IERC20(assetsMapped[i]).balanceOf(address(this));\n if (balance > 0) {\n _deposit(assetsMapped[i], balance);\n }\n }\n }\n\n /**\n * @dev Withdraw asset from Morpho\n * @param _recipient Address to receive withdrawn asset\n * @param _asset Address of asset to withdraw\n * @param _amount Amount of asset to withdraw\n */\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external override onlyVault nonReentrant {\n _withdraw(_recipient, _asset, _amount);\n }\n\n function _withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) internal {\n require(_amount > 0, \"Must withdraw something\");\n require(_recipient != address(0), \"Must specify recipient\");\n\n address pToken = assetToPToken[_asset];\n\n IMorpho(MORPHO).withdraw(pToken, _amount);\n emit Withdrawal(_asset, address(_getCTokenFor(_asset)), _amount);\n IERC20(_asset).safeTransfer(_recipient, _amount);\n }\n\n /**\n * @dev Remove all assets from platform and send them to Vault contract.\n */\n function withdrawAll() external override onlyVaultOrGovernor nonReentrant {\n for (uint256 i = 0; i < assetsMapped.length; i++) {\n uint256 balance = _checkBalance(assetsMapped[i]);\n if (balance > 0) {\n _withdraw(vaultAddress, assetsMapped[i], balance);\n }\n }\n }\n\n /**\n * @dev Return total value of an asset held in the platform\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n external\n view\n override\n returns (uint256 balance)\n {\n return _checkBalance(_asset);\n }\n\n function _checkBalance(address _asset)\n internal\n view\n returns (uint256 balance)\n {\n address pToken = assetToPToken[_asset];\n\n // Total value represented by decimal position of underlying token\n (, , balance) = ILens(LENS).getCurrentSupplyBalanceInOf(\n pToken,\n address(this)\n );\n }\n}\n" + }, + "contracts/strategies/NativeStaking/FeeAccumulator.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { Address } from \"@openzeppelin/contracts/utils/Address.sol\";\n\n/**\n * @title Fee Accumulator for Native Staking SSV Strategy\n * @notice Receives execution rewards which includes tx fees and\n * MEV rewards like tx priority and tx ordering.\n * It does NOT include swept ETH from beacon chain consensus rewards or full validator withdrawals.\n * @author Origin Protocol Inc\n */\ncontract FeeAccumulator {\n /// @notice The address of the Native Staking Strategy\n address public immutable STRATEGY;\n\n event ExecutionRewardsCollected(address indexed strategy, uint256 amount);\n\n /**\n * @param _strategy Address of the Native Staking Strategy\n */\n constructor(address _strategy) {\n STRATEGY = _strategy;\n }\n\n /**\n * @notice sends all ETH in this FeeAccumulator contract to the Native Staking Strategy.\n * @return eth The amount of execution rewards that were sent to the Native Staking Strategy\n */\n function collect() external returns (uint256 eth) {\n require(msg.sender == STRATEGY, \"Caller is not the Strategy\");\n\n eth = address(this).balance;\n if (eth > 0) {\n // Send the ETH to the Native Staking Strategy\n Address.sendValue(payable(STRATEGY), eth);\n\n emit ExecutionRewardsCollected(STRATEGY, eth);\n }\n }\n\n /**\n * @dev Accept ETH\n */\n receive() external payable {}\n}\n" + }, + "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/utils/math/Math.sol\";\n\nimport { InitializableAbstractStrategy } from \"../../utils/InitializableAbstractStrategy.sol\";\nimport { IWETH9 } from \"../../interfaces/IWETH9.sol\";\nimport { FeeAccumulator } from \"./FeeAccumulator.sol\";\nimport { ValidatorAccountant } from \"./ValidatorAccountant.sol\";\n\nstruct ValidatorStakeData {\n bytes pubkey;\n bytes signature;\n bytes32 depositDataRoot;\n}\n\n/// @title Native Staking SSV Strategy\n/// @notice Strategy to deploy funds into DVT validators powered by the SSV Network\n/// @author Origin Protocol Inc\n/// @dev This contract handles WETH and ETH and in some operations interchanges between the two. Any WETH that\n/// is on the contract across multiple blocks (and not just transitory within a transaction) is considered an\n/// asset. Meaning deposits increase the balance of the asset and withdrawal decrease it. As opposed to all\n/// our other strategies the WETH doesn't immediately get deposited into an underlying strategy and can be present\n/// across multiple blocks waiting to be unwrapped to ETH and staked to validators. This separation of WETH and ETH is\n/// required since the rewards (reward token) is also in ETH.\n///\n/// To simplify the accounting of WETH there is another difference in behavior compared to the other strategies.\n/// To withdraw WETH asset - exit message is posted to validators and the ETH hits this contract with multiple days\n/// delay. In order to simplify the WETH accounting upon detection of such an event the ValidatorAccountant\n/// immediately wraps ETH to WETH and sends it to the Vault.\n///\n/// On the other hand any ETH on the contract (across multiple blocks) is there either:\n/// - as a result of already accounted for consensus rewards\n/// - as a result of not yet accounted for consensus rewards\n/// - as a results of not yet accounted for full validator withdrawals (or validator slashes)\n///\n/// Even though the strategy assets and rewards are a very similar asset the consensus layer rewards and the\n/// execution layer rewards are considered rewards and those are dripped to the Vault over a configurable time\n/// interval and not immediately.\ncontract NativeStakingSSVStrategy is\n ValidatorAccountant,\n InitializableAbstractStrategy\n{\n using SafeERC20 for IERC20;\n\n /// @notice SSV ERC20 token that serves as a payment for operating SSV validators\n address public immutable SSV_TOKEN;\n /// @notice Fee collector address\n /// @dev this address will receive Execution layer rewards - These are rewards earned for\n /// executing transactions on the Ethereum network as part of block proposals. They include\n /// priority fees (fees paid by users for their transactions to be included) and MEV rewards\n /// (rewards for arranging transactions in a way that benefits the validator).\n address payable public immutable FEE_ACCUMULATOR_ADDRESS;\n\n /// @dev This contract receives WETH as the deposit asset, but unlike other strategies doesn't immediately\n /// deposit it to an underlying platform. Rather a special privilege account stakes it to the validators.\n /// For that reason calling WETH.balanceOf(this) in a deposit function can contain WETH that has just been\n /// deposited and also WETH that has previously been deposited. To keep a correct count we need to keep track\n /// of WETH that has already been accounted for.\n /// This value represents the amount of WETH balance of this contract that has already been accounted for by the\n /// deposit events.\n /// It is important to note that this variable is not concerned with WETH that is a result of full/partial\n /// withdrawal of the validators. It is strictly concerned with WETH that has been deposited and is waiting to\n /// be staked.\n uint256 public depositedWethAccountedFor;\n\n // For future use\n uint256[49] private __gap;\n\n /// @param _baseConfig Base strategy config with platformAddress (ERC-4626 Vault contract), eg sfrxETH or sDAI,\n /// and vaultAddress (OToken Vault contract), eg VaultProxy or OETHVaultProxy\n /// @param _wethAddress Address of the Erc20 WETH Token contract\n /// @param _ssvToken Address of the Erc20 SSV Token contract\n /// @param _ssvNetwork Address of the SSV Network contract\n /// @param _maxValidators Maximum number of validators that can be registered in the strategy\n /// @param _feeAccumulator Address of the fee accumulator receiving execution layer validator rewards\n /// @param _beaconChainDepositContract Address of the beacon chain deposit contract\n constructor(\n BaseStrategyConfig memory _baseConfig,\n address _wethAddress,\n address _ssvToken,\n address _ssvNetwork,\n uint256 _maxValidators,\n address _feeAccumulator,\n address _beaconChainDepositContract\n )\n InitializableAbstractStrategy(_baseConfig)\n ValidatorAccountant(\n _wethAddress,\n _baseConfig.vaultAddress,\n _beaconChainDepositContract,\n _ssvNetwork,\n _maxValidators\n )\n {\n SSV_TOKEN = _ssvToken;\n FEE_ACCUMULATOR_ADDRESS = payable(_feeAccumulator);\n }\n\n /// @notice initialize function, to set up initial internal state\n /// @param _rewardTokenAddresses Address of reward token for platform\n /// @param _assets Addresses of initial supported assets\n /// @param _pTokens Platform Token corresponding addresses\n function initialize(\n address[] memory _rewardTokenAddresses,\n address[] memory _assets,\n address[] memory _pTokens\n ) external onlyGovernor initializer {\n InitializableAbstractStrategy._initialize(\n _rewardTokenAddresses,\n _assets,\n _pTokens\n );\n }\n\n /// @notice Unlike other strategies, this does not deposit assets into the underlying platform.\n /// It just checks the asset is WETH and emits the Deposit event.\n /// To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used.\n /// Will NOT revert if the strategy is paused from an accounting failure.\n /// @param _asset Address of asset to deposit. Has to be WETH.\n /// @param _amount Amount of assets that were transferred to the strategy by the vault.\n function deposit(address _asset, uint256 _amount)\n external\n override\n onlyVault\n nonReentrant\n {\n require(_asset == WETH, \"Unsupported asset\");\n depositedWethAccountedFor += _amount;\n _deposit(_asset, _amount);\n }\n\n /// @dev Deposit WETH to this strategy so it can later be staked into a validator.\n /// @param _asset Address of WETH\n /// @param _amount Amount of WETH to deposit\n function _deposit(address _asset, uint256 _amount) internal {\n require(_amount > 0, \"Must deposit something\");\n /*\n * We could do a check here that would revert when \"_amount % 32 ether != 0\". With the idea of\n * not allowing deposits that will result in WETH sitting on the strategy after all the possible batches\n * of 32ETH have been staked.\n * But someone could mess with our strategy by sending some WETH to it. And we might want to deposit just\n * enough WETH to add it up to 32 so it can be staked. For that reason the check is left out.\n *\n * WETH sitting on the strategy won't interfere with the accounting since accounting only operates on ETH.\n */\n emit Deposit(_asset, address(0), _amount);\n }\n\n /// @notice Unlike other strategies, this does not deposit assets into the underlying platform.\n /// It just emits the Deposit event.\n /// To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used.\n /// Will NOT revert if the strategy is paused from an accounting failure.\n function depositAll() external override onlyVault nonReentrant {\n uint256 wethBalance = IERC20(WETH).balanceOf(address(this));\n uint256 newWeth = wethBalance - depositedWethAccountedFor;\n\n if (newWeth > 0) {\n depositedWethAccountedFor = wethBalance;\n\n _deposit(WETH, newWeth);\n }\n }\n\n /// @notice Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract.\n /// That can happen when:\n /// - after mints if the strategy is the default\n /// - time between depositToStrategy and stakeEth\n /// - the deposit was not a multiple of 32 WETH\n /// - someone sent WETH directly to this contract\n /// Will NOT revert if the strategy is paused from an accounting failure.\n /// @param _recipient Address to receive withdrawn assets\n /// @param _asset WETH to withdraw\n /// @param _amount Amount of WETH to withdraw\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external override onlyVault nonReentrant {\n require(_asset == WETH, \"Unsupported asset\");\n _withdraw(_recipient, _asset, _amount);\n }\n\n function _withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) internal {\n require(_amount > 0, \"Must withdraw something\");\n require(_recipient != address(0), \"Must specify recipient\");\n\n _wethWithdrawn(_amount);\n\n IERC20(_asset).safeTransfer(_recipient, _amount);\n emit Withdrawal(_asset, address(0), _amount);\n }\n\n /// @notice transfer all WETH deposits back to the vault.\n /// This does not withdraw from the validators. That has to be done separately with the\n /// `exitSsvValidator` and `removeSsvValidator` operations.\n /// This does not withdraw any execution rewards from the FeeAccumulator or\n /// consensus rewards in this strategy.\n /// Any ETH in this strategy that was swept from a full validator withdrawal will not be withdrawn.\n /// ETH from full validator withdrawals is sent to the Vault using `doAccounting`.\n /// Will NOT revert if the strategy is paused from an accounting failure.\n function withdrawAll() external override onlyVaultOrGovernor nonReentrant {\n uint256 wethBalance = IERC20(WETH).balanceOf(address(this));\n if (wethBalance > 0) {\n _withdraw(vaultAddress, WETH, wethBalance);\n }\n }\n\n /// @notice Returns the total value of (W)ETH that is staked to the validators\n /// and WETH deposits that are still to be staked.\n /// This does not include ETH from consensus rewards sitting in this strategy\n /// or ETH from MEV rewards in the FeeAccumulator. These rewards are harvested\n /// and sent to the Dripper so will eventually be sent to the Vault as WETH.\n /// @param _asset Address of weth asset\n /// @return balance Total value of (W)ETH\n function checkBalance(address _asset)\n external\n view\n override\n returns (uint256 balance)\n {\n require(_asset == WETH, \"Unsupported asset\");\n\n balance =\n // add the ETH that has been staked in validators\n activeDepositedValidators *\n FULL_STAKE +\n // add the WETH in the strategy from deposits that are still to be staked\n IERC20(WETH).balanceOf(address(this));\n }\n\n function pause() external onlyStrategist {\n _pause();\n }\n\n /// @notice Returns bool indicating whether asset is supported by strategy.\n /// @param _asset The address of the asset token.\n function supportsAsset(address _asset) public view override returns (bool) {\n return _asset == WETH;\n }\n\n /// @notice Approves the SSV Network contract to transfer SSV tokens for deposits\n function safeApproveAllTokens() external override {\n /// @dev Approves the SSV Network contract to transfer SSV tokens for deposits\n IERC20(SSV_TOKEN).approve(SSV_NETWORK, type(uint256).max);\n }\n\n /**\n * @notice Only accept ETH from the FeeAccumulator and the WETH contract - required when\n * unwrapping WETH just before staking it to the validator\n * @dev don't want to receive donations from anyone else as this will\n * mess with the accounting of the consensus rewards and validator full withdrawals\n */\n receive() external payable {\n require(\n msg.sender == FEE_ACCUMULATOR_ADDRESS || msg.sender == WETH,\n \"Eth not from allowed contracts\"\n );\n }\n\n /***************************************\n Internal functions\n ****************************************/\n\n function _abstractSetPToken(address _asset, address) internal override {}\n\n /// @dev Convert accumulated ETH to WETH and send to the Harvester.\n /// Will revert if the strategy is paused for accounting.\n function _collectRewardTokens() internal override whenNotPaused {\n // collect ETH from execution rewards from the fee accumulator\n uint256 executionRewards = FeeAccumulator(FEE_ACCUMULATOR_ADDRESS)\n .collect();\n\n // total ETH rewards to be harvested = execution rewards + consensus rewards\n uint256 ethRewards = executionRewards + consensusRewards;\n\n require(\n address(this).balance >= ethRewards,\n \"Insufficient eth balance\"\n );\n\n if (ethRewards > 0) {\n // reset the counter keeping track of beacon chain consensus rewards\n consensusRewards = 0;\n\n // Convert ETH rewards to WETH\n IWETH9(WETH).deposit{ value: ethRewards }();\n\n IERC20(WETH).safeTransfer(harvesterAddress, ethRewards);\n emit RewardTokenCollected(harvesterAddress, WETH, ethRewards);\n }\n }\n\n /// @dev emits Withdrawal event from NativeStakingSSVStrategy\n function _wethWithdrawnToVault(uint256 _amount) internal override {\n emit Withdrawal(WETH, address(0), _amount);\n }\n\n /// @dev Called when WETH is withdrawn from the strategy or staked to a validator so\n /// the strategy knows how much WETH it has on deposit.\n /// This is so it can emit the correct amount in the Deposit event in depositAll().\n function _wethWithdrawn(uint256 _amount) internal override {\n /* In an ideal world we wouldn't need to reduce the deduction amount when the\n * depositedWethAccountedFor is smaller than the _amount.\n *\n * The reason this is required is that a malicious actor could sent WETH directly\n * to this contract and that would circumvent the increase of depositedWethAccountedFor\n * property. When the ETH would be staked the depositedWethAccountedFor amount could\n * be deducted so much that it would be negative.\n */\n uint256 deductAmount = Math.min(_amount, depositedWethAccountedFor);\n depositedWethAccountedFor -= deductAmount;\n }\n}\n" + }, + "contracts/strategies/NativeStaking/ValidatorAccountant.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { ValidatorRegistrator } from \"./ValidatorRegistrator.sol\";\nimport { IWETH9 } from \"../../interfaces/IWETH9.sol\";\n\n/// @title Validator Accountant\n/// @notice Attributes the ETH swept from beacon chain validators to this strategy contract\n/// as either full or partial withdrawals. Partial withdrawals being consensus rewards.\n/// Full withdrawals are from exited validators.\n/// @author Origin Protocol Inc\nabstract contract ValidatorAccountant is ValidatorRegistrator {\n /// @notice The minimum amount of blocks that need to pass between two calls to manuallyFixAccounting\n uint256 public constant MIN_FIX_ACCOUNTING_CADENCE = 7200; // 1 day\n\n /// @notice Keeps track of the total consensus rewards swept from the beacon chain\n uint256 public consensusRewards;\n\n /// @notice start of fuse interval\n uint256 public fuseIntervalStart;\n /// @notice end of fuse interval\n uint256 public fuseIntervalEnd;\n /// @notice last block number manuallyFixAccounting has been called\n uint256 public lastFixAccountingBlockNumber;\n\n uint256[49] private __gap;\n\n event FuseIntervalUpdated(uint256 start, uint256 end);\n event AccountingFullyWithdrawnValidator(\n uint256 noOfValidators,\n uint256 remainingValidators,\n uint256 wethSentToVault\n );\n event AccountingValidatorSlashed(\n uint256 remainingValidators,\n uint256 wethSentToVault\n );\n event AccountingConsensusRewards(uint256 amount);\n\n event AccountingManuallyFixed(\n int256 validatorsDelta,\n int256 consensusRewardsDelta,\n uint256 wethToVault\n );\n\n /// @param _wethAddress Address of the Erc20 WETH Token contract\n /// @param _vaultAddress Address of the Vault\n /// @param _beaconChainDepositContract Address of the beacon chain deposit contract\n /// @param _ssvNetwork Address of the SSV Network contract\n /// @param _maxValidators Maximum number of validators that can be registered in the strategy\n constructor(\n address _wethAddress,\n address _vaultAddress,\n address _beaconChainDepositContract,\n address _ssvNetwork,\n uint256 _maxValidators\n )\n ValidatorRegistrator(\n _wethAddress,\n _vaultAddress,\n _beaconChainDepositContract,\n _ssvNetwork,\n _maxValidators\n )\n {}\n\n /// @notice set fuse interval values\n function setFuseInterval(\n uint256 _fuseIntervalStart,\n uint256 _fuseIntervalEnd\n ) external onlyGovernor {\n require(\n _fuseIntervalStart < _fuseIntervalEnd &&\n _fuseIntervalEnd < 32 ether &&\n _fuseIntervalEnd - _fuseIntervalStart >= 4 ether,\n \"Incorrect fuse interval\"\n );\n\n fuseIntervalStart = _fuseIntervalStart;\n fuseIntervalEnd = _fuseIntervalEnd;\n\n emit FuseIntervalUpdated(_fuseIntervalStart, _fuseIntervalEnd);\n }\n\n /* solhint-disable max-line-length */\n /// This notion page offers a good explanation of how the accounting functions\n /// https://www.notion.so/originprotocol/Limited-simplified-native-staking-accounting-67a217c8420d40678eb943b9da0ee77d\n /// In short, after dividing by 32, if the ETH remaining on the contract falls between 0 and fuseIntervalStart,\n /// the accounting function will treat that ETH as Beacon chain consensus rewards.\n /// On the contrary, if after dividing by 32, the ETH remaining on the contract falls between fuseIntervalEnd and 32,\n /// the accounting function will treat that as a validator slashing.\n /// @notice Perform the accounting attributing beacon chain ETH to either full or partial withdrawals. Returns true when\n /// accounting is valid and fuse isn't \"blown\". Returns false when fuse is blown.\n /// @dev This function could in theory be permission-less but lets allow only the Registrator (Defender Action) to call it\n /// for now.\n /// @return accountingValid true if accounting was successful, false if fuse is blown\n /* solhint-enable max-line-length */\n function doAccounting()\n external\n onlyRegistrator\n whenNotPaused\n nonReentrant\n returns (bool accountingValid)\n {\n // pause the accounting on failure\n accountingValid = _doAccounting(true);\n }\n\n // slither-disable-start reentrancy-eth\n function _doAccounting(bool pauseOnFail)\n internal\n returns (bool accountingValid)\n {\n if (address(this).balance < consensusRewards) {\n return _failAccounting(pauseOnFail);\n }\n\n // Calculate all the new ETH that has been swept to the contract since the last accounting\n uint256 newSweptETH = address(this).balance - consensusRewards;\n accountingValid = true;\n\n // send the ETH that is from fully withdrawn validators to the Vault\n if (newSweptETH >= FULL_STAKE) {\n uint256 fullyWithdrawnValidators;\n // explicitly cast to uint256 as we want to round to a whole number of validators\n fullyWithdrawnValidators = uint256(newSweptETH / FULL_STAKE);\n activeDepositedValidators -= fullyWithdrawnValidators;\n\n uint256 wethToVault = FULL_STAKE * fullyWithdrawnValidators;\n IWETH9(WETH).deposit{ value: wethToVault }();\n // slither-disable-next-line unchecked-transfer\n IWETH9(WETH).transfer(VAULT_ADDRESS, wethToVault);\n _wethWithdrawnToVault(wethToVault);\n\n emit AccountingFullyWithdrawnValidator(\n fullyWithdrawnValidators,\n activeDepositedValidators,\n wethToVault\n );\n }\n\n uint256 ethRemaining = address(this).balance - consensusRewards;\n // should be less than a whole validator stake\n require(ethRemaining < FULL_STAKE, \"Unexpected accounting\");\n\n // If no Beacon chain consensus rewards swept\n if (ethRemaining == 0) {\n // do nothing\n return accountingValid;\n } else if (ethRemaining < fuseIntervalStart) {\n // Beacon chain consensus rewards swept (partial validator withdrawals)\n // solhint-disable-next-line reentrancy\n consensusRewards += ethRemaining;\n emit AccountingConsensusRewards(ethRemaining);\n } else if (ethRemaining > fuseIntervalEnd) {\n // Beacon chain consensus rewards swept but also a slashed validator fully exited\n IWETH9(WETH).deposit{ value: ethRemaining }();\n // slither-disable-next-line unchecked-transfer\n IWETH9(WETH).transfer(VAULT_ADDRESS, ethRemaining);\n activeDepositedValidators -= 1;\n\n _wethWithdrawnToVault(ethRemaining);\n\n emit AccountingValidatorSlashed(\n activeDepositedValidators,\n ethRemaining\n );\n }\n // Oh no... Fuse is blown. The Strategist needs to adjust the accounting values.\n else {\n return _failAccounting(pauseOnFail);\n }\n }\n\n // slither-disable-end reentrancy-eth\n\n /// @dev pause any further accounting if required and return false\n function _failAccounting(bool pauseOnFail)\n internal\n returns (bool accountingValid)\n {\n // pause if not already\n if (pauseOnFail) {\n _pause();\n }\n // fail the accounting\n accountingValid = false;\n }\n\n /// @notice Allow the Strategist to fix the accounting of this strategy and unpause.\n /// @param _validatorsDelta adjust the active validators by up to plus three or minus three\n /// @param _consensusRewardsDelta adjust the accounted for consensus rewards up or down\n /// @param _ethToVaultAmount the amount of ETH that gets wrapped into WETH and sent to the Vault\n /// @dev There is a case when a validator(s) gets slashed so much that the eth swept from\n /// the beacon chain enters the fuse area and there are no consensus rewards on the contract\n /// to \"dip into\"/use. To increase the amount of unaccounted ETH over the fuse end interval\n /// we need to reduce the amount of active deposited validators and immediately send WETH\n /// to the vault, so it doesn't interfere with further accounting.\n function manuallyFixAccounting(\n int256 _validatorsDelta,\n int256 _consensusRewardsDelta,\n uint256 _ethToVaultAmount\n ) external onlyStrategist whenPaused nonReentrant {\n require(\n lastFixAccountingBlockNumber + MIN_FIX_ACCOUNTING_CADENCE <\n block.number,\n \"Fix accounting called too soon\"\n );\n require(\n _validatorsDelta >= -3 &&\n _validatorsDelta <= 3 &&\n // new value must be positive\n int256(activeDepositedValidators) + _validatorsDelta >= 0,\n \"Invalid validatorsDelta\"\n );\n require(\n _consensusRewardsDelta >= -332 ether &&\n _consensusRewardsDelta <= 332 ether &&\n // new value must be positive\n int256(consensusRewards) + _consensusRewardsDelta >= 0,\n \"Invalid consensusRewardsDelta\"\n );\n require(_ethToVaultAmount <= 32 ether * 3, \"Invalid wethToVaultAmount\");\n\n activeDepositedValidators = uint256(\n int256(activeDepositedValidators) + _validatorsDelta\n );\n consensusRewards = uint256(\n int256(consensusRewards) + _consensusRewardsDelta\n );\n lastFixAccountingBlockNumber = block.number;\n if (_ethToVaultAmount > 0) {\n IWETH9(WETH).deposit{ value: _ethToVaultAmount }();\n // slither-disable-next-line unchecked-transfer\n IWETH9(WETH).transfer(VAULT_ADDRESS, _ethToVaultAmount);\n _wethWithdrawnToVault(_ethToVaultAmount);\n }\n\n emit AccountingManuallyFixed(\n _validatorsDelta,\n _consensusRewardsDelta,\n _ethToVaultAmount\n );\n\n // rerun the accounting to see if it has now been fixed.\n // Do not pause the accounting on failure as it is already paused\n require(_doAccounting(false), \"Fuse still blown\");\n\n // unpause since doAccounting was successful\n _unpause();\n }\n\n /***************************************\n Abstract\n ****************************************/\n\n /// @dev allows for NativeStakingSSVStrategy contract to emit the Withdrawal event\n function _wethWithdrawnToVault(uint256 _amount) internal virtual;\n}\n" + }, + "contracts/strategies/NativeStaking/ValidatorRegistrator.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { Pausable } from \"@openzeppelin/contracts/security/Pausable.sol\";\nimport { Governable } from \"../../governance/Governable.sol\";\nimport { IDepositContract } from \"../../interfaces/IDepositContract.sol\";\nimport { IVault } from \"../../interfaces/IVault.sol\";\nimport { IWETH9 } from \"../../interfaces/IWETH9.sol\";\nimport { ISSVNetwork, Cluster } from \"../../interfaces/ISSVNetwork.sol\";\n\nstruct ValidatorStakeData {\n bytes pubkey;\n bytes signature;\n bytes32 depositDataRoot;\n}\n\n/**\n * @title Registrator of the validators\n * @notice This contract implements all the required functionality to register, exit and remove validators.\n * @author Origin Protocol Inc\n */\nabstract contract ValidatorRegistrator is Governable, Pausable {\n /// @notice The maximum amount of ETH that can be staked by a validator\n /// @dev this can change in the future with EIP-7251, Increase the MAX_EFFECTIVE_BALANCE\n uint256 public constant FULL_STAKE = 32 ether;\n\n /// @notice The address of the Wrapped ETH (WETH) token contract\n address public immutable WETH;\n /// @notice The address of the beacon chain deposit contract\n address public immutable BEACON_CHAIN_DEPOSIT_CONTRACT;\n /// @notice The address of the SSV Network contract used to interface with\n address public immutable SSV_NETWORK;\n /// @notice Address of the OETH Vault proxy contract\n address public immutable VAULT_ADDRESS;\n /// @notice Maximum number of validators that can be registered in this strategy\n uint256 public immutable MAX_VALIDATORS;\n\n /// @notice Address of the registrator - allowed to register, exit and remove validators\n address public validatorRegistrator;\n /// @notice The number of validators that have 32 (!) ETH actively deposited. When a new deposit\n /// to a validator happens this number increases, when a validator exit is detected this number\n /// decreases.\n uint256 public activeDepositedValidators;\n /// @notice State of the validators keccak256(pubKey) => state\n mapping(bytes32 => VALIDATOR_STATE) public validatorsStates;\n /// @notice The account that is allowed to modify stakeETHThreshold and reset stakeETHTally\n address public stakingMonitor;\n /// @notice Amount of ETH that can be staked before staking on the contract is suspended\n /// and the `stakingMonitor` needs to approve further staking by calling `resetStakeETHTally`\n uint256 public stakeETHThreshold;\n /// @notice Amount of ETH that has been staked since the `stakingMonitor` last called `resetStakeETHTally`.\n /// This can not go above `stakeETHThreshold`.\n uint256 public stakeETHTally;\n // For future use\n uint256[47] private __gap;\n\n enum VALIDATOR_STATE {\n NON_REGISTERED, // validator is not registered on the SSV network\n REGISTERED, // validator is registered on the SSV network\n STAKED, // validator has funds staked\n EXITING, // exit message has been posted and validator is in the process of exiting\n EXIT_COMPLETE // validator has funds withdrawn to the EigenPod and is removed from the SSV\n }\n\n event RegistratorChanged(address indexed newAddress);\n event StakingMonitorChanged(address indexed newAddress);\n event ETHStaked(bytes32 indexed pubKeyHash, bytes pubKey, uint256 amount);\n event SSVValidatorRegistered(\n bytes32 indexed pubKeyHash,\n bytes pubKey,\n uint64[] operatorIds\n );\n event SSVValidatorExitInitiated(\n bytes32 indexed pubKeyHash,\n bytes pubKey,\n uint64[] operatorIds\n );\n event SSVValidatorExitCompleted(\n bytes32 indexed pubKeyHash,\n bytes pubKey,\n uint64[] operatorIds\n );\n event StakeETHThresholdChanged(uint256 amount);\n event StakeETHTallyReset();\n\n /// @dev Throws if called by any account other than the Registrator\n modifier onlyRegistrator() {\n require(\n msg.sender == validatorRegistrator,\n \"Caller is not the Registrator\"\n );\n _;\n }\n\n /// @dev Throws if called by any account other than the Staking monitor\n modifier onlyStakingMonitor() {\n require(msg.sender == stakingMonitor, \"Caller is not the Monitor\");\n _;\n }\n\n /// @dev Throws if called by any account other than the Strategist\n modifier onlyStrategist() {\n require(\n msg.sender == IVault(VAULT_ADDRESS).strategistAddr(),\n \"Caller is not the Strategist\"\n );\n _;\n }\n\n /// @param _wethAddress Address of the Erc20 WETH Token contract\n /// @param _vaultAddress Address of the Vault\n /// @param _beaconChainDepositContract Address of the beacon chain deposit contract\n /// @param _ssvNetwork Address of the SSV Network contract\n /// @param _maxValidators Maximum number of validators that can be registered in the strategy\n constructor(\n address _wethAddress,\n address _vaultAddress,\n address _beaconChainDepositContract,\n address _ssvNetwork,\n uint256 _maxValidators\n ) {\n WETH = _wethAddress;\n BEACON_CHAIN_DEPOSIT_CONTRACT = _beaconChainDepositContract;\n SSV_NETWORK = _ssvNetwork;\n VAULT_ADDRESS = _vaultAddress;\n MAX_VALIDATORS = _maxValidators;\n }\n\n /// @notice Set the address of the registrator which can register, exit and remove validators\n function setRegistrator(address _address) external onlyGovernor {\n validatorRegistrator = _address;\n emit RegistratorChanged(_address);\n }\n\n /// @notice Set the address of the staking monitor that is allowed to reset stakeETHTally\n function setStakingMonitor(address _address) external onlyGovernor {\n stakingMonitor = _address;\n emit StakingMonitorChanged(_address);\n }\n\n /// @notice Set the amount of ETH that can be staked before staking monitor\n // needs to a approve further staking by resetting the stake ETH tally\n function setStakeETHThreshold(uint256 _amount) external onlyGovernor {\n stakeETHThreshold = _amount;\n emit StakeETHThresholdChanged(_amount);\n }\n\n /// @notice Reset the stakeETHTally\n function resetStakeETHTally() external onlyStakingMonitor {\n stakeETHTally = 0;\n emit StakeETHTallyReset();\n }\n\n /// @notice Stakes WETH to the node validators\n /// @param validators A list of validator data needed to stake.\n /// The `ValidatorStakeData` struct contains the pubkey, signature and depositDataRoot.\n /// Only the registrator can call this function.\n // slither-disable-start reentrancy-eth\n function stakeEth(ValidatorStakeData[] calldata validators)\n external\n onlyRegistrator\n whenNotPaused\n nonReentrant\n {\n uint256 requiredETH = validators.length * FULL_STAKE;\n\n // Check there is enough WETH from the deposits sitting in this strategy contract\n require(\n requiredETH <= IWETH9(WETH).balanceOf(address(this)),\n \"Insufficient WETH\"\n );\n require(\n activeDepositedValidators + validators.length <= MAX_VALIDATORS,\n \"Max validators reached\"\n );\n\n require(\n stakeETHTally + requiredETH <= stakeETHThreshold,\n \"Staking ETH over threshold\"\n );\n stakeETHTally += requiredETH;\n\n // Convert required ETH from WETH\n IWETH9(WETH).withdraw(requiredETH);\n _wethWithdrawn(requiredETH);\n\n /* 0x01 to indicate that withdrawal credentials will contain an EOA address that the sweeping function\n * can sweep funds to.\n * bytes11(0) to fill up the required zeros\n * remaining bytes20 are for the address\n */\n bytes memory withdrawalCredentials = abi.encodePacked(\n bytes1(0x01),\n bytes11(0),\n address(this)\n );\n\n // For each validator\n for (uint256 i = 0; i < validators.length; ++i) {\n bytes32 pubKeyHash = keccak256(validators[i].pubkey);\n\n require(\n validatorsStates[pubKeyHash] == VALIDATOR_STATE.REGISTERED,\n \"Validator not registered\"\n );\n\n IDepositContract(BEACON_CHAIN_DEPOSIT_CONTRACT).deposit{\n value: FULL_STAKE\n }(\n validators[i].pubkey,\n withdrawalCredentials,\n validators[i].signature,\n validators[i].depositDataRoot\n );\n\n validatorsStates[pubKeyHash] = VALIDATOR_STATE.STAKED;\n\n emit ETHStaked(pubKeyHash, validators[i].pubkey, FULL_STAKE);\n }\n // save gas by changing this storage variable only once rather each time in the loop.\n activeDepositedValidators += validators.length;\n }\n\n // slither-disable-end reentrancy-eth\n\n /// @notice Registers a new validator in the SSV Cluster.\n /// Only the registrator can call this function.\n /// @param publicKeys The public keys of the validators\n /// @param operatorIds The operator IDs of the SSV Cluster\n /// @param sharesData The shares data for each validator\n /// @param ssvAmount The amount of SSV tokens to be deposited to the SSV cluster\n /// @param cluster The SSV cluster details including the validator count and SSV balance\n // slither-disable-start reentrancy-no-eth\n function registerSsvValidators(\n bytes[] calldata publicKeys,\n uint64[] calldata operatorIds,\n bytes[] calldata sharesData,\n uint256 ssvAmount,\n Cluster calldata cluster\n ) external onlyRegistrator whenNotPaused {\n require(\n publicKeys.length == sharesData.length,\n \"Pubkey sharesData mismatch\"\n );\n // Check each public key has not already been used\n bytes32 pubKeyHash;\n VALIDATOR_STATE currentState;\n for (uint256 i = 0; i < publicKeys.length; ++i) {\n pubKeyHash = keccak256(publicKeys[i]);\n currentState = validatorsStates[pubKeyHash];\n require(\n currentState == VALIDATOR_STATE.NON_REGISTERED,\n \"Validator already registered\"\n );\n\n validatorsStates[pubKeyHash] = VALIDATOR_STATE.REGISTERED;\n\n emit SSVValidatorRegistered(pubKeyHash, publicKeys[i], operatorIds);\n }\n\n ISSVNetwork(SSV_NETWORK).bulkRegisterValidator(\n publicKeys,\n operatorIds,\n sharesData,\n ssvAmount,\n cluster\n );\n }\n\n // slither-disable-end reentrancy-no-eth\n\n /// @notice Exit a validator from the Beacon chain.\n /// The staked ETH will eventually swept to this native staking strategy.\n /// Only the registrator can call this function.\n /// @param publicKey The public key of the validator\n /// @param operatorIds The operator IDs of the SSV Cluster\n // slither-disable-start reentrancy-no-eth\n function exitSsvValidator(\n bytes calldata publicKey,\n uint64[] calldata operatorIds\n ) external onlyRegistrator whenNotPaused {\n bytes32 pubKeyHash = keccak256(publicKey);\n VALIDATOR_STATE currentState = validatorsStates[pubKeyHash];\n require(currentState == VALIDATOR_STATE.STAKED, \"Validator not staked\");\n\n ISSVNetwork(SSV_NETWORK).exitValidator(publicKey, operatorIds);\n\n validatorsStates[pubKeyHash] = VALIDATOR_STATE.EXITING;\n\n emit SSVValidatorExitInitiated(pubKeyHash, publicKey, operatorIds);\n }\n\n // slither-disable-end reentrancy-no-eth\n\n /// @notice Remove a validator from the SSV Cluster.\n /// Make sure `exitSsvValidator` is called before and the validate has exited the Beacon chain.\n /// If removed before the validator has exited the beacon chain will result in the validator being slashed.\n /// Only the registrator can call this function.\n /// @param publicKey The public key of the validator\n /// @param operatorIds The operator IDs of the SSV Cluster\n /// @param cluster The SSV cluster details including the validator count and SSV balance\n // slither-disable-start reentrancy-no-eth\n function removeSsvValidator(\n bytes calldata publicKey,\n uint64[] calldata operatorIds,\n Cluster calldata cluster\n ) external onlyRegistrator whenNotPaused {\n bytes32 pubKeyHash = keccak256(publicKey);\n VALIDATOR_STATE currentState = validatorsStates[pubKeyHash];\n require(\n currentState == VALIDATOR_STATE.EXITING,\n \"Validator not exiting\"\n );\n\n ISSVNetwork(SSV_NETWORK).removeValidator(\n publicKey,\n operatorIds,\n cluster\n );\n\n validatorsStates[pubKeyHash] = VALIDATOR_STATE.EXIT_COMPLETE;\n\n emit SSVValidatorExitCompleted(pubKeyHash, publicKey, operatorIds);\n }\n\n // slither-disable-end reentrancy-no-eth\n\n /// @notice Deposits more SSV Tokens to the SSV Network contract which is used to pay the SSV Operators.\n /// @dev A SSV cluster is defined by the SSVOwnerAddress and the set of operatorIds.\n /// uses \"onlyStrategist\" modifier so continuous front-running can't DOS our maintenance service\n /// that tries to top up SSV tokens.\n /// @param operatorIds The operator IDs of the SSV Cluster\n /// @param ssvAmount The amount of SSV tokens to be deposited to the SSV cluster\n /// @param cluster The SSV cluster details including the validator count and SSV balance\n function depositSSV(\n uint64[] memory operatorIds,\n uint256 ssvAmount,\n Cluster memory cluster\n ) external onlyStrategist {\n ISSVNetwork(SSV_NETWORK).deposit(\n address(this),\n operatorIds,\n ssvAmount,\n cluster\n );\n }\n\n /***************************************\n Abstract\n ****************************************/\n\n /// @dev Called when WETH is withdrawn from the strategy or staked to a validator so\n /// the strategy knows how much WETH it has on deposit.\n /// This is so it can emit the correct amount in the Deposit event in depositAll().\n function _wethWithdrawn(uint256 _amount) internal virtual;\n}\n" + }, + "contracts/strategies/ThreePoolStrategy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title Curve 3Pool Strategy\n * @notice Investment strategy for investing stablecoins via Curve 3Pool\n * @author Origin Protocol Inc\n */\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { ICurveGauge } from \"./ICurveGauge.sol\";\nimport { ICurvePool } from \"./ICurvePool.sol\";\nimport { ICRVMinter } from \"./ICRVMinter.sol\";\nimport { IERC20, BaseCurveStrategy, InitializableAbstractStrategy } from \"./BaseCurveStrategy.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { Helpers } from \"../utils/Helpers.sol\";\n\n/*\n * IMPORTANT(!) If ThreePoolStrategy needs to be re-deployed, it requires new\n * proxy contract with fresh storage slots. Changes in `BaseCurveStrategy`\n * storage slots would break existing implementation.\n *\n * Remove this notice if ThreePoolStrategy is re-deployed\n */\ncontract ThreePoolStrategy is BaseCurveStrategy {\n using StableMath for uint256;\n using SafeERC20 for IERC20;\n\n address internal crvGaugeAddress;\n address internal crvMinterAddress;\n\n constructor(BaseStrategyConfig memory _stratConfig)\n InitializableAbstractStrategy(_stratConfig)\n {}\n\n /**\n * Initializer for setting up strategy internal state. This overrides the\n * InitializableAbstractStrategy initializer as Curve strategies don't fit\n * well within that abstraction.\n * @param _rewardTokenAddress Address of CRV\n * @param _assets Addresses of supported assets. MUST be passed in the same\n * order as returned by coins on the pool contract, i.e.\n * DAI, USDC, USDT\n * @param _pTokens Platform Token corresponding addresses\n * @param _crvGaugeAddress Address of the Curve DAO gauge for this pool\n * @param _crvMinterAddress Address of the CRV minter for rewards\n */\n function initialize(\n address[] calldata _rewardTokenAddress, // CRV\n address[] calldata _assets,\n address[] calldata _pTokens,\n address _crvGaugeAddress,\n address _crvMinterAddress\n ) external onlyGovernor initializer {\n require(_assets.length == 3, \"Must have exactly three assets\");\n // Should be set prior to abstract initialize call otherwise\n // abstractSetPToken calls will fail\n crvGaugeAddress = _crvGaugeAddress;\n crvMinterAddress = _crvMinterAddress;\n pTokenAddress = _pTokens[0];\n InitializableAbstractStrategy._initialize(\n _rewardTokenAddress,\n _assets,\n _pTokens\n );\n _approveBase();\n }\n\n function _lpDepositAll() internal override {\n IERC20 pToken = IERC20(pTokenAddress);\n // Deposit into Gauge\n ICurveGauge(crvGaugeAddress).deposit(\n pToken.balanceOf(address(this)),\n address(this)\n );\n }\n\n function _lpWithdraw(uint256 numPTokens) internal override {\n // Not enough of pool token exists on this contract, some must be\n // staked in Gauge, unstake difference\n ICurveGauge(crvGaugeAddress).withdraw(numPTokens);\n }\n\n function _lpWithdrawAll() internal override {\n ICurveGauge gauge = ICurveGauge(crvGaugeAddress);\n gauge.withdraw(gauge.balanceOf(address(this)));\n }\n\n /**\n * @dev Get the total asset value held in the platform\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n public\n view\n override\n returns (uint256 balance)\n {\n require(assetToPToken[_asset] != address(0), \"Unsupported asset\");\n // LP tokens in this contract. This should generally be nothing as we\n // should always stake the full balance in the Gauge, but include for\n // safety\n\n uint256 contractPTokens = IERC20(pTokenAddress).balanceOf(\n address(this)\n );\n ICurveGauge gauge = ICurveGauge(crvGaugeAddress);\n uint256 gaugePTokens = gauge.balanceOf(address(this));\n uint256 totalPTokens = contractPTokens + gaugePTokens;\n\n ICurvePool curvePool = ICurvePool(platformAddress);\n if (totalPTokens > 0) {\n uint256 virtual_price = curvePool.get_virtual_price();\n uint256 value = (totalPTokens * virtual_price) / 1e18;\n uint256 assetDecimals = Helpers.getDecimals(_asset);\n balance = value.scaleBy(assetDecimals, 18) / 3;\n }\n }\n\n function _approveBase() internal override {\n IERC20 pToken = IERC20(pTokenAddress);\n // 3Pool for LP token (required for removing liquidity)\n pToken.safeApprove(platformAddress, 0);\n pToken.safeApprove(platformAddress, type(uint256).max);\n // Gauge for LP token\n pToken.safeApprove(crvGaugeAddress, 0);\n pToken.safeApprove(crvGaugeAddress, type(uint256).max);\n }\n\n /**\n * @dev Collect accumulated CRV and send to Vault.\n */\n function collectRewardTokens() public override onlyHarvester nonReentrant {\n // Collect\n ICRVMinter(crvMinterAddress).mint(crvGaugeAddress);\n // Send\n IERC20 crvToken = IERC20(rewardTokenAddresses[0]);\n uint256 balance = crvToken.balanceOf(address(this));\n emit RewardTokenCollected(\n harvesterAddress,\n rewardTokenAddresses[0],\n balance\n );\n crvToken.safeTransfer(harvesterAddress, balance);\n }\n}\n" + }, + "contracts/strategies/VaultValueChecker.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IOUSD } from \"../interfaces/IOUSD.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\n\ncontract VaultValueChecker {\n IVault public immutable vault;\n IOUSD public immutable ousd;\n // Snapshot expiration time in seconds.\n // Used to prevent accidental use of an old snapshot, but\n // is not zero to allow easy testing of strategist actions in fork testing\n uint256 constant SNAPSHOT_EXPIRES = 5 * 60;\n\n struct Snapshot {\n uint256 vaultValue;\n uint256 totalSupply;\n uint256 time;\n }\n // By doing per user snapshots, we prevent a reentrancy attack\n // from a third party that updates the snapshot in the middle\n // of an allocation process\n\n mapping(address => Snapshot) public snapshots;\n\n constructor(address _vault, address _ousd) {\n vault = IVault(_vault);\n ousd = IOUSD(_ousd);\n }\n\n function takeSnapshot() external {\n snapshots[msg.sender] = Snapshot({\n vaultValue: vault.totalValue(),\n totalSupply: ousd.totalSupply(),\n time: block.timestamp\n });\n }\n\n function checkDelta(\n int256 expectedProfit,\n int256 profitVariance,\n int256 expectedVaultChange,\n int256 vaultChangeVariance\n ) external {\n // Intentionaly not view so that this method shows up in TX builders\n Snapshot memory snapshot = snapshots[msg.sender];\n int256 vaultChange = toInt256(vault.totalValue()) -\n toInt256(snapshot.vaultValue);\n int256 supplyChange = toInt256(ousd.totalSupply()) -\n toInt256(snapshot.totalSupply);\n int256 profit = vaultChange - supplyChange;\n\n require(\n snapshot.time >= block.timestamp - SNAPSHOT_EXPIRES,\n \"Snapshot too old\"\n );\n require(snapshot.time <= block.timestamp, \"Snapshot too new\");\n require(profit >= expectedProfit - profitVariance, \"Profit too low\");\n require(profit <= expectedProfit + profitVariance, \"Profit too high\");\n require(\n vaultChange >= expectedVaultChange - vaultChangeVariance,\n \"Vault value change too low\"\n );\n require(\n vaultChange <= expectedVaultChange + vaultChangeVariance,\n \"Vault value change too high\"\n );\n }\n\n function toInt256(uint256 value) internal pure returns (int256) {\n // From openzeppelin math/SafeCast.sol\n // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\n require(\n value <= uint256(type(int256).max),\n \"SafeCast: value doesn't fit in an int256\"\n );\n return int256(value);\n }\n}\n\ncontract OETHVaultValueChecker is VaultValueChecker {\n constructor(address _vault, address _ousd)\n VaultValueChecker(_vault, _ousd)\n {}\n}\n" + }, + "contracts/token/OUSD.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title OUSD Token Contract\n * @dev ERC20 compatible contract for OUSD\n * @dev Implements an elastic supply\n * @author Origin Protocol Inc\n */\nimport { SafeMath } from \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport { Address } from \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport { Initializable } from \"../utils/Initializable.sol\";\nimport { InitializableERC20Detailed } from \"../utils/InitializableERC20Detailed.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\n\n/**\n * NOTE that this is an ERC20 token but the invariant that the sum of\n * balanceOf(x) for all x is not >= totalSupply(). This is a consequence of the\n * rebasing design. Any integrations with OUSD should be aware.\n */\n\ncontract OUSD is Initializable, InitializableERC20Detailed, Governable {\n using SafeMath for uint256;\n using StableMath for uint256;\n\n event TotalSupplyUpdatedHighres(\n uint256 totalSupply,\n uint256 rebasingCredits,\n uint256 rebasingCreditsPerToken\n );\n event AccountRebasingEnabled(address account);\n event AccountRebasingDisabled(address account);\n\n enum RebaseOptions {\n NotSet,\n OptOut,\n OptIn\n }\n\n uint256 private constant MAX_SUPPLY = ~uint128(0); // (2^128) - 1\n uint256 public _totalSupply;\n mapping(address => mapping(address => uint256)) private _allowances;\n address public vaultAddress = address(0);\n mapping(address => uint256) private _creditBalances;\n uint256 private _rebasingCredits;\n uint256 private _rebasingCreditsPerToken;\n // Frozen address/credits are non rebasing (value is held in contracts which\n // do not receive yield unless they explicitly opt in)\n uint256 public nonRebasingSupply;\n mapping(address => uint256) public nonRebasingCreditsPerToken;\n mapping(address => RebaseOptions) public rebaseState;\n mapping(address => uint256) public isUpgraded;\n\n uint256 private constant RESOLUTION_INCREASE = 1e9;\n\n function initialize(\n string calldata _nameArg,\n string calldata _symbolArg,\n address _vaultAddress,\n uint256 _initialCreditsPerToken\n ) external onlyGovernor initializer {\n InitializableERC20Detailed._initialize(_nameArg, _symbolArg, 18);\n _rebasingCreditsPerToken = _initialCreditsPerToken;\n vaultAddress = _vaultAddress;\n }\n\n /**\n * @dev Verifies that the caller is the Vault contract\n */\n modifier onlyVault() {\n require(vaultAddress == msg.sender, \"Caller is not the Vault\");\n _;\n }\n\n /**\n * @return The total supply of OUSD.\n */\n function totalSupply() public view override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @return Low resolution rebasingCreditsPerToken\n */\n function rebasingCreditsPerToken() public view returns (uint256) {\n return _rebasingCreditsPerToken / RESOLUTION_INCREASE;\n }\n\n /**\n * @return Low resolution total number of rebasing credits\n */\n function rebasingCredits() public view returns (uint256) {\n return _rebasingCredits / RESOLUTION_INCREASE;\n }\n\n /**\n * @return High resolution rebasingCreditsPerToken\n */\n function rebasingCreditsPerTokenHighres() public view returns (uint256) {\n return _rebasingCreditsPerToken;\n }\n\n /**\n * @return High resolution total number of rebasing credits\n */\n function rebasingCreditsHighres() public view returns (uint256) {\n return _rebasingCredits;\n }\n\n /**\n * @dev Gets the balance of the specified address.\n * @param _account Address to query the balance of.\n * @return A uint256 representing the amount of base units owned by the\n * specified address.\n */\n function balanceOf(address _account)\n public\n view\n override\n returns (uint256)\n {\n if (_creditBalances[_account] == 0) return 0;\n return\n _creditBalances[_account].divPrecisely(_creditsPerToken(_account));\n }\n\n /**\n * @dev Gets the credits balance of the specified address.\n * @dev Backwards compatible with old low res credits per token.\n * @param _account The address to query the balance of.\n * @return (uint256, uint256) Credit balance and credits per token of the\n * address\n */\n function creditsBalanceOf(address _account)\n public\n view\n returns (uint256, uint256)\n {\n uint256 cpt = _creditsPerToken(_account);\n if (cpt == 1e27) {\n // For a period before the resolution upgrade, we created all new\n // contract accounts at high resolution. Since they are not changing\n // as a result of this upgrade, we will return their true values\n return (_creditBalances[_account], cpt);\n } else {\n return (\n _creditBalances[_account] / RESOLUTION_INCREASE,\n cpt / RESOLUTION_INCREASE\n );\n }\n }\n\n /**\n * @dev Gets the credits balance of the specified address.\n * @param _account The address to query the balance of.\n * @return (uint256, uint256, bool) Credit balance, credits per token of the\n * address, and isUpgraded\n */\n function creditsBalanceOfHighres(address _account)\n public\n view\n returns (\n uint256,\n uint256,\n bool\n )\n {\n return (\n _creditBalances[_account],\n _creditsPerToken(_account),\n isUpgraded[_account] == 1\n );\n }\n\n /**\n * @dev Transfer tokens to a specified address.\n * @param _to the address to transfer to.\n * @param _value the amount to be transferred.\n * @return true on success.\n */\n function transfer(address _to, uint256 _value)\n public\n override\n returns (bool)\n {\n require(_to != address(0), \"Transfer to zero address\");\n require(\n _value <= balanceOf(msg.sender),\n \"Transfer greater than balance\"\n );\n\n _executeTransfer(msg.sender, _to, _value);\n\n emit Transfer(msg.sender, _to, _value);\n\n return true;\n }\n\n /**\n * @dev Transfer tokens from one address to another.\n * @param _from The address you want to send tokens from.\n * @param _to The address you want to transfer to.\n * @param _value The amount of tokens to be transferred.\n */\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) public override returns (bool) {\n require(_to != address(0), \"Transfer to zero address\");\n require(_value <= balanceOf(_from), \"Transfer greater than balance\");\n\n _allowances[_from][msg.sender] = _allowances[_from][msg.sender].sub(\n _value\n );\n\n _executeTransfer(_from, _to, _value);\n\n emit Transfer(_from, _to, _value);\n\n return true;\n }\n\n /**\n * @dev Update the count of non rebasing credits in response to a transfer\n * @param _from The address you want to send tokens from.\n * @param _to The address you want to transfer to.\n * @param _value Amount of OUSD to transfer\n */\n function _executeTransfer(\n address _from,\n address _to,\n uint256 _value\n ) internal {\n bool isNonRebasingTo = _isNonRebasingAccount(_to);\n bool isNonRebasingFrom = _isNonRebasingAccount(_from);\n\n // Credits deducted and credited might be different due to the\n // differing creditsPerToken used by each account\n uint256 creditsCredited = _value.mulTruncate(_creditsPerToken(_to));\n uint256 creditsDeducted = _value.mulTruncate(_creditsPerToken(_from));\n\n _creditBalances[_from] = _creditBalances[_from].sub(\n creditsDeducted,\n \"Transfer amount exceeds balance\"\n );\n _creditBalances[_to] = _creditBalances[_to].add(creditsCredited);\n\n if (isNonRebasingTo && !isNonRebasingFrom) {\n // Transfer to non-rebasing account from rebasing account, credits\n // are removed from the non rebasing tally\n nonRebasingSupply = nonRebasingSupply.add(_value);\n // Update rebasingCredits by subtracting the deducted amount\n _rebasingCredits = _rebasingCredits.sub(creditsDeducted);\n } else if (!isNonRebasingTo && isNonRebasingFrom) {\n // Transfer to rebasing account from non-rebasing account\n // Decreasing non-rebasing credits by the amount that was sent\n nonRebasingSupply = nonRebasingSupply.sub(_value);\n // Update rebasingCredits by adding the credited amount\n _rebasingCredits = _rebasingCredits.add(creditsCredited);\n }\n }\n\n /**\n * @dev Function to check the amount of tokens that _owner has allowed to\n * `_spender`.\n * @param _owner The address which owns the funds.\n * @param _spender The address which will spend the funds.\n * @return The number of tokens still available for the _spender.\n */\n function allowance(address _owner, address _spender)\n public\n view\n override\n returns (uint256)\n {\n return _allowances[_owner][_spender];\n }\n\n /**\n * @dev Approve the passed address to spend the specified amount of tokens\n * on behalf of msg.sender. This method is included for ERC20\n * compatibility. `increaseAllowance` and `decreaseAllowance` should be\n * used instead.\n *\n * Changing an allowance with this method brings the risk that someone\n * may transfer both the old and the new allowance - if they are both\n * greater than zero - if a transfer transaction is mined before the\n * later approve() call is mined.\n * @param _spender The address which will spend the funds.\n * @param _value The amount of tokens to be spent.\n */\n function approve(address _spender, uint256 _value)\n public\n override\n returns (bool)\n {\n _allowances[msg.sender][_spender] = _value;\n emit Approval(msg.sender, _spender, _value);\n return true;\n }\n\n /**\n * @dev Increase the amount of tokens that an owner has allowed to\n * `_spender`.\n * This method should be used instead of approve() to avoid the double\n * approval vulnerability described above.\n * @param _spender The address which will spend the funds.\n * @param _addedValue The amount of tokens to increase the allowance by.\n */\n function increaseAllowance(address _spender, uint256 _addedValue)\n public\n returns (bool)\n {\n _allowances[msg.sender][_spender] = _allowances[msg.sender][_spender]\n .add(_addedValue);\n emit Approval(msg.sender, _spender, _allowances[msg.sender][_spender]);\n return true;\n }\n\n /**\n * @dev Decrease the amount of tokens that an owner has allowed to\n `_spender`.\n * @param _spender The address which will spend the funds.\n * @param _subtractedValue The amount of tokens to decrease the allowance\n * by.\n */\n function decreaseAllowance(address _spender, uint256 _subtractedValue)\n public\n returns (bool)\n {\n uint256 oldValue = _allowances[msg.sender][_spender];\n if (_subtractedValue >= oldValue) {\n _allowances[msg.sender][_spender] = 0;\n } else {\n _allowances[msg.sender][_spender] = oldValue.sub(_subtractedValue);\n }\n emit Approval(msg.sender, _spender, _allowances[msg.sender][_spender]);\n return true;\n }\n\n /**\n * @dev Mints new tokens, increasing totalSupply.\n */\n function mint(address _account, uint256 _amount) external onlyVault {\n _mint(_account, _amount);\n }\n\n /**\n * @dev Creates `_amount` tokens and assigns them to `_account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements\n *\n * - `to` cannot be the zero address.\n */\n function _mint(address _account, uint256 _amount) internal nonReentrant {\n require(_account != address(0), \"Mint to the zero address\");\n\n bool isNonRebasingAccount = _isNonRebasingAccount(_account);\n\n uint256 creditAmount = _amount.mulTruncate(_creditsPerToken(_account));\n _creditBalances[_account] = _creditBalances[_account].add(creditAmount);\n\n // If the account is non rebasing and doesn't have a set creditsPerToken\n // then set it i.e. this is a mint from a fresh contract\n if (isNonRebasingAccount) {\n nonRebasingSupply = nonRebasingSupply.add(_amount);\n } else {\n _rebasingCredits = _rebasingCredits.add(creditAmount);\n }\n\n _totalSupply = _totalSupply.add(_amount);\n\n require(_totalSupply < MAX_SUPPLY, \"Max supply\");\n\n emit Transfer(address(0), _account, _amount);\n }\n\n /**\n * @dev Burns tokens, decreasing totalSupply.\n */\n function burn(address account, uint256 amount) external onlyVault {\n _burn(account, amount);\n }\n\n /**\n * @dev Destroys `_amount` tokens from `_account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements\n *\n * - `_account` cannot be the zero address.\n * - `_account` must have at least `_amount` tokens.\n */\n function _burn(address _account, uint256 _amount) internal nonReentrant {\n require(_account != address(0), \"Burn from the zero address\");\n if (_amount == 0) {\n return;\n }\n\n bool isNonRebasingAccount = _isNonRebasingAccount(_account);\n uint256 creditAmount = _amount.mulTruncate(_creditsPerToken(_account));\n uint256 currentCredits = _creditBalances[_account];\n\n // Remove the credits, burning rounding errors\n if (\n currentCredits == creditAmount || currentCredits - 1 == creditAmount\n ) {\n // Handle dust from rounding\n _creditBalances[_account] = 0;\n } else if (currentCredits > creditAmount) {\n _creditBalances[_account] = _creditBalances[_account].sub(\n creditAmount\n );\n } else {\n revert(\"Remove exceeds balance\");\n }\n\n // Remove from the credit tallies and non-rebasing supply\n if (isNonRebasingAccount) {\n nonRebasingSupply = nonRebasingSupply.sub(_amount);\n } else {\n _rebasingCredits = _rebasingCredits.sub(creditAmount);\n }\n\n _totalSupply = _totalSupply.sub(_amount);\n\n emit Transfer(_account, address(0), _amount);\n }\n\n /**\n * @dev Get the credits per token for an account. Returns a fixed amount\n * if the account is non-rebasing.\n * @param _account Address of the account.\n */\n function _creditsPerToken(address _account)\n internal\n view\n returns (uint256)\n {\n if (nonRebasingCreditsPerToken[_account] != 0) {\n return nonRebasingCreditsPerToken[_account];\n } else {\n return _rebasingCreditsPerToken;\n }\n }\n\n /**\n * @dev Is an account using rebasing accounting or non-rebasing accounting?\n * Also, ensure contracts are non-rebasing if they have not opted in.\n * @param _account Address of the account.\n */\n function _isNonRebasingAccount(address _account) internal returns (bool) {\n bool isContract = Address.isContract(_account);\n if (isContract && rebaseState[_account] == RebaseOptions.NotSet) {\n _ensureRebasingMigration(_account);\n }\n return nonRebasingCreditsPerToken[_account] > 0;\n }\n\n /**\n * @dev Ensures internal account for rebasing and non-rebasing credits and\n * supply is updated following deployment of frozen yield change.\n */\n function _ensureRebasingMigration(address _account) internal {\n if (nonRebasingCreditsPerToken[_account] == 0) {\n emit AccountRebasingDisabled(_account);\n if (_creditBalances[_account] == 0) {\n // Since there is no existing balance, we can directly set to\n // high resolution, and do not have to do any other bookkeeping\n nonRebasingCreditsPerToken[_account] = 1e27;\n } else {\n // Migrate an existing account:\n\n // Set fixed credits per token for this account\n nonRebasingCreditsPerToken[_account] = _rebasingCreditsPerToken;\n // Update non rebasing supply\n nonRebasingSupply = nonRebasingSupply.add(balanceOf(_account));\n // Update credit tallies\n _rebasingCredits = _rebasingCredits.sub(\n _creditBalances[_account]\n );\n }\n }\n }\n\n /**\n * @notice Enable rebasing for an account.\n * @dev Add a contract address to the non-rebasing exception list. The\n * address's balance will be part of rebases and the account will be exposed\n * to upside and downside.\n * @param _account Address of the account.\n */\n function governanceRebaseOptIn(address _account)\n public\n nonReentrant\n onlyGovernor\n {\n _rebaseOptIn(_account);\n }\n\n /**\n * @dev Add a contract address to the non-rebasing exception list. The\n * address's balance will be part of rebases and the account will be exposed\n * to upside and downside.\n */\n function rebaseOptIn() public nonReentrant {\n _rebaseOptIn(msg.sender);\n }\n\n function _rebaseOptIn(address _account) internal {\n require(_isNonRebasingAccount(_account), \"Account has not opted out\");\n\n // Convert balance into the same amount at the current exchange rate\n uint256 newCreditBalance = _creditBalances[_account]\n .mul(_rebasingCreditsPerToken)\n .div(_creditsPerToken(_account));\n\n // Decreasing non rebasing supply\n nonRebasingSupply = nonRebasingSupply.sub(balanceOf(_account));\n\n _creditBalances[_account] = newCreditBalance;\n\n // Increase rebasing credits, totalSupply remains unchanged so no\n // adjustment necessary\n _rebasingCredits = _rebasingCredits.add(_creditBalances[_account]);\n\n rebaseState[_account] = RebaseOptions.OptIn;\n\n // Delete any fixed credits per token\n delete nonRebasingCreditsPerToken[_account];\n emit AccountRebasingEnabled(_account);\n }\n\n /**\n * @dev Explicitly mark that an address is non-rebasing.\n */\n function rebaseOptOut() public nonReentrant {\n require(!_isNonRebasingAccount(msg.sender), \"Account has not opted in\");\n\n // Increase non rebasing supply\n nonRebasingSupply = nonRebasingSupply.add(balanceOf(msg.sender));\n // Set fixed credits per token\n nonRebasingCreditsPerToken[msg.sender] = _rebasingCreditsPerToken;\n\n // Decrease rebasing credits, total supply remains unchanged so no\n // adjustment necessary\n _rebasingCredits = _rebasingCredits.sub(_creditBalances[msg.sender]);\n\n // Mark explicitly opted out of rebasing\n rebaseState[msg.sender] = RebaseOptions.OptOut;\n emit AccountRebasingDisabled(msg.sender);\n }\n\n /**\n * @dev Modify the supply without minting new tokens. This uses a change in\n * the exchange rate between \"credits\" and OUSD tokens to change balances.\n * @param _newTotalSupply New total supply of OUSD.\n */\n function changeSupply(uint256 _newTotalSupply)\n external\n onlyVault\n nonReentrant\n {\n require(_totalSupply > 0, \"Cannot increase 0 supply\");\n\n if (_totalSupply == _newTotalSupply) {\n emit TotalSupplyUpdatedHighres(\n _totalSupply,\n _rebasingCredits,\n _rebasingCreditsPerToken\n );\n return;\n }\n\n _totalSupply = _newTotalSupply > MAX_SUPPLY\n ? MAX_SUPPLY\n : _newTotalSupply;\n\n _rebasingCreditsPerToken = _rebasingCredits.divPrecisely(\n _totalSupply.sub(nonRebasingSupply)\n );\n\n require(_rebasingCreditsPerToken > 0, \"Invalid change in supply\");\n\n _totalSupply = _rebasingCredits\n .divPrecisely(_rebasingCreditsPerToken)\n .add(nonRebasingSupply);\n\n emit TotalSupplyUpdatedHighres(\n _totalSupply,\n _rebasingCredits,\n _rebasingCreditsPerToken\n );\n }\n}\n" + }, + "contracts/utils/BalancerErrors.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see .\n\npragma solidity >=0.7.4 <0.9.0;\n\n// solhint-disable\n\n/**\n * @dev Reverts if `condition` is false, with a revert reason containing `errorCode`. Only codes up to 999 are\n * supported.\n * Uses the default 'BAL' prefix for the error code\n */\nfunction _require(bool condition, uint256 errorCode) pure {\n if (!condition) _revert(errorCode);\n}\n\n/**\n * @dev Reverts if `condition` is false, with a revert reason containing `errorCode`. Only codes up to 999 are\n * supported.\n */\nfunction _require(\n bool condition,\n uint256 errorCode,\n bytes3 prefix\n) pure {\n if (!condition) _revert(errorCode, prefix);\n}\n\n/**\n * @dev Reverts with a revert reason containing `errorCode`. Only codes up to 999 are supported.\n * Uses the default 'BAL' prefix for the error code\n */\nfunction _revert(uint256 errorCode) pure {\n _revert(errorCode, 0x42414c); // This is the raw byte representation of \"BAL\"\n}\n\n/**\n * @dev Reverts with a revert reason containing `errorCode`. Only codes up to 999 are supported.\n */\nfunction _revert(uint256 errorCode, bytes3 prefix) pure {\n uint256 prefixUint = uint256(uint24(prefix));\n // We're going to dynamically create a revert string based on the error code, with the following format:\n // 'BAL#{errorCode}'\n // where the code is left-padded with zeroes to three digits (so they range from 000 to 999).\n //\n // We don't have revert strings embedded in the contract to save bytecode size: it takes much less space to store a\n // number (8 to 16 bits) than the individual string characters.\n //\n // The dynamic string creation algorithm that follows could be implemented in Solidity, but assembly allows for a\n // much denser implementation, again saving bytecode size. Given this function unconditionally reverts, this is a\n // safe place to rely on it without worrying about how its usage might affect e.g. memory contents.\n assembly {\n // First, we need to compute the ASCII representation of the error code. We assume that it is in the 0-999\n // range, so we only need to convert three digits. To convert the digits to ASCII, we add 0x30, the value for\n // the '0' character.\n\n let units := add(mod(errorCode, 10), 0x30)\n\n errorCode := div(errorCode, 10)\n let tenths := add(mod(errorCode, 10), 0x30)\n\n errorCode := div(errorCode, 10)\n let hundreds := add(mod(errorCode, 10), 0x30)\n\n // With the individual characters, we can now construct the full string.\n // We first append the '#' character (0x23) to the prefix. In the case of 'BAL', it results in 0x42414c23 ('BAL#')\n // Then, we shift this by 24 (to provide space for the 3 bytes of the error code), and add the\n // characters to it, each shifted by a multiple of 8.\n // The revert reason is then shifted left by 200 bits (256 minus the length of the string, 7 characters * 8 bits\n // per character = 56) to locate it in the most significant part of the 256 slot (the beginning of a byte\n // array).\n let formattedPrefix := shl(24, add(0x23, shl(8, prefixUint)))\n\n let revertReason := shl(\n 200,\n add(\n formattedPrefix,\n add(add(units, shl(8, tenths)), shl(16, hundreds))\n )\n )\n\n // We can now encode the reason in memory, which can be safely overwritten as we're about to revert. The encoded\n // message will have the following layout:\n // [ revert reason identifier ] [ string location offset ] [ string length ] [ string contents ]\n\n // The Solidity revert reason identifier is 0x08c739a0, the function selector of the Error(string) function. We\n // also write zeroes to the next 28 bytes of memory, but those are about to be overwritten.\n mstore(\n 0x0,\n 0x08c379a000000000000000000000000000000000000000000000000000000000\n )\n // Next is the offset to the location of the string, which will be placed immediately after (20 bytes away).\n mstore(\n 0x04,\n 0x0000000000000000000000000000000000000000000000000000000000000020\n )\n // The string length is fixed: 7 characters.\n mstore(0x24, 7)\n // Finally, the string itself is stored.\n mstore(0x44, revertReason)\n\n // Even if the string is only 7 bytes long, we need to return a full 32 byte slot containing it. The length of\n // the encoded message is therefore 4 + 32 + 32 + 32 = 100.\n revert(0, 100)\n }\n}\n\nlibrary Errors {\n // Math\n uint256 internal constant ADD_OVERFLOW = 0;\n uint256 internal constant SUB_OVERFLOW = 1;\n uint256 internal constant SUB_UNDERFLOW = 2;\n uint256 internal constant MUL_OVERFLOW = 3;\n uint256 internal constant ZERO_DIVISION = 4;\n uint256 internal constant DIV_INTERNAL = 5;\n uint256 internal constant X_OUT_OF_BOUNDS = 6;\n uint256 internal constant Y_OUT_OF_BOUNDS = 7;\n uint256 internal constant PRODUCT_OUT_OF_BOUNDS = 8;\n uint256 internal constant INVALID_EXPONENT = 9;\n\n // Input\n uint256 internal constant OUT_OF_BOUNDS = 100;\n uint256 internal constant UNSORTED_ARRAY = 101;\n uint256 internal constant UNSORTED_TOKENS = 102;\n uint256 internal constant INPUT_LENGTH_MISMATCH = 103;\n uint256 internal constant ZERO_TOKEN = 104;\n uint256 internal constant INSUFFICIENT_DATA = 105;\n\n // Shared pools\n uint256 internal constant MIN_TOKENS = 200;\n uint256 internal constant MAX_TOKENS = 201;\n uint256 internal constant MAX_SWAP_FEE_PERCENTAGE = 202;\n uint256 internal constant MIN_SWAP_FEE_PERCENTAGE = 203;\n uint256 internal constant MINIMUM_BPT = 204;\n uint256 internal constant CALLER_NOT_VAULT = 205;\n uint256 internal constant UNINITIALIZED = 206;\n uint256 internal constant BPT_IN_MAX_AMOUNT = 207;\n uint256 internal constant BPT_OUT_MIN_AMOUNT = 208;\n uint256 internal constant EXPIRED_PERMIT = 209;\n uint256 internal constant NOT_TWO_TOKENS = 210;\n uint256 internal constant DISABLED = 211;\n\n // Pools\n uint256 internal constant MIN_AMP = 300;\n uint256 internal constant MAX_AMP = 301;\n uint256 internal constant MIN_WEIGHT = 302;\n uint256 internal constant MAX_STABLE_TOKENS = 303;\n uint256 internal constant MAX_IN_RATIO = 304;\n uint256 internal constant MAX_OUT_RATIO = 305;\n uint256 internal constant MIN_BPT_IN_FOR_TOKEN_OUT = 306;\n uint256 internal constant MAX_OUT_BPT_FOR_TOKEN_IN = 307;\n uint256 internal constant NORMALIZED_WEIGHT_INVARIANT = 308;\n uint256 internal constant INVALID_TOKEN = 309;\n uint256 internal constant UNHANDLED_JOIN_KIND = 310;\n uint256 internal constant ZERO_INVARIANT = 311;\n uint256 internal constant ORACLE_INVALID_SECONDS_QUERY = 312;\n uint256 internal constant ORACLE_NOT_INITIALIZED = 313;\n uint256 internal constant ORACLE_QUERY_TOO_OLD = 314;\n uint256 internal constant ORACLE_INVALID_INDEX = 315;\n uint256 internal constant ORACLE_BAD_SECS = 316;\n uint256 internal constant AMP_END_TIME_TOO_CLOSE = 317;\n uint256 internal constant AMP_ONGOING_UPDATE = 318;\n uint256 internal constant AMP_RATE_TOO_HIGH = 319;\n uint256 internal constant AMP_NO_ONGOING_UPDATE = 320;\n uint256 internal constant STABLE_INVARIANT_DIDNT_CONVERGE = 321;\n uint256 internal constant STABLE_GET_BALANCE_DIDNT_CONVERGE = 322;\n uint256 internal constant RELAYER_NOT_CONTRACT = 323;\n uint256 internal constant BASE_POOL_RELAYER_NOT_CALLED = 324;\n uint256 internal constant REBALANCING_RELAYER_REENTERED = 325;\n uint256 internal constant GRADUAL_UPDATE_TIME_TRAVEL = 326;\n uint256 internal constant SWAPS_DISABLED = 327;\n uint256 internal constant CALLER_IS_NOT_LBP_OWNER = 328;\n uint256 internal constant PRICE_RATE_OVERFLOW = 329;\n uint256 internal constant INVALID_JOIN_EXIT_KIND_WHILE_SWAPS_DISABLED = 330;\n uint256 internal constant WEIGHT_CHANGE_TOO_FAST = 331;\n uint256 internal constant LOWER_GREATER_THAN_UPPER_TARGET = 332;\n uint256 internal constant UPPER_TARGET_TOO_HIGH = 333;\n uint256 internal constant UNHANDLED_BY_LINEAR_POOL = 334;\n uint256 internal constant OUT_OF_TARGET_RANGE = 335;\n uint256 internal constant UNHANDLED_EXIT_KIND = 336;\n uint256 internal constant UNAUTHORIZED_EXIT = 337;\n uint256 internal constant MAX_MANAGEMENT_SWAP_FEE_PERCENTAGE = 338;\n uint256 internal constant UNHANDLED_BY_MANAGED_POOL = 339;\n uint256 internal constant UNHANDLED_BY_PHANTOM_POOL = 340;\n uint256 internal constant TOKEN_DOES_NOT_HAVE_RATE_PROVIDER = 341;\n uint256 internal constant INVALID_INITIALIZATION = 342;\n uint256 internal constant OUT_OF_NEW_TARGET_RANGE = 343;\n uint256 internal constant FEATURE_DISABLED = 344;\n uint256 internal constant UNINITIALIZED_POOL_CONTROLLER = 345;\n uint256 internal constant SET_SWAP_FEE_DURING_FEE_CHANGE = 346;\n uint256 internal constant SET_SWAP_FEE_PENDING_FEE_CHANGE = 347;\n uint256 internal constant CHANGE_TOKENS_DURING_WEIGHT_CHANGE = 348;\n uint256 internal constant CHANGE_TOKENS_PENDING_WEIGHT_CHANGE = 349;\n uint256 internal constant MAX_WEIGHT = 350;\n uint256 internal constant UNAUTHORIZED_JOIN = 351;\n uint256 internal constant MAX_MANAGEMENT_AUM_FEE_PERCENTAGE = 352;\n uint256 internal constant FRACTIONAL_TARGET = 353;\n uint256 internal constant ADD_OR_REMOVE_BPT = 354;\n uint256 internal constant INVALID_CIRCUIT_BREAKER_BOUNDS = 355;\n uint256 internal constant CIRCUIT_BREAKER_TRIPPED = 356;\n uint256 internal constant MALICIOUS_QUERY_REVERT = 357;\n uint256 internal constant JOINS_EXITS_DISABLED = 358;\n\n // Lib\n uint256 internal constant REENTRANCY = 400;\n uint256 internal constant SENDER_NOT_ALLOWED = 401;\n uint256 internal constant PAUSED = 402;\n uint256 internal constant PAUSE_WINDOW_EXPIRED = 403;\n uint256 internal constant MAX_PAUSE_WINDOW_DURATION = 404;\n uint256 internal constant MAX_BUFFER_PERIOD_DURATION = 405;\n uint256 internal constant INSUFFICIENT_BALANCE = 406;\n uint256 internal constant INSUFFICIENT_ALLOWANCE = 407;\n uint256 internal constant ERC20_TRANSFER_FROM_ZERO_ADDRESS = 408;\n uint256 internal constant ERC20_TRANSFER_TO_ZERO_ADDRESS = 409;\n uint256 internal constant ERC20_MINT_TO_ZERO_ADDRESS = 410;\n uint256 internal constant ERC20_BURN_FROM_ZERO_ADDRESS = 411;\n uint256 internal constant ERC20_APPROVE_FROM_ZERO_ADDRESS = 412;\n uint256 internal constant ERC20_APPROVE_TO_ZERO_ADDRESS = 413;\n uint256 internal constant ERC20_TRANSFER_EXCEEDS_ALLOWANCE = 414;\n uint256 internal constant ERC20_DECREASED_ALLOWANCE_BELOW_ZERO = 415;\n uint256 internal constant ERC20_TRANSFER_EXCEEDS_BALANCE = 416;\n uint256 internal constant ERC20_BURN_EXCEEDS_ALLOWANCE = 417;\n uint256 internal constant SAFE_ERC20_CALL_FAILED = 418;\n uint256 internal constant ADDRESS_INSUFFICIENT_BALANCE = 419;\n uint256 internal constant ADDRESS_CANNOT_SEND_VALUE = 420;\n uint256 internal constant SAFE_CAST_VALUE_CANT_FIT_INT256 = 421;\n uint256 internal constant GRANT_SENDER_NOT_ADMIN = 422;\n uint256 internal constant REVOKE_SENDER_NOT_ADMIN = 423;\n uint256 internal constant RENOUNCE_SENDER_NOT_ALLOWED = 424;\n uint256 internal constant BUFFER_PERIOD_EXPIRED = 425;\n uint256 internal constant CALLER_IS_NOT_OWNER = 426;\n uint256 internal constant NEW_OWNER_IS_ZERO = 427;\n uint256 internal constant CODE_DEPLOYMENT_FAILED = 428;\n uint256 internal constant CALL_TO_NON_CONTRACT = 429;\n uint256 internal constant LOW_LEVEL_CALL_FAILED = 430;\n uint256 internal constant NOT_PAUSED = 431;\n uint256 internal constant ADDRESS_ALREADY_ALLOWLISTED = 432;\n uint256 internal constant ADDRESS_NOT_ALLOWLISTED = 433;\n uint256 internal constant ERC20_BURN_EXCEEDS_BALANCE = 434;\n uint256 internal constant INVALID_OPERATION = 435;\n uint256 internal constant CODEC_OVERFLOW = 436;\n uint256 internal constant IN_RECOVERY_MODE = 437;\n uint256 internal constant NOT_IN_RECOVERY_MODE = 438;\n uint256 internal constant INDUCED_FAILURE = 439;\n uint256 internal constant EXPIRED_SIGNATURE = 440;\n uint256 internal constant MALFORMED_SIGNATURE = 441;\n uint256 internal constant SAFE_CAST_VALUE_CANT_FIT_UINT64 = 442;\n uint256 internal constant UNHANDLED_FEE_TYPE = 443;\n uint256 internal constant BURN_FROM_ZERO = 444;\n\n // Vault\n uint256 internal constant INVALID_POOL_ID = 500;\n uint256 internal constant CALLER_NOT_POOL = 501;\n uint256 internal constant SENDER_NOT_ASSET_MANAGER = 502;\n uint256 internal constant USER_DOESNT_ALLOW_RELAYER = 503;\n uint256 internal constant INVALID_SIGNATURE = 504;\n uint256 internal constant EXIT_BELOW_MIN = 505;\n uint256 internal constant JOIN_ABOVE_MAX = 506;\n uint256 internal constant SWAP_LIMIT = 507;\n uint256 internal constant SWAP_DEADLINE = 508;\n uint256 internal constant CANNOT_SWAP_SAME_TOKEN = 509;\n uint256 internal constant UNKNOWN_AMOUNT_IN_FIRST_SWAP = 510;\n uint256 internal constant MALCONSTRUCTED_MULTIHOP_SWAP = 511;\n uint256 internal constant INTERNAL_BALANCE_OVERFLOW = 512;\n uint256 internal constant INSUFFICIENT_INTERNAL_BALANCE = 513;\n uint256 internal constant INVALID_ETH_INTERNAL_BALANCE = 514;\n uint256 internal constant INVALID_POST_LOAN_BALANCE = 515;\n uint256 internal constant INSUFFICIENT_ETH = 516;\n uint256 internal constant UNALLOCATED_ETH = 517;\n uint256 internal constant ETH_TRANSFER = 518;\n uint256 internal constant CANNOT_USE_ETH_SENTINEL = 519;\n uint256 internal constant TOKENS_MISMATCH = 520;\n uint256 internal constant TOKEN_NOT_REGISTERED = 521;\n uint256 internal constant TOKEN_ALREADY_REGISTERED = 522;\n uint256 internal constant TOKENS_ALREADY_SET = 523;\n uint256 internal constant TOKENS_LENGTH_MUST_BE_2 = 524;\n uint256 internal constant NONZERO_TOKEN_BALANCE = 525;\n uint256 internal constant BALANCE_TOTAL_OVERFLOW = 526;\n uint256 internal constant POOL_NO_TOKENS = 527;\n uint256 internal constant INSUFFICIENT_FLASH_LOAN_BALANCE = 528;\n\n // Fees\n uint256 internal constant SWAP_FEE_PERCENTAGE_TOO_HIGH = 600;\n uint256 internal constant FLASH_LOAN_FEE_PERCENTAGE_TOO_HIGH = 601;\n uint256 internal constant INSUFFICIENT_FLASH_LOAN_FEE_AMOUNT = 602;\n uint256 internal constant AUM_FEE_PERCENTAGE_TOO_HIGH = 603;\n\n // FeeSplitter\n uint256 internal constant SPLITTER_FEE_PERCENTAGE_TOO_HIGH = 700;\n\n // Misc\n uint256 internal constant UNIMPLEMENTED = 998;\n uint256 internal constant SHOULD_NOT_HAPPEN = 999;\n}\n" + }, + "contracts/utils/Helpers.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IBasicToken } from \"../interfaces/IBasicToken.sol\";\n\nlibrary Helpers {\n /**\n * @notice Fetch the `symbol()` from an ERC20 token\n * @dev Grabs the `symbol()` from a contract\n * @param _token Address of the ERC20 token\n * @return string Symbol of the ERC20 token\n */\n function getSymbol(address _token) internal view returns (string memory) {\n string memory symbol = IBasicToken(_token).symbol();\n return symbol;\n }\n\n /**\n * @notice Fetch the `decimals()` from an ERC20 token\n * @dev Grabs the `decimals()` from a contract and fails if\n * the decimal value does not live within a certain range\n * @param _token Address of the ERC20 token\n * @return uint256 Decimals of the ERC20 token\n */\n function getDecimals(address _token) internal view returns (uint256) {\n uint256 decimals = IBasicToken(_token).decimals();\n require(\n decimals >= 4 && decimals <= 18,\n \"Token must have sufficient decimal places\"\n );\n\n return decimals;\n }\n}\n" + }, + "contracts/utils/Initializable.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title Base contract any contracts that need to initialize state after deployment.\n * @author Origin Protocol Inc\n */\nabstract contract Initializable {\n /**\n * @dev Indicates that the contract has been initialized.\n */\n bool private initialized;\n\n /**\n * @dev Indicates that the contract is in the process of being initialized.\n */\n bool private initializing;\n\n /**\n * @dev Modifier to protect an initializer function from being invoked twice.\n */\n modifier initializer() {\n require(\n initializing || !initialized,\n \"Initializable: contract is already initialized\"\n );\n\n bool isTopLevelCall = !initializing;\n if (isTopLevelCall) {\n initializing = true;\n initialized = true;\n }\n\n _;\n\n if (isTopLevelCall) {\n initializing = false;\n }\n }\n\n uint256[50] private ______gap;\n}\n" + }, + "contracts/utils/InitializableAbstractStrategy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title Base contract for vault strategies.\n * @author Origin Protocol Inc\n */\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { Initializable } from \"../utils/Initializable.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\n\nabstract contract InitializableAbstractStrategy is Initializable, Governable {\n using SafeERC20 for IERC20;\n\n event PTokenAdded(address indexed _asset, address _pToken);\n event PTokenRemoved(address indexed _asset, address _pToken);\n event Deposit(address indexed _asset, address _pToken, uint256 _amount);\n event Withdrawal(address indexed _asset, address _pToken, uint256 _amount);\n event RewardTokenCollected(\n address recipient,\n address rewardToken,\n uint256 amount\n );\n event RewardTokenAddressesUpdated(\n address[] _oldAddresses,\n address[] _newAddresses\n );\n event HarvesterAddressesUpdated(\n address _oldHarvesterAddress,\n address _newHarvesterAddress\n );\n\n /// @notice Address of the underlying platform\n address public immutable platformAddress;\n /// @notice Address of the OToken vault\n address public immutable vaultAddress;\n\n /// @dev Replaced with an immutable variable\n // slither-disable-next-line constable-states\n address private _deprecated_platformAddress;\n\n /// @dev Replaced with an immutable\n // slither-disable-next-line constable-states\n address private _deprecated_vaultAddress;\n\n /// @notice asset => pToken (Platform Specific Token Address)\n mapping(address => address) public assetToPToken;\n\n /// @notice Full list of all assets supported by the strategy\n address[] internal assetsMapped;\n\n // Deprecated: Reward token address\n // slither-disable-next-line constable-states\n address private _deprecated_rewardTokenAddress;\n\n // Deprecated: now resides in Harvester's rewardTokenConfigs\n // slither-disable-next-line constable-states\n uint256 private _deprecated_rewardLiquidationThreshold;\n\n /// @notice Address of the Harvester contract allowed to collect reward tokens\n address public harvesterAddress;\n\n /// @notice Address of the reward tokens. eg CRV, BAL, CVX, AURA\n address[] public rewardTokenAddresses;\n\n /* Reserved for future expansion. Used to be 100 storage slots\n * and has decreased to accommodate:\n * - harvesterAddress\n * - rewardTokenAddresses\n */\n int256[98] private _reserved;\n\n struct BaseStrategyConfig {\n address platformAddress; // Address of the underlying platform\n address vaultAddress; // Address of the OToken's Vault\n }\n\n /**\n * @param _config The platform and OToken vault addresses\n */\n constructor(BaseStrategyConfig memory _config) {\n platformAddress = _config.platformAddress;\n vaultAddress = _config.vaultAddress;\n }\n\n /**\n * @dev Internal initialize function, to set up initial internal state\n * @param _rewardTokenAddresses Address of reward token for platform\n * @param _assets Addresses of initial supported assets\n * @param _pTokens Platform Token corresponding addresses\n */\n function _initialize(\n address[] memory _rewardTokenAddresses,\n address[] memory _assets,\n address[] memory _pTokens\n ) internal {\n rewardTokenAddresses = _rewardTokenAddresses;\n\n uint256 assetCount = _assets.length;\n require(assetCount == _pTokens.length, \"Invalid input arrays\");\n for (uint256 i = 0; i < assetCount; ++i) {\n _setPTokenAddress(_assets[i], _pTokens[i]);\n }\n }\n\n /**\n * @notice Collect accumulated reward token and send to Vault.\n */\n function collectRewardTokens() external virtual onlyHarvester nonReentrant {\n _collectRewardTokens();\n }\n\n /**\n * @dev Default implementation that transfers reward tokens to the Harvester\n * Implementing strategies need to add custom logic to collect the rewards.\n */\n function _collectRewardTokens() internal virtual {\n uint256 rewardTokenCount = rewardTokenAddresses.length;\n for (uint256 i = 0; i < rewardTokenCount; ++i) {\n IERC20 rewardToken = IERC20(rewardTokenAddresses[i]);\n uint256 balance = rewardToken.balanceOf(address(this));\n if (balance > 0) {\n emit RewardTokenCollected(\n harvesterAddress,\n address(rewardToken),\n balance\n );\n rewardToken.safeTransfer(harvesterAddress, balance);\n }\n }\n }\n\n /**\n * @dev Verifies that the caller is the Vault.\n */\n modifier onlyVault() {\n require(msg.sender == vaultAddress, \"Caller is not the Vault\");\n _;\n }\n\n /**\n * @dev Verifies that the caller is the Harvester.\n */\n modifier onlyHarvester() {\n require(msg.sender == harvesterAddress, \"Caller is not the Harvester\");\n _;\n }\n\n /**\n * @dev Verifies that the caller is the Vault or Governor.\n */\n modifier onlyVaultOrGovernor() {\n require(\n msg.sender == vaultAddress || msg.sender == governor(),\n \"Caller is not the Vault or Governor\"\n );\n _;\n }\n\n /**\n * @dev Verifies that the caller is the Vault, Governor, or Strategist.\n */\n modifier onlyVaultOrGovernorOrStrategist() {\n require(\n msg.sender == vaultAddress ||\n msg.sender == governor() ||\n msg.sender == IVault(vaultAddress).strategistAddr(),\n \"Caller is not the Vault, Governor, or Strategist\"\n );\n _;\n }\n\n /**\n * @notice Set the reward token addresses. Any old addresses will be overwritten.\n * @param _rewardTokenAddresses Array of reward token addresses\n */\n function setRewardTokenAddresses(address[] calldata _rewardTokenAddresses)\n external\n onlyGovernor\n {\n uint256 rewardTokenCount = _rewardTokenAddresses.length;\n for (uint256 i = 0; i < rewardTokenCount; ++i) {\n require(\n _rewardTokenAddresses[i] != address(0),\n \"Can not set an empty address as a reward token\"\n );\n }\n\n emit RewardTokenAddressesUpdated(\n rewardTokenAddresses,\n _rewardTokenAddresses\n );\n rewardTokenAddresses = _rewardTokenAddresses;\n }\n\n /**\n * @notice Get the reward token addresses.\n * @return address[] the reward token addresses.\n */\n function getRewardTokenAddresses()\n external\n view\n returns (address[] memory)\n {\n return rewardTokenAddresses;\n }\n\n /**\n * @notice Provide support for asset by passing its pToken address.\n * This method can only be called by the system Governor\n * @param _asset Address for the asset\n * @param _pToken Address for the corresponding platform token\n */\n function setPTokenAddress(address _asset, address _pToken)\n external\n virtual\n onlyGovernor\n {\n _setPTokenAddress(_asset, _pToken);\n }\n\n /**\n * @notice Remove a supported asset by passing its index.\n * This method can only be called by the system Governor\n * @param _assetIndex Index of the asset to be removed\n */\n function removePToken(uint256 _assetIndex) external virtual onlyGovernor {\n require(_assetIndex < assetsMapped.length, \"Invalid index\");\n address asset = assetsMapped[_assetIndex];\n address pToken = assetToPToken[asset];\n\n if (_assetIndex < assetsMapped.length - 1) {\n assetsMapped[_assetIndex] = assetsMapped[assetsMapped.length - 1];\n }\n assetsMapped.pop();\n assetToPToken[asset] = address(0);\n\n emit PTokenRemoved(asset, pToken);\n }\n\n /**\n * @notice Provide support for asset by passing its pToken address.\n * Add to internal mappings and execute the platform specific,\n * abstract method `_abstractSetPToken`\n * @param _asset Address for the asset\n * @param _pToken Address for the corresponding platform token\n */\n function _setPTokenAddress(address _asset, address _pToken) internal {\n require(assetToPToken[_asset] == address(0), \"pToken already set\");\n require(\n _asset != address(0) && _pToken != address(0),\n \"Invalid addresses\"\n );\n\n assetToPToken[_asset] = _pToken;\n assetsMapped.push(_asset);\n\n emit PTokenAdded(_asset, _pToken);\n\n _abstractSetPToken(_asset, _pToken);\n }\n\n /**\n * @notice Transfer token to governor. Intended for recovering tokens stuck in\n * strategy contracts, i.e. mistaken sends.\n * @param _asset Address for the asset\n * @param _amount Amount of the asset to transfer\n */\n function transferToken(address _asset, uint256 _amount)\n public\n onlyGovernor\n {\n require(!supportsAsset(_asset), \"Cannot transfer supported asset\");\n IERC20(_asset).safeTransfer(governor(), _amount);\n }\n\n /**\n * @notice Set the Harvester contract that can collect rewards.\n * @param _harvesterAddress Address of the harvester contract.\n */\n function setHarvesterAddress(address _harvesterAddress)\n external\n onlyGovernor\n {\n emit HarvesterAddressesUpdated(harvesterAddress, _harvesterAddress);\n harvesterAddress = _harvesterAddress;\n }\n\n /***************************************\n Abstract\n ****************************************/\n\n function _abstractSetPToken(address _asset, address _pToken)\n internal\n virtual;\n\n function safeApproveAllTokens() external virtual;\n\n /**\n * @notice Deposit an amount of assets into the platform\n * @param _asset Address for the asset\n * @param _amount Units of asset to deposit\n */\n function deposit(address _asset, uint256 _amount) external virtual;\n\n /**\n * @notice Deposit all supported assets in this strategy contract to the platform\n */\n function depositAll() external virtual;\n\n /**\n * @notice Withdraw an `amount` of assets from the platform and\n * send to the `_recipient`.\n * @param _recipient Address to which the asset should be sent\n * @param _asset Address of the asset\n * @param _amount Units of asset to withdraw\n */\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external virtual;\n\n /**\n * @notice Withdraw all supported assets from platform and\n * sends to the OToken's Vault.\n */\n function withdrawAll() external virtual;\n\n /**\n * @notice Get the total asset value held in the platform.\n * This includes any interest that was generated since depositing.\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n external\n view\n virtual\n returns (uint256 balance);\n\n /**\n * @notice Check if an asset is supported.\n * @param _asset Address of the asset\n * @return bool Whether asset is supported\n */\n function supportsAsset(address _asset) public view virtual returns (bool);\n}\n" + }, + "contracts/utils/InitializableERC20Detailed.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @dev Optional functions from the ERC20 standard.\n * Converted from openzeppelin/contracts/token/ERC20/ERC20Detailed.sol\n * @author Origin Protocol Inc\n */\nabstract contract InitializableERC20Detailed is IERC20 {\n // Storage gap to skip storage from prior to OUSD reset\n uint256[100] private _____gap;\n\n string private _name;\n string private _symbol;\n uint8 private _decimals;\n\n /**\n * @dev Sets the values for `name`, `symbol`, and `decimals`. All three of\n * these values are immutable: they can only be set once during\n * construction.\n * @notice To avoid variable shadowing appended `Arg` after arguments name.\n */\n function _initialize(\n string memory nameArg,\n string memory symbolArg,\n uint8 decimalsArg\n ) internal {\n _name = nameArg;\n _symbol = symbolArg;\n _decimals = decimalsArg;\n }\n\n /**\n * @notice Returns the name of the token.\n */\n function name() public view returns (string memory) {\n return _name;\n }\n\n /**\n * @notice Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view returns (string memory) {\n return _symbol;\n }\n\n /**\n * @notice Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5,05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei.\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view returns (uint8) {\n return _decimals;\n }\n}\n" + }, + "contracts/utils/StableMath.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { SafeMath } from \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\n\n// Based on StableMath from Stability Labs Pty. Ltd.\n// https://github.com/mstable/mStable-contracts/blob/master/contracts/shared/StableMath.sol\n\nlibrary StableMath {\n using SafeMath for uint256;\n\n /**\n * @dev Scaling unit for use in specific calculations,\n * where 1 * 10**18, or 1e18 represents a unit '1'\n */\n uint256 private constant FULL_SCALE = 1e18;\n\n /***************************************\n Helpers\n ****************************************/\n\n /**\n * @dev Adjust the scale of an integer\n * @param to Decimals to scale to\n * @param from Decimals to scale from\n */\n function scaleBy(\n uint256 x,\n uint256 to,\n uint256 from\n ) internal pure returns (uint256) {\n if (to > from) {\n x = x.mul(10**(to - from));\n } else if (to < from) {\n // slither-disable-next-line divide-before-multiply\n x = x.div(10**(from - to));\n }\n return x;\n }\n\n /***************************************\n Precise Arithmetic\n ****************************************/\n\n /**\n * @dev Multiplies two precise units, and then truncates by the full scale\n * @param x Left hand input to multiplication\n * @param y Right hand input to multiplication\n * @return Result after multiplying the two inputs and then dividing by the shared\n * scale unit\n */\n function mulTruncate(uint256 x, uint256 y) internal pure returns (uint256) {\n return mulTruncateScale(x, y, FULL_SCALE);\n }\n\n /**\n * @dev Multiplies two precise units, and then truncates by the given scale. For example,\n * when calculating 90% of 10e18, (10e18 * 9e17) / 1e18 = (9e36) / 1e18 = 9e18\n * @param x Left hand input to multiplication\n * @param y Right hand input to multiplication\n * @param scale Scale unit\n * @return Result after multiplying the two inputs and then dividing by the shared\n * scale unit\n */\n function mulTruncateScale(\n uint256 x,\n uint256 y,\n uint256 scale\n ) internal pure returns (uint256) {\n // e.g. assume scale = fullScale\n // z = 10e18 * 9e17 = 9e36\n uint256 z = x.mul(y);\n // return 9e36 / 1e18 = 9e18\n return z.div(scale);\n }\n\n /**\n * @dev Multiplies two precise units, and then truncates by the full scale, rounding up the result\n * @param x Left hand input to multiplication\n * @param y Right hand input to multiplication\n * @return Result after multiplying the two inputs and then dividing by the shared\n * scale unit, rounded up to the closest base unit.\n */\n function mulTruncateCeil(uint256 x, uint256 y)\n internal\n pure\n returns (uint256)\n {\n // e.g. 8e17 * 17268172638 = 138145381104e17\n uint256 scaled = x.mul(y);\n // e.g. 138145381104e17 + 9.99...e17 = 138145381113.99...e17\n uint256 ceil = scaled.add(FULL_SCALE.sub(1));\n // e.g. 13814538111.399...e18 / 1e18 = 13814538111\n return ceil.div(FULL_SCALE);\n }\n\n /**\n * @dev Precisely divides two units, by first scaling the left hand operand. Useful\n * for finding percentage weightings, i.e. 8e18/10e18 = 80% (or 8e17)\n * @param x Left hand input to division\n * @param y Right hand input to division\n * @return Result after multiplying the left operand by the scale, and\n * executing the division on the right hand input.\n */\n function divPrecisely(uint256 x, uint256 y)\n internal\n pure\n returns (uint256)\n {\n // e.g. 8e18 * 1e18 = 8e36\n uint256 z = x.mul(FULL_SCALE);\n // e.g. 8e36 / 10e18 = 8e17\n return z.div(y);\n }\n}\n" + }, + "contracts/vault/OETHVault.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { Vault } from \"./Vault.sol\";\n\n/**\n * @title OETH Vault Contract\n * @author Origin Protocol Inc\n */\ncontract OETHVault is Vault {\n\n}\n" + }, + "contracts/vault/OETHVaultAdmin.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { IStrategy } from \"../interfaces/IStrategy.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { VaultAdmin } from \"./VaultAdmin.sol\";\n\n/**\n * @title OETH VaultAdmin Contract\n * @author Origin Protocol Inc\n */\ncontract OETHVaultAdmin is VaultAdmin {\n using SafeERC20 for IERC20;\n\n address public immutable weth;\n\n constructor(address _weth) {\n weth = _weth;\n }\n\n /// @dev Simplified version of the deposit function as WETH is the only supported asset.\n function _depositToStrategy(\n address _strategyToAddress,\n address[] calldata _assets,\n uint256[] calldata _amounts\n ) internal override {\n require(\n strategies[_strategyToAddress].isSupported,\n \"Invalid to Strategy\"\n );\n require(\n _assets.length == 1 && _amounts.length == 1 && _assets[0] == weth,\n \"Only WETH is supported\"\n );\n\n // Check the there is enough WETH to transfer once the WETH reserved for the withdrawal queue is accounted for\n require(_amounts[0] <= _wethAvailable(), \"Not enough WETH available\");\n\n // Send required amount of funds to the strategy\n IERC20(weth).safeTransfer(_strategyToAddress, _amounts[0]);\n\n // Deposit all the funds that have been sent to the strategy\n IStrategy(_strategyToAddress).depositAll();\n }\n\n function _withdrawFromStrategy(\n address _recipient,\n address _strategyFromAddress,\n address[] calldata _assets,\n uint256[] calldata _amounts\n ) internal override {\n super._withdrawFromStrategy(\n _recipient,\n _strategyFromAddress,\n _assets,\n _amounts\n );\n\n IVault(address(this)).addWithdrawalQueueLiquidity();\n }\n\n function _withdrawAllFromStrategy(address _strategyAddr) internal override {\n super._withdrawAllFromStrategy(_strategyAddr);\n\n IVault(address(this)).addWithdrawalQueueLiquidity();\n }\n\n function _withdrawAllFromStrategies() internal override {\n super._withdrawAllFromStrategies();\n\n IVault(address(this)).addWithdrawalQueueLiquidity();\n }\n\n // TODO move to a library?\n function _wethAvailable() internal view returns (uint256 wethAvailable) {\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\n\n // Check if the claimable WETH is less than the queued amount\n uint256 queueShortfall = queue.queued - queue.claimable;\n uint256 wethBalance = IERC20(weth).balanceOf(address(this));\n // Of the claimable withdrawal requests, how much is unclaimed?\n uint256 unclaimed = queue.claimable - queue.claimed;\n\n if (wethBalance > queueShortfall + unclaimed) {\n wethAvailable = wethBalance - queueShortfall - unclaimed;\n }\n }\n\n function _swapCollateral(\n address _fromAsset,\n address _toAsset,\n uint256 _fromAssetAmount,\n uint256 _minToAssetAmount,\n bytes calldata _data\n ) internal override returns (uint256 toAssetAmount) {\n require(_fromAsset != weth, \"swap from WETH not supported\");\n require(_toAsset == weth, \"only swap to WETH\");\n toAssetAmount = super._swapCollateral(\n _fromAsset,\n _toAsset,\n _fromAssetAmount,\n _minToAssetAmount,\n _data\n );\n\n // Add any new WETH to the withdrawal queue first\n IVault(address(this)).addWithdrawalQueueLiquidity();\n }\n}\n" + }, + "contracts/vault/OETHVaultCore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { VaultCore } from \"./VaultCore.sol\";\n\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IStrategy } from \"../interfaces/IStrategy.sol\";\nimport { IDripper } from \"../interfaces/IDripper.sol\";\n\n/**\n * @title OETH VaultCore Contract\n * @author Origin Protocol Inc\n */\ncontract OETHVaultCore is VaultCore {\n using SafeERC20 for IERC20;\n using StableMath for uint256;\n\n address public immutable weth;\n uint256 public wethAssetIndex;\n\n constructor(address _weth) {\n weth = _weth;\n }\n\n /**\n * @dev Caches WETH's index in `allAssets` variable.\n * Reduces gas usage by redeem by caching that.\n */\n function cacheWETHAssetIndex() external onlyGovernor {\n uint256 assetCount = allAssets.length;\n for (uint256 i = 0; i < assetCount; ++i) {\n if (allAssets[i] == weth) {\n wethAssetIndex = i;\n break;\n }\n }\n\n require(allAssets[wethAssetIndex] == weth, \"Invalid WETH Asset Index\");\n }\n\n // @inheritdoc VaultCore\n // slither-disable-start reentrancy-no-eth\n function _mint(\n address _asset,\n uint256 _amount,\n uint256 _minimumOusdAmount\n ) internal virtual override {\n require(_asset == weth, \"Unsupported asset for minting\");\n require(_amount > 0, \"Amount must be greater than 0\");\n require(\n _amount >= _minimumOusdAmount,\n \"Mint amount lower than minimum\"\n );\n\n emit Mint(msg.sender, _amount);\n\n // Rebase must happen before any transfers occur.\n if (!rebasePaused && _amount >= rebaseThreshold) {\n // Stream any harvested rewards (WETH) that are available to the Vault\n IDripper(dripper).collect();\n\n _rebase();\n }\n\n // Mint oTokens\n oUSD.mint(msg.sender, _amount);\n\n // Transfer the deposited coins to the vault\n IERC20(_asset).safeTransferFrom(msg.sender, address(this), _amount);\n\n // Give priority to the withdrawal queue for the new WETH liquidity\n _addWithdrawalQueueLiquidity();\n\n // Auto-allocate if necessary\n if (_amount >= autoAllocateThreshold) {\n _allocate();\n }\n }\n\n // slither-disable-end reentrancy-no-eth\n\n // @inheritdoc VaultCore\n function _calculateRedeemOutputs(uint256 _amount)\n internal\n view\n virtual\n override\n returns (uint256[] memory outputs)\n {\n // Overrides `VaultCore._calculateRedeemOutputs` to redeem with only\n // WETH instead of LST-mix. Doesn't change the function signature\n // for backward compatibility\n\n // Calculate redeem fee\n if (redeemFeeBps > 0) {\n uint256 redeemFee = _amount.mulTruncateScale(redeemFeeBps, 1e4);\n _amount = _amount - redeemFee;\n }\n\n // Ensure that the WETH index is cached\n uint256 _wethAssetIndex = wethAssetIndex;\n require(\n allAssets[_wethAssetIndex] == weth,\n \"WETH Asset index not cached\"\n );\n\n outputs = new uint256[](allAssets.length);\n outputs[_wethAssetIndex] = _amount;\n }\n\n // @inheritdoc VaultCore\n function _redeem(uint256 _amount, uint256 _minimumUnitAmount)\n internal\n virtual\n override\n {\n // Override `VaultCore._redeem` to simplify it. Gets rid of oracle\n // usage and looping through all assets for LST-mix redeem. Instead\n // does a simple WETH-only redeem.\n emit Redeem(msg.sender, _amount);\n\n if (_amount == 0) {\n return;\n }\n\n // Amount excluding fees\n uint256 amountMinusFee = _calculateRedeemOutputs(_amount)[\n wethAssetIndex\n ];\n\n require(\n amountMinusFee >= _minimumUnitAmount,\n \"Redeem amount lower than minimum\"\n );\n\n // If there is any WETH in the Vault available after accounting for the withdrawal queue\n if (_wethAvailable() >= amountMinusFee) {\n // Use Vault funds first if sufficient\n IERC20(weth).safeTransfer(msg.sender, amountMinusFee);\n } else {\n address strategyAddr = assetDefaultStrategies[weth];\n if (strategyAddr != address(0)) {\n // Nothing in Vault, but something in Strategy, send from there\n IStrategy strategy = IStrategy(strategyAddr);\n strategy.withdraw(msg.sender, weth, amountMinusFee);\n } else {\n // Cant find funds anywhere\n revert(\"Liquidity error\");\n }\n }\n\n // Burn OETH from user (including fees)\n oUSD.burn(msg.sender, _amount);\n\n _postRedeem(_amount);\n }\n\n /**\n * @notice Request an asynchronous withdrawal of the underlying asset. eg WETH\n * @param _amount Amount of oTokens to burn. eg OETH\n * @param requestId Unique ID for the withdrawal request\n * @param queued Cumulative total of all WETH queued including already claimed requests.\n * This request can be claimed once the withdrawal queue's claimable amount\n * is greater than or equal this request's queued amount.\n */\n function requestWithdrawal(uint256 _amount)\n external\n whenNotCapitalPaused\n nonReentrant\n returns (uint256 requestId, uint256 queued)\n {\n // Burn the user's OETH\n // This also checks the requester has enough OETH to burn\n oUSD.burn(msg.sender, _amount);\n\n requestId = withdrawalQueueMetadata.nextWithdrawalIndex;\n queued = withdrawalQueueMetadata.queued + _amount;\n\n // store the next withdrawal request\n withdrawalQueueMetadata.nextWithdrawalIndex = uint128(requestId + 1);\n withdrawalQueueMetadata.queued = uint128(queued);\n\n emit WithdrawalRequested(msg.sender, requestId, _amount, queued);\n\n withdrawalRequests[requestId] = WithdrawalRequest({\n withdrawer: msg.sender,\n claimed: false,\n amount: uint128(_amount),\n queued: uint128(queued)\n });\n }\n\n /**\n * @notice Claim a previously requested withdrawal once it is claimable.\n * @param requestId Unique ID for the withdrawal request\n * @return amount Amount of WETH transferred to the withdrawer\n */\n function claimWithdrawal(uint256 requestId)\n external\n whenNotCapitalPaused\n nonReentrant\n returns (uint256 amount)\n {\n amount = _claimWithdrawal(requestId);\n\n // transfer WETH from the vault to the withdrawer\n IERC20(weth).safeTransfer(msg.sender, amount);\n }\n\n /**\n * @notice Claim a previously requested withdrawals once they are claimable.\n * @param requestIds Unique ID of each withdrawal request\n * @return amounts Amount of WETH received for each request\n */\n function claimWithdrawals(uint256[] memory requestIds)\n external\n whenNotCapitalPaused\n nonReentrant\n returns (uint256[] memory amounts, uint256 totalAmount)\n {\n amounts = new uint256[](requestIds.length);\n for (uint256 i = 0; i < requestIds.length; ++i) {\n amounts[i] = _claimWithdrawal(requestIds[i]);\n totalAmount += amounts[i];\n }\n\n // transfer all the claimed WETH from the vault to the withdrawer\n IERC20(weth).safeTransfer(msg.sender, totalAmount);\n }\n\n // slither-disable-start reentrancy-no-eth\n\n function _claimWithdrawal(uint256 requestId)\n internal\n returns (uint256 amount)\n {\n // Check if there's enough liquidity to cover the withdrawal request\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\n WithdrawalRequest memory request = withdrawalRequests[requestId];\n\n require(request.claimed == false, \"already claimed\");\n require(request.withdrawer == msg.sender, \"not requester\");\n\n // Try and get more liquidity in the withdrawal queue if there is not enough\n if (request.queued > queue.claimable) {\n // Stream any harvested rewards (WETH) that are available to the Vault\n IDripper(dripper).collect();\n\n // Add any WETH from the Dripper to the withdrawal queue\n uint256 addedClaimable = _addWithdrawalQueueLiquidity();\n\n // If there still isn't enough liquidity in the queue to claim, revert\n require(\n request.queued <= queue.claimable + addedClaimable,\n \"queue pending liquidity\"\n );\n }\n\n // Store the updated claimed amount\n withdrawalQueueMetadata.claimed = queue.claimed + request.amount;\n // Store the request as claimed\n withdrawalRequests[requestId].claimed = true;\n\n emit WithdrawalClaimed(msg.sender, requestId, request.amount);\n\n return request.amount;\n }\n\n // slither-disable-end reentrancy-no-eth\n\n /// @notice Collects harvested rewards from the Dripper as WETH then\n /// adds WETH to the withdrawal queue if there is a funding shortfall.\n /// @dev is called from the Native Staking strategy when validator withdrawals are processed.\n /// It also called before any WETH is allocated to a strategy.\n function addWithdrawalQueueLiquidity() external {\n // Stream any harvested rewards (WETH) that are available to the Vault\n IDripper(dripper).collect();\n\n _addWithdrawalQueueLiquidity();\n }\n\n /// @dev Adds WETH to the withdrawal queue if there is a funding shortfall.\n function _addWithdrawalQueueLiquidity()\n internal\n returns (uint256 addedClaimable)\n {\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\n\n // Check if the claimable WETH is less than the queued amount\n uint256 queueShortfall = queue.queued - queue.claimable;\n\n // No need to get WETH balance if all the withdrawal requests are claimable\n if (queueShortfall > 0) {\n uint256 wethBalance = IERC20(weth).balanceOf(address(this));\n\n // Of the claimable withdrawal requests, how much is unclaimed?\n uint256 unclaimed = queue.claimable - queue.claimed;\n if (wethBalance > unclaimed) {\n uint256 unallocatedWeth = wethBalance - unclaimed;\n\n // the new claimable amount is the smaller of the queue shortfall or unallocated weth\n addedClaimable = queueShortfall < unallocatedWeth\n ? queueShortfall\n : unallocatedWeth;\n uint256 newClaimable = queue.claimable + addedClaimable;\n\n // Store the new claimable amount back to storage\n withdrawalQueueMetadata.claimable = uint128(newClaimable);\n\n // emit a WithdrawalClaimable event\n emit WithdrawalClaimable(newClaimable, addedClaimable);\n }\n }\n }\n\n /***************************************\n View Functions\n ****************************************/\n\n function _wethAvailable() internal view returns (uint256 wethAvailable) {\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\n\n // Check if the claimable WETH is less than the queued amount\n uint256 queueShortfall = queue.queued - queue.claimable;\n uint256 wethBalance = IERC20(weth).balanceOf(address(this));\n // Of the claimable withdrawal requests, how much is unclaimed?\n uint256 unclaimed = queue.claimable - queue.claimed;\n\n if (wethBalance > queueShortfall + unclaimed) {\n wethAvailable = wethBalance - queueShortfall - unclaimed;\n }\n }\n\n function _checkBalance(address _asset)\n internal\n view\n override\n returns (uint256 balance)\n {\n balance = super._checkBalance(_asset);\n\n if (_asset == weth) {\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\n // Need to remove WETH that is reserved for the withdrawal queue\n return balance + queue.claimed - queue.queued;\n }\n }\n\n function _allocate() internal override {\n // Add any unallocated WETH to the withdrawal queue first\n _addWithdrawalQueueLiquidity();\n\n super._allocate();\n }\n\n function _totalValue() internal view override returns (uint256 value) {\n value = super._totalValue();\n\n // Need to remove WETH that is reserved for the withdrawal queue.\n // reserved for the withdrawal queue = cumulative queued total - total claimed\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\n value = value + queue.claimed - queue.queued;\n }\n}\n" + }, + "contracts/vault/OETHZapper.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { IWETH9 } from \"../interfaces/IWETH9.sol\";\nimport { ISfrxETH } from \"../interfaces/ISfrxETH.sol\";\n\ncontract OETHZapper {\n IERC20 public immutable oeth;\n IVault public immutable vault;\n\n IWETH9 public constant weth =\n IWETH9(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);\n IERC20 public constant frxeth =\n IERC20(0x5E8422345238F34275888049021821E8E08CAa1f);\n ISfrxETH public constant sfrxeth =\n ISfrxETH(0xac3E018457B222d93114458476f3E3416Abbe38F);\n address private constant ETH_MARKER =\n 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n event Zap(address indexed minter, address indexed asset, uint256 amount);\n\n constructor(address _oeth, address _vault) {\n oeth = IERC20(_oeth);\n vault = IVault(_vault);\n\n weth.approve(address(_vault), type(uint256).max);\n frxeth.approve(address(_vault), type(uint256).max);\n }\n\n /**\n * @dev Deposit ETH and receive OETH in return.\n * Will verify that the user is sent 1:1 for ETH.\n */\n receive() external payable {\n deposit();\n }\n\n /**\n * @dev Deposit ETH and receive OETH in return\n * Will verify that the user is sent 1:1 for ETH.\n * @return Amount of OETH sent to user\n */\n function deposit() public payable returns (uint256) {\n uint256 balance = address(this).balance;\n weth.deposit{ value: balance }();\n emit Zap(msg.sender, ETH_MARKER, balance);\n return _mint(address(weth), balance);\n }\n\n /**\n * @dev Deposit SFRXETH to the vault and receive OETH in return\n * @param amount Amount of SFRXETH to deposit\n * @param minOETH Minimum amount of OETH to receive\n * @return Amount of OETH sent to user\n */\n function depositSFRXETH(uint256 amount, uint256 minOETH)\n external\n returns (uint256)\n {\n sfrxeth.redeem(amount, address(this), msg.sender);\n emit Zap(msg.sender, address(sfrxeth), amount);\n return _mint(address(frxeth), minOETH);\n }\n\n /**\n * @dev Internal function to mint OETH from an asset\n * @param asset Address of asset for the vault to mint from\n * @param minOETH Minimum amount of OETH to for user to receive\n * @return Amount of OETH sent to user\n */\n function _mint(address asset, uint256 minOETH) internal returns (uint256) {\n uint256 toMint = IERC20(asset).balanceOf(address(this));\n vault.mint(asset, toMint, minOETH);\n uint256 mintedAmount = oeth.balanceOf(address(this));\n require(mintedAmount >= minOETH, \"Zapper: not enough minted\");\n require(oeth.transfer(msg.sender, mintedAmount));\n return mintedAmount;\n }\n}\n" + }, + "contracts/vault/Vault.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title OUSD VaultInitializer Contract\n * @notice The VaultInitializer sets up the initial contract.\n * @author Origin Protocol Inc\n */\nimport { VaultInitializer } from \"./VaultInitializer.sol\";\nimport { VaultAdmin } from \"./VaultAdmin.sol\";\n\ncontract Vault is VaultInitializer, VaultAdmin {}\n" + }, + "contracts/vault/VaultAdmin.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title OToken VaultAdmin contract\n * @notice The VaultAdmin contract makes configuration and admin calls on the vault.\n * @author Origin Protocol Inc\n */\n\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { IOracle } from \"../interfaces/IOracle.sol\";\nimport { ISwapper } from \"../interfaces/ISwapper.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\n\nimport \"./VaultStorage.sol\";\n\ncontract VaultAdmin is VaultStorage {\n using SafeERC20 for IERC20;\n using StableMath for uint256;\n\n /**\n * @dev Verifies that the caller is the Governor or Strategist.\n */\n modifier onlyGovernorOrStrategist() {\n require(\n msg.sender == strategistAddr || isGovernor(),\n \"Caller is not the Strategist or Governor\"\n );\n _;\n }\n\n /***************************************\n Configuration\n ****************************************/\n\n /**\n * @notice Set address of price provider.\n * @param _priceProvider Address of price provider\n */\n function setPriceProvider(address _priceProvider) external onlyGovernor {\n priceProvider = _priceProvider;\n emit PriceProviderUpdated(_priceProvider);\n }\n\n /**\n * @notice Set a fee in basis points to be charged for a redeem.\n * @param _redeemFeeBps Basis point fee to be charged\n */\n function setRedeemFeeBps(uint256 _redeemFeeBps) external onlyGovernor {\n require(_redeemFeeBps <= 1000, \"Redeem fee should not be over 10%\");\n redeemFeeBps = _redeemFeeBps;\n emit RedeemFeeUpdated(_redeemFeeBps);\n }\n\n /**\n * @notice Set a buffer of assets to keep in the Vault to handle most\n * redemptions without needing to spend gas unwinding assets from a Strategy.\n * @param _vaultBuffer Percentage using 18 decimals. 100% = 1e18.\n */\n function setVaultBuffer(uint256 _vaultBuffer)\n external\n onlyGovernorOrStrategist\n {\n require(_vaultBuffer <= 1e18, \"Invalid value\");\n vaultBuffer = _vaultBuffer;\n emit VaultBufferUpdated(_vaultBuffer);\n }\n\n /**\n * @notice Sets the minimum amount of OTokens in a mint to trigger an\n * automatic allocation of funds afterwords.\n * @param _threshold OToken amount with 18 fixed decimals.\n */\n function setAutoAllocateThreshold(uint256 _threshold)\n external\n onlyGovernor\n {\n autoAllocateThreshold = _threshold;\n emit AllocateThresholdUpdated(_threshold);\n }\n\n /**\n * @notice Set a minimum amount of OTokens in a mint or redeem that triggers a\n * rebase\n * @param _threshold OToken amount with 18 fixed decimals.\n */\n function setRebaseThreshold(uint256 _threshold) external onlyGovernor {\n rebaseThreshold = _threshold;\n emit RebaseThresholdUpdated(_threshold);\n }\n\n /**\n * @notice Set address of Strategist\n * @param _address Address of Strategist\n */\n function setStrategistAddr(address _address) external onlyGovernor {\n strategistAddr = _address;\n emit StrategistUpdated(_address);\n }\n\n /**\n * @notice Set the default Strategy for an asset, i.e. the one which the asset\n will be automatically allocated to and withdrawn from\n * @param _asset Address of the asset\n * @param _strategy Address of the Strategy\n */\n function setAssetDefaultStrategy(address _asset, address _strategy)\n external\n onlyGovernorOrStrategist\n {\n emit AssetDefaultStrategyUpdated(_asset, _strategy);\n // If its a zero address being passed for the strategy we are removing\n // the default strategy\n if (_strategy != address(0)) {\n // Make sure the strategy meets some criteria\n require(strategies[_strategy].isSupported, \"Strategy not approved\");\n IStrategy strategy = IStrategy(_strategy);\n require(assets[_asset].isSupported, \"Asset is not supported\");\n require(\n strategy.supportsAsset(_asset),\n \"Asset not supported by Strategy\"\n );\n }\n assetDefaultStrategies[_asset] = _strategy;\n }\n\n /**\n * @notice Set maximum amount of OTokens that can at any point be minted and deployed\n * to strategy (used only by ConvexOUSDMetaStrategy for now).\n * @param _threshold OToken amount with 18 fixed decimals.\n */\n function setNetOusdMintForStrategyThreshold(uint256 _threshold)\n external\n onlyGovernor\n {\n /**\n * Because `netOusdMintedForStrategy` check in vault core works both ways\n * (positive and negative) the actual impact of the amount of OToken minted\n * could be double the threshold. E.g.:\n * - contract has threshold set to 100\n * - state of netOusdMinted is -90\n * - in effect it can mint 190 OToken and still be within limits\n *\n * We are somewhat mitigating this behaviour by resetting the netOusdMinted\n * counter whenever new threshold is set. So it can only move one threshold\n * amount in each direction. This also enables us to reduce the threshold\n * amount and not have problems with current netOusdMinted being near\n * limits on either side.\n */\n netOusdMintedForStrategy = 0;\n netOusdMintForStrategyThreshold = _threshold;\n emit NetOusdMintForStrategyThresholdChanged(_threshold);\n }\n\n /**\n * @notice Set the Dripper contract that streams harvested rewards to the vault.\n * @param _dripper Address of the Dripper contract.\n */\n function setDripper(address _dripper) external onlyGovernor {\n dripper = _dripper;\n emit DripperChanged(_dripper);\n }\n\n /***************************************\n Swaps\n ****************************************/\n\n /**\n * @notice Strategist swaps collateral assets sitting in the vault.\n * @param _fromAsset The token address of the asset being sold by the vault.\n * @param _toAsset The token address of the asset being purchased by the vault.\n * @param _fromAssetAmount The amount of assets being sold by the vault.\n * @param _minToAssetAmount The minimum amount of assets to be purchased.\n * @param _data implementation specific data. eg 1Inch swap data\n * @return toAssetAmount The amount of toAssets that was received from the swap\n */\n function swapCollateral(\n address _fromAsset,\n address _toAsset,\n uint256 _fromAssetAmount,\n uint256 _minToAssetAmount,\n bytes calldata _data\n )\n external\n nonReentrant\n onlyGovernorOrStrategist\n returns (uint256 toAssetAmount)\n {\n toAssetAmount = _swapCollateral(\n _fromAsset,\n _toAsset,\n _fromAssetAmount,\n _minToAssetAmount,\n _data\n );\n }\n\n function _swapCollateral(\n address _fromAsset,\n address _toAsset,\n uint256 _fromAssetAmount,\n uint256 _minToAssetAmount,\n bytes calldata _data\n ) internal virtual returns (uint256 toAssetAmount) {\n // Check fromAsset and toAsset are valid\n Asset memory fromAssetConfig = assets[address(_fromAsset)];\n Asset memory toAssetConfig = assets[_toAsset];\n require(fromAssetConfig.isSupported, \"From asset is not supported\");\n require(toAssetConfig.isSupported, \"To asset is not supported\");\n\n // Load swap config into memory to avoid separate SLOADs\n SwapConfig memory config = swapConfig;\n\n // Scope a new block to remove toAssetBalBefore from the scope of swapCollateral.\n // This avoids a stack too deep error.\n {\n uint256 toAssetBalBefore = IERC20(_toAsset).balanceOf(\n address(this)\n );\n\n // Transfer from assets to the swapper contract\n IERC20(_fromAsset).safeTransfer(config.swapper, _fromAssetAmount);\n\n // Call to the Swapper contract to do the actual swap\n // The -1 is required for stETH which sometimes transfers 1 wei less than what was specified.\n // slither-disable-next-line unused-return\n ISwapper(config.swapper).swap(\n _fromAsset,\n _toAsset,\n _fromAssetAmount - 1,\n _minToAssetAmount,\n _data\n );\n\n // Compute the change in asset balance held by the Vault\n toAssetAmount =\n IERC20(_toAsset).balanceOf(address(this)) -\n toAssetBalBefore;\n }\n\n // Check the to assets returned is above slippage amount specified by the strategist\n require(\n toAssetAmount >= _minToAssetAmount,\n \"Strategist slippage limit\"\n );\n\n // Scope a new block to remove minOracleToAssetAmount from the scope of swapCollateral.\n // This avoids a stack too deep error.\n {\n // Check the slippage against the Oracle in case the strategist made a mistake or has become malicious.\n // to asset amount = from asset amount * from asset price / to asset price\n uint256 minOracleToAssetAmount = (_fromAssetAmount *\n (1e4 - fromAssetConfig.allowedOracleSlippageBps) *\n IOracle(priceProvider).price(_fromAsset)) /\n (IOracle(priceProvider).price(_toAsset) *\n (1e4 + toAssetConfig.allowedOracleSlippageBps));\n\n // Scale both sides up to 18 decimals to compare\n require(\n toAssetAmount.scaleBy(18, toAssetConfig.decimals) >=\n minOracleToAssetAmount.scaleBy(\n 18,\n fromAssetConfig.decimals\n ),\n \"Oracle slippage limit exceeded\"\n );\n }\n\n // Check the vault's total value hasn't gone below the OToken total supply\n // by more than the allowed percentage.\n require(\n IVault(address(this)).totalValue() >=\n (oUSD.totalSupply() * ((1e4 - config.allowedUndervalueBps))) /\n 1e4,\n \"Allowed value < supply\"\n );\n\n emit Swapped(_fromAsset, _toAsset, _fromAssetAmount, toAssetAmount);\n }\n\n /***************************************\n Swap Config\n ****************************************/\n\n /**\n * @notice Set the contract the performs swaps of collateral assets.\n * @param _swapperAddr Address of the Swapper contract that implements the ISwapper interface.\n */\n function setSwapper(address _swapperAddr) external onlyGovernor {\n swapConfig.swapper = _swapperAddr;\n emit SwapperChanged(_swapperAddr);\n }\n\n /// @notice Contract that swaps the vault's collateral assets\n function swapper() external view returns (address swapper_) {\n swapper_ = swapConfig.swapper;\n }\n\n /**\n * @notice Set max allowed percentage the vault total value can drop below the OToken total supply in basis points\n * when executing collateral swaps.\n * @param _basis Percentage in basis points. eg 100 == 1%\n */\n function setSwapAllowedUndervalue(uint16 _basis) external onlyGovernor {\n require(_basis < 10001, \"Invalid basis points\");\n swapConfig.allowedUndervalueBps = _basis;\n emit SwapAllowedUndervalueChanged(_basis);\n }\n\n /**\n * @notice Max allowed percentage the vault total value can drop below the OToken total supply in basis points\n * when executing a collateral swap.\n * For example 100 == 1%\n * @return value Percentage in basis points.\n */\n function allowedSwapUndervalue() external view returns (uint256 value) {\n value = swapConfig.allowedUndervalueBps;\n }\n\n /**\n * @notice Set the allowed slippage from the Oracle price for collateral asset swaps.\n * @param _asset Address of the asset token.\n * @param _allowedOracleSlippageBps allowed slippage from Oracle in basis points. eg 20 = 0.2%. Max 10%.\n */\n function setOracleSlippage(address _asset, uint16 _allowedOracleSlippageBps)\n external\n onlyGovernor\n {\n require(assets[_asset].isSupported, \"Asset not supported\");\n require(_allowedOracleSlippageBps < 1000, \"Slippage too high\");\n\n assets[_asset].allowedOracleSlippageBps = _allowedOracleSlippageBps;\n\n emit SwapSlippageChanged(_asset, _allowedOracleSlippageBps);\n }\n\n /***************************************\n Asset Config\n ****************************************/\n\n /**\n * @notice Add a supported asset to the contract, i.e. one that can be\n * to mint OTokens.\n * @param _asset Address of asset\n */\n function supportAsset(address _asset, uint8 _unitConversion)\n external\n onlyGovernor\n {\n require(!assets[_asset].isSupported, \"Asset already supported\");\n\n assets[_asset] = Asset({\n isSupported: true,\n unitConversion: UnitConversion(_unitConversion),\n decimals: 0, // will be overridden in _cacheDecimals\n allowedOracleSlippageBps: 0 // 0% by default\n });\n\n _cacheDecimals(_asset);\n allAssets.push(_asset);\n\n // Verify that our oracle supports the asset\n // slither-disable-next-line unused-return\n IOracle(priceProvider).price(_asset);\n\n emit AssetSupported(_asset);\n }\n\n /**\n * @notice Remove a supported asset from the Vault\n * @param _asset Address of asset\n */\n function removeAsset(address _asset) external onlyGovernor {\n require(assets[_asset].isSupported, \"Asset not supported\");\n require(\n IVault(address(this)).checkBalance(_asset) <= 1e13,\n \"Vault still holds asset\"\n );\n\n uint256 assetsCount = allAssets.length;\n uint256 assetIndex = assetsCount; // initialize at invaid index\n for (uint256 i = 0; i < assetsCount; ++i) {\n if (allAssets[i] == _asset) {\n assetIndex = i;\n break;\n }\n }\n\n // Note: If asset is not found in `allAssets`, the following line\n // will revert with an out-of-bound error. However, there's no\n // reason why an asset would have `Asset.isSupported = true` but\n // not exist in `allAssets`.\n\n // Update allAssets array\n allAssets[assetIndex] = allAssets[assetsCount - 1];\n allAssets.pop();\n\n // Reset default strategy\n assetDefaultStrategies[_asset] = address(0);\n emit AssetDefaultStrategyUpdated(_asset, address(0));\n\n // Remove asset from storage\n delete assets[_asset];\n\n emit AssetRemoved(_asset);\n }\n\n /**\n * @notice Cache decimals on OracleRouter for a particular asset. This action\n * is required before that asset's price can be accessed.\n * @param _asset Address of asset token\n */\n function cacheDecimals(address _asset) external onlyGovernor {\n _cacheDecimals(_asset);\n }\n\n /***************************************\n Strategy Config\n ****************************************/\n\n /**\n * @notice Add a strategy to the Vault.\n * @param _addr Address of the strategy to add\n */\n function approveStrategy(address _addr) external onlyGovernor {\n require(!strategies[_addr].isSupported, \"Strategy already approved\");\n strategies[_addr] = Strategy({ isSupported: true, _deprecated: 0 });\n allStrategies.push(_addr);\n emit StrategyApproved(_addr);\n }\n\n /**\n * @notice Remove a strategy from the Vault.\n * @param _addr Address of the strategy to remove\n */\n\n function removeStrategy(address _addr) external onlyGovernor {\n require(strategies[_addr].isSupported, \"Strategy not approved\");\n\n uint256 assetCount = allAssets.length;\n for (uint256 i = 0; i < assetCount; ++i) {\n require(\n assetDefaultStrategies[allAssets[i]] != _addr,\n \"Strategy is default for an asset\"\n );\n }\n\n // Initialize strategyIndex with out of bounds result so function will\n // revert if no valid index found\n uint256 stratCount = allStrategies.length;\n uint256 strategyIndex = stratCount;\n for (uint256 i = 0; i < stratCount; ++i) {\n if (allStrategies[i] == _addr) {\n strategyIndex = i;\n break;\n }\n }\n\n if (strategyIndex < stratCount) {\n allStrategies[strategyIndex] = allStrategies[stratCount - 1];\n allStrategies.pop();\n\n // Mark the strategy as not supported\n strategies[_addr].isSupported = false;\n\n // Withdraw all assets\n IStrategy strategy = IStrategy(_addr);\n strategy.withdrawAll();\n\n emit StrategyRemoved(_addr);\n }\n }\n\n /***************************************\n Strategies\n ****************************************/\n\n /**\n * @notice Deposit multiple assets from the vault into the strategy.\n * @param _strategyToAddress Address of the Strategy to deposit assets into.\n * @param _assets Array of asset address that will be deposited into the strategy.\n * @param _amounts Array of amounts of each corresponding asset to deposit.\n */\n function depositToStrategy(\n address _strategyToAddress,\n address[] calldata _assets,\n uint256[] calldata _amounts\n ) external onlyGovernorOrStrategist nonReentrant {\n _depositToStrategy(_strategyToAddress, _assets, _amounts);\n }\n\n function _depositToStrategy(\n address _strategyToAddress,\n address[] calldata _assets,\n uint256[] calldata _amounts\n ) internal virtual {\n require(\n strategies[_strategyToAddress].isSupported,\n \"Invalid to Strategy\"\n );\n require(_assets.length == _amounts.length, \"Parameter length mismatch\");\n\n uint256 assetCount = _assets.length;\n for (uint256 i = 0; i < assetCount; ++i) {\n address assetAddr = _assets[i];\n require(\n IStrategy(_strategyToAddress).supportsAsset(assetAddr),\n \"Asset unsupported\"\n );\n // Send required amount of funds to the strategy\n IERC20(assetAddr).safeTransfer(_strategyToAddress, _amounts[i]);\n }\n\n // Deposit all the funds that have been sent to the strategy\n IStrategy(_strategyToAddress).depositAll();\n }\n\n /**\n * @notice Withdraw multiple assets from the strategy to the vault.\n * @param _strategyFromAddress Address of the Strategy to withdraw assets from.\n * @param _assets Array of asset address that will be withdrawn from the strategy.\n * @param _amounts Array of amounts of each corresponding asset to withdraw.\n */\n function withdrawFromStrategy(\n address _strategyFromAddress,\n address[] calldata _assets,\n uint256[] calldata _amounts\n ) external onlyGovernorOrStrategist nonReentrant {\n _withdrawFromStrategy(\n address(this),\n _strategyFromAddress,\n _assets,\n _amounts\n );\n }\n\n /**\n * @param _recipient can either be a strategy or the Vault\n */\n function _withdrawFromStrategy(\n address _recipient,\n address _strategyFromAddress,\n address[] calldata _assets,\n uint256[] calldata _amounts\n ) internal virtual {\n require(\n strategies[_strategyFromAddress].isSupported,\n \"Invalid from Strategy\"\n );\n require(_assets.length == _amounts.length, \"Parameter length mismatch\");\n\n uint256 assetCount = _assets.length;\n for (uint256 i = 0; i < assetCount; ++i) {\n // Withdraw from Strategy to the recipient\n IStrategy(_strategyFromAddress).withdraw(\n _recipient,\n _assets[i],\n _amounts[i]\n );\n }\n }\n\n /**\n * @notice Sets the maximum allowable difference between\n * total supply and backing assets' value.\n */\n function setMaxSupplyDiff(uint256 _maxSupplyDiff) external onlyGovernor {\n maxSupplyDiff = _maxSupplyDiff;\n emit MaxSupplyDiffChanged(_maxSupplyDiff);\n }\n\n /**\n * @notice Sets the trusteeAddress that can receive a portion of yield.\n * Setting to the zero address disables this feature.\n */\n function setTrusteeAddress(address _address) external onlyGovernor {\n trusteeAddress = _address;\n emit TrusteeAddressChanged(_address);\n }\n\n /**\n * @notice Sets the TrusteeFeeBps to the percentage of yield that should be\n * received in basis points.\n */\n function setTrusteeFeeBps(uint256 _basis) external onlyGovernor {\n require(_basis <= 5000, \"basis cannot exceed 50%\");\n trusteeFeeBps = _basis;\n emit TrusteeFeeBpsChanged(_basis);\n }\n\n /**\n * @notice Set OToken Metapool strategy\n * @param _ousdMetaStrategy Address of OToken metapool strategy\n */\n function setOusdMetaStrategy(address _ousdMetaStrategy)\n external\n onlyGovernor\n {\n ousdMetaStrategy = _ousdMetaStrategy;\n emit OusdMetaStrategyUpdated(_ousdMetaStrategy);\n }\n\n /***************************************\n Pause\n ****************************************/\n\n /**\n * @notice Set the deposit paused flag to true to prevent rebasing.\n */\n function pauseRebase() external onlyGovernorOrStrategist {\n rebasePaused = true;\n emit RebasePaused();\n }\n\n /**\n * @notice Set the deposit paused flag to true to allow rebasing.\n */\n function unpauseRebase() external onlyGovernorOrStrategist {\n rebasePaused = false;\n emit RebaseUnpaused();\n }\n\n /**\n * @notice Set the deposit paused flag to true to prevent capital movement.\n */\n function pauseCapital() external onlyGovernorOrStrategist {\n capitalPaused = true;\n emit CapitalPaused();\n }\n\n /**\n * @notice Set the deposit paused flag to false to enable capital movement.\n */\n function unpauseCapital() external onlyGovernorOrStrategist {\n capitalPaused = false;\n emit CapitalUnpaused();\n }\n\n /***************************************\n Utils\n ****************************************/\n\n /**\n * @notice Transfer token to governor. Intended for recovering tokens stuck in\n * contract, i.e. mistaken sends.\n * @param _asset Address for the asset\n * @param _amount Amount of the asset to transfer\n */\n function transferToken(address _asset, uint256 _amount)\n external\n onlyGovernor\n {\n require(!assets[_asset].isSupported, \"Only unsupported assets\");\n IERC20(_asset).safeTransfer(governor(), _amount);\n }\n\n /***************************************\n Strategies Admin\n ****************************************/\n\n /**\n * @notice Withdraws all assets from the strategy and sends assets to the Vault.\n * @param _strategyAddr Strategy address.\n */\n function withdrawAllFromStrategy(address _strategyAddr)\n external\n onlyGovernorOrStrategist\n {\n _withdrawAllFromStrategy(_strategyAddr);\n }\n\n function _withdrawAllFromStrategy(address _strategyAddr) internal virtual {\n require(\n strategies[_strategyAddr].isSupported,\n \"Strategy is not supported\"\n );\n IStrategy strategy = IStrategy(_strategyAddr);\n strategy.withdrawAll();\n }\n\n /**\n * @notice Withdraws all assets from all the strategies and sends assets to the Vault.\n */\n function withdrawAllFromStrategies() external onlyGovernorOrStrategist {\n _withdrawAllFromStrategies();\n }\n\n function _withdrawAllFromStrategies() internal virtual {\n uint256 stratCount = allStrategies.length;\n for (uint256 i = 0; i < stratCount; ++i) {\n IStrategy(allStrategies[i]).withdrawAll();\n }\n }\n\n /***************************************\n Utils\n ****************************************/\n\n function _cacheDecimals(address token) internal {\n Asset storage tokenAsset = assets[token];\n if (tokenAsset.decimals != 0) {\n return;\n }\n uint8 decimals = IBasicToken(token).decimals();\n require(decimals >= 6 && decimals <= 18, \"Unexpected precision\");\n tokenAsset.decimals = decimals;\n }\n}\n" + }, + "contracts/vault/VaultCore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title OToken VaultCore contract\n * @notice The Vault contract stores assets. On a deposit, OTokens will be minted\n and sent to the depositor. On a withdrawal, OTokens will be burned and\n assets will be sent to the withdrawer. The Vault accepts deposits of\n interest from yield bearing strategies which will modify the supply\n of OTokens.\n * @author Origin Protocol Inc\n */\n\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { IOracle } from \"../interfaces/IOracle.sol\";\nimport { IGetExchangeRateToken } from \"../interfaces/IGetExchangeRateToken.sol\";\nimport { IDripper } from \"../interfaces/IDripper.sol\";\n\nimport \"./VaultInitializer.sol\";\n\ncontract VaultCore is VaultInitializer {\n using SafeERC20 for IERC20;\n using StableMath for uint256;\n // max signed int\n uint256 internal constant MAX_INT = 2**255 - 1;\n // max un-signed int\n uint256 internal constant MAX_UINT =\n 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;\n\n /**\n * @dev Verifies that the rebasing is not paused.\n */\n modifier whenNotRebasePaused() {\n require(!rebasePaused, \"Rebasing paused\");\n _;\n }\n\n /**\n * @dev Verifies that the deposits are not paused.\n */\n modifier whenNotCapitalPaused() {\n require(!capitalPaused, \"Capital paused\");\n _;\n }\n\n modifier onlyOusdMetaStrategy() {\n require(\n msg.sender == ousdMetaStrategy,\n \"Caller is not the OUSD meta strategy\"\n );\n _;\n }\n\n /**\n * @notice Deposit a supported asset and mint OTokens.\n * @param _asset Address of the asset being deposited\n * @param _amount Amount of the asset being deposited\n * @param _minimumOusdAmount Minimum OTokens to mint\n */\n function mint(\n address _asset,\n uint256 _amount,\n uint256 _minimumOusdAmount\n ) external whenNotCapitalPaused nonReentrant {\n _mint(_asset, _amount, _minimumOusdAmount);\n }\n\n function _mint(\n address _asset,\n uint256 _amount,\n uint256 _minimumOusdAmount\n ) internal virtual {\n require(assets[_asset].isSupported, \"Asset is not supported\");\n require(_amount > 0, \"Amount must be greater than 0\");\n\n uint256 units = _toUnits(_amount, _asset);\n uint256 unitPrice = _toUnitPrice(_asset, true);\n uint256 priceAdjustedDeposit = (units * unitPrice) / 1e18;\n\n if (_minimumOusdAmount > 0) {\n require(\n priceAdjustedDeposit >= _minimumOusdAmount,\n \"Mint amount lower than minimum\"\n );\n }\n\n emit Mint(msg.sender, priceAdjustedDeposit);\n\n // Rebase must happen before any transfers occur.\n if (priceAdjustedDeposit >= rebaseThreshold && !rebasePaused) {\n if (dripper != address(0)) {\n // Stream any harvested rewards that are available\n IDripper(dripper).collect();\n }\n _rebase();\n }\n\n // Mint matching amount of OTokens\n oUSD.mint(msg.sender, priceAdjustedDeposit);\n\n // Transfer the deposited coins to the vault\n IERC20 asset = IERC20(_asset);\n asset.safeTransferFrom(msg.sender, address(this), _amount);\n\n if (priceAdjustedDeposit >= autoAllocateThreshold) {\n _allocate();\n }\n }\n\n /**\n * @notice Mint OTokens for a Metapool Strategy\n * @param _amount Amount of the asset being deposited\n *\n * Notice: can't use `nonReentrant` modifier since the `mint` function can\n * call `allocate`, and that can trigger `ConvexOUSDMetaStrategy` to call this function\n * while the execution of the `mint` has not yet completed -> causing a `nonReentrant` collision.\n *\n * Also important to understand is that this is a limitation imposed by the test suite.\n * Production / mainnet contracts should never be configured in a way where mint/redeem functions\n * that are moving funds between the Vault and end user wallets can influence strategies\n * utilizing this function.\n */\n function mintForStrategy(uint256 _amount)\n external\n whenNotCapitalPaused\n onlyOusdMetaStrategy\n {\n require(_amount < MAX_INT, \"Amount too high\");\n\n emit Mint(msg.sender, _amount);\n\n // safe to cast because of the require check at the beginning of the function\n netOusdMintedForStrategy += int256(_amount);\n\n require(\n abs(netOusdMintedForStrategy) < netOusdMintForStrategyThreshold,\n \"Minted ousd surpassed netOusdMintForStrategyThreshold.\"\n );\n\n // Mint matching amount of OTokens\n oUSD.mint(msg.sender, _amount);\n }\n\n // In memoriam\n\n /**\n * @notice Withdraw a supported asset and burn OTokens.\n * @param _amount Amount of OTokens to burn\n * @param _minimumUnitAmount Minimum stablecoin units to receive in return\n */\n function redeem(uint256 _amount, uint256 _minimumUnitAmount)\n external\n whenNotCapitalPaused\n nonReentrant\n {\n _redeem(_amount, _minimumUnitAmount);\n }\n\n /**\n * @notice Withdraw a supported asset and burn OTokens.\n * @param _amount Amount of OTokens to burn\n * @param _minimumUnitAmount Minimum stablecoin units to receive in return\n */\n function _redeem(uint256 _amount, uint256 _minimumUnitAmount)\n internal\n virtual\n {\n // Calculate redemption outputs\n uint256[] memory outputs = _calculateRedeemOutputs(_amount);\n\n emit Redeem(msg.sender, _amount);\n\n // Send outputs\n uint256 assetCount = allAssets.length;\n for (uint256 i = 0; i < assetCount; ++i) {\n if (outputs[i] == 0) continue;\n\n address assetAddr = allAssets[i];\n\n if (IERC20(assetAddr).balanceOf(address(this)) >= outputs[i]) {\n // Use Vault funds first if sufficient\n IERC20(assetAddr).safeTransfer(msg.sender, outputs[i]);\n } else {\n address strategyAddr = assetDefaultStrategies[assetAddr];\n if (strategyAddr != address(0)) {\n // Nothing in Vault, but something in Strategy, send from there\n IStrategy strategy = IStrategy(strategyAddr);\n strategy.withdraw(msg.sender, assetAddr, outputs[i]);\n } else {\n // Cant find funds anywhere\n revert(\"Liquidity error\");\n }\n }\n }\n\n if (_minimumUnitAmount > 0) {\n uint256 unitTotal = 0;\n for (uint256 i = 0; i < outputs.length; ++i) {\n unitTotal += _toUnits(outputs[i], allAssets[i]);\n }\n require(\n unitTotal >= _minimumUnitAmount,\n \"Redeem amount lower than minimum\"\n );\n }\n\n oUSD.burn(msg.sender, _amount);\n\n _postRedeem(_amount);\n }\n\n function _postRedeem(uint256 _amount) internal {\n // Until we can prove that we won't affect the prices of our assets\n // by withdrawing them, this should be here.\n // It's possible that a strategy was off on its asset total, perhaps\n // a reward token sold for more or for less than anticipated.\n uint256 totalUnits = 0;\n if (_amount >= rebaseThreshold && !rebasePaused) {\n totalUnits = _rebase();\n } else {\n totalUnits = _totalValue();\n }\n\n // Check that the OTokens are backed by enough assets\n if (maxSupplyDiff > 0) {\n // Allow a max difference of maxSupplyDiff% between\n // backing assets value and OUSD total supply\n uint256 diff = oUSD.totalSupply().divPrecisely(totalUnits);\n require(\n (diff > 1e18 ? diff - 1e18 : 1e18 - diff) <= maxSupplyDiff,\n \"Backing supply liquidity error\"\n );\n }\n }\n\n /**\n * @notice Burn OTokens for Metapool Strategy\n * @param _amount Amount of OUSD to burn\n *\n * @dev Notice: can't use `nonReentrant` modifier since the `redeem` function could\n * require withdrawal on `ConvexOUSDMetaStrategy` and that one can call `burnForStrategy`\n * while the execution of the `redeem` has not yet completed -> causing a `nonReentrant` collision.\n *\n * Also important to understand is that this is a limitation imposed by the test suite.\n * Production / mainnet contracts should never be configured in a way where mint/redeem functions\n * that are moving funds between the Vault and end user wallets can influence strategies\n * utilizing this function.\n */\n function burnForStrategy(uint256 _amount)\n external\n whenNotCapitalPaused\n onlyOusdMetaStrategy\n {\n require(_amount < MAX_INT, \"Amount too high\");\n\n emit Redeem(msg.sender, _amount);\n\n // safe to cast because of the require check at the beginning of the function\n netOusdMintedForStrategy -= int256(_amount);\n\n require(\n abs(netOusdMintedForStrategy) < netOusdMintForStrategyThreshold,\n \"Attempting to burn too much OUSD.\"\n );\n\n // Burn OTokens\n oUSD.burn(msg.sender, _amount);\n }\n\n /**\n * @notice Withdraw a supported asset and burn all OTokens.\n * @param _minimumUnitAmount Minimum stablecoin units to receive in return\n */\n function redeemAll(uint256 _minimumUnitAmount)\n external\n whenNotCapitalPaused\n nonReentrant\n {\n _redeem(oUSD.balanceOf(msg.sender), _minimumUnitAmount);\n }\n\n /**\n * @notice Allocate unallocated funds on Vault to strategies.\n **/\n function allocate() external whenNotCapitalPaused nonReentrant {\n _allocate();\n }\n\n /**\n * @dev Allocate unallocated funds on Vault to strategies.\n **/\n function _allocate() internal virtual {\n uint256 vaultValue = _totalValueInVault();\n // Nothing in vault to allocate\n if (vaultValue == 0) return;\n uint256 strategiesValue = _totalValueInStrategies();\n // We have a method that does the same as this, gas optimisation\n uint256 calculatedTotalValue = vaultValue + strategiesValue;\n\n // We want to maintain a buffer on the Vault so calculate a percentage\n // modifier to multiply each amount being allocated by to enforce the\n // vault buffer\n uint256 vaultBufferModifier;\n if (strategiesValue == 0) {\n // Nothing in Strategies, allocate 100% minus the vault buffer to\n // strategies\n vaultBufferModifier = uint256(1e18) - vaultBuffer;\n } else {\n vaultBufferModifier =\n (vaultBuffer * calculatedTotalValue) /\n vaultValue;\n if (1e18 > vaultBufferModifier) {\n // E.g. 1e18 - (1e17 * 10e18)/5e18 = 8e17\n // (5e18 * 8e17) / 1e18 = 4e18 allocated from Vault\n vaultBufferModifier = uint256(1e18) - vaultBufferModifier;\n } else {\n // We need to let the buffer fill\n return;\n }\n }\n if (vaultBufferModifier == 0) return;\n\n // Iterate over all assets in the Vault and allocate to the appropriate\n // strategy\n uint256 assetCount = allAssets.length;\n for (uint256 i = 0; i < assetCount; ++i) {\n IERC20 asset = IERC20(allAssets[i]);\n uint256 assetBalance = asset.balanceOf(address(this));\n // No balance, nothing to do here\n if (assetBalance == 0) continue;\n\n // Multiply the balance by the vault buffer modifier and truncate\n // to the scale of the asset decimals\n uint256 allocateAmount = assetBalance.mulTruncate(\n vaultBufferModifier\n );\n\n address depositStrategyAddr = assetDefaultStrategies[\n address(asset)\n ];\n\n if (depositStrategyAddr != address(0) && allocateAmount > 0) {\n IStrategy strategy = IStrategy(depositStrategyAddr);\n // Transfer asset to Strategy and call deposit method to\n // mint or take required action\n asset.safeTransfer(address(strategy), allocateAmount);\n strategy.deposit(address(asset), allocateAmount);\n emit AssetAllocated(\n address(asset),\n depositStrategyAddr,\n allocateAmount\n );\n }\n }\n }\n\n /**\n * @notice Calculate the total value of assets held by the Vault and all\n * strategies and update the supply of OTokens.\n */\n function rebase() external virtual nonReentrant {\n _rebase();\n }\n\n /**\n * @dev Calculate the total value of assets held by the Vault and all\n * strategies and update the supply of OTokens, optionally sending a\n * portion of the yield to the trustee.\n * @return totalUnits Total balance of Vault in units\n */\n function _rebase() internal whenNotRebasePaused returns (uint256) {\n uint256 ousdSupply = oUSD.totalSupply();\n uint256 vaultValue = _totalValue();\n if (ousdSupply == 0) {\n return vaultValue;\n }\n\n // Yield fee collection\n address _trusteeAddress = trusteeAddress; // gas savings\n if (_trusteeAddress != address(0) && (vaultValue > ousdSupply)) {\n uint256 yield = vaultValue - ousdSupply;\n uint256 fee = yield.mulTruncateScale(trusteeFeeBps, 1e4);\n require(yield > fee, \"Fee must not be greater than yield\");\n if (fee > 0) {\n oUSD.mint(_trusteeAddress, fee);\n }\n emit YieldDistribution(_trusteeAddress, yield, fee);\n }\n\n // Only rachet OToken supply upwards\n ousdSupply = oUSD.totalSupply(); // Final check should use latest value\n if (vaultValue > ousdSupply) {\n oUSD.changeSupply(vaultValue);\n }\n return vaultValue;\n }\n\n /**\n * @notice Determine the total value of assets held by the vault and its\n * strategies.\n * @return value Total value in USD/ETH (1e18)\n */\n function totalValue() external view virtual returns (uint256 value) {\n value = _totalValue();\n }\n\n /**\n * @dev Internal Calculate the total value of the assets held by the\n * vault and its strategies.\n * @return value Total value in USD/ETH (1e18)\n */\n function _totalValue() internal view virtual returns (uint256 value) {\n return _totalValueInVault() + _totalValueInStrategies();\n }\n\n /**\n * @dev Internal to calculate total value of all assets held in Vault.\n * @return value Total value in USD/ETH (1e18)\n */\n function _totalValueInVault()\n internal\n view\n virtual\n returns (uint256 value)\n {\n uint256 assetCount = allAssets.length;\n for (uint256 y = 0; y < assetCount; ++y) {\n address assetAddr = allAssets[y];\n uint256 balance = IERC20(assetAddr).balanceOf(address(this));\n if (balance > 0) {\n value += _toUnits(balance, assetAddr);\n }\n }\n }\n\n /**\n * @dev Internal to calculate total value of all assets held in Strategies.\n * @return value Total value in USD/ETH (1e18)\n */\n function _totalValueInStrategies() internal view returns (uint256 value) {\n uint256 stratCount = allStrategies.length;\n for (uint256 i = 0; i < stratCount; ++i) {\n value = value + _totalValueInStrategy(allStrategies[i]);\n }\n }\n\n /**\n * @dev Internal to calculate total value of all assets held by strategy.\n * @param _strategyAddr Address of the strategy\n * @return value Total value in USD/ETH (1e18)\n */\n function _totalValueInStrategy(address _strategyAddr)\n internal\n view\n returns (uint256 value)\n {\n IStrategy strategy = IStrategy(_strategyAddr);\n uint256 assetCount = allAssets.length;\n for (uint256 y = 0; y < assetCount; ++y) {\n address assetAddr = allAssets[y];\n if (strategy.supportsAsset(assetAddr)) {\n uint256 balance = strategy.checkBalance(assetAddr);\n if (balance > 0) {\n value += _toUnits(balance, assetAddr);\n }\n }\n }\n }\n\n /**\n * @notice Get the balance of an asset held in Vault and all strategies.\n * @param _asset Address of asset\n * @return uint256 Balance of asset in decimals of asset\n */\n function checkBalance(address _asset) external view returns (uint256) {\n return _checkBalance(_asset);\n }\n\n /**\n * @notice Get the balance of an asset held in Vault and all strategies.\n * @param _asset Address of asset\n * @return balance Balance of asset in decimals of asset\n */\n function _checkBalance(address _asset)\n internal\n view\n virtual\n returns (uint256 balance)\n {\n IERC20 asset = IERC20(_asset);\n balance = asset.balanceOf(address(this));\n uint256 stratCount = allStrategies.length;\n for (uint256 i = 0; i < stratCount; ++i) {\n IStrategy strategy = IStrategy(allStrategies[i]);\n if (strategy.supportsAsset(_asset)) {\n balance = balance + strategy.checkBalance(_asset);\n }\n }\n }\n\n /**\n * @notice Calculate the outputs for a redeem function, i.e. the mix of\n * coins that will be returned\n */\n function calculateRedeemOutputs(uint256 _amount)\n external\n view\n returns (uint256[] memory)\n {\n return _calculateRedeemOutputs(_amount);\n }\n\n /**\n * @dev Calculate the outputs for a redeem function, i.e. the mix of\n * coins that will be returned.\n * @return outputs Array of amounts respective to the supported assets\n */\n function _calculateRedeemOutputs(uint256 _amount)\n internal\n view\n virtual\n returns (uint256[] memory outputs)\n {\n // We always give out coins in proportion to how many we have,\n // Now if all coins were the same value, this math would easy,\n // just take the percentage of each coin, and multiply by the\n // value to be given out. But if coins are worth more than $1,\n // then we would end up handing out too many coins. We need to\n // adjust by the total value of coins.\n //\n // To do this, we total up the value of our coins, by their\n // percentages. Then divide what we would otherwise give out by\n // this number.\n //\n // Let say we have 100 DAI at $1.06 and 200 USDT at $1.00.\n // So for every 1 DAI we give out, we'll be handing out 2 USDT\n // Our total output ratio is: 33% * 1.06 + 66% * 1.00 = 1.02\n //\n // So when calculating the output, we take the percentage of\n // each coin, times the desired output value, divided by the\n // totalOutputRatio.\n //\n // For example, withdrawing: 30 OUSD:\n // DAI 33% * 30 / 1.02 = 9.80 DAI\n // USDT = 66 % * 30 / 1.02 = 19.60 USDT\n //\n // Checking these numbers:\n // 9.80 DAI * 1.06 = $10.40\n // 19.60 USDT * 1.00 = $19.60\n //\n // And so the user gets $10.40 + $19.60 = $30 worth of value.\n\n uint256 assetCount = allAssets.length;\n uint256[] memory assetUnits = new uint256[](assetCount);\n uint256[] memory assetBalances = new uint256[](assetCount);\n outputs = new uint256[](assetCount);\n\n // Calculate redeem fee\n if (redeemFeeBps > 0) {\n uint256 redeemFee = _amount.mulTruncateScale(redeemFeeBps, 1e4);\n _amount = _amount - redeemFee;\n }\n\n // Calculate assets balances and decimals once,\n // for a large gas savings.\n uint256 totalUnits = 0;\n for (uint256 i = 0; i < assetCount; ++i) {\n address assetAddr = allAssets[i];\n uint256 balance = _checkBalance(assetAddr);\n assetBalances[i] = balance;\n assetUnits[i] = _toUnits(balance, assetAddr);\n totalUnits = totalUnits + assetUnits[i];\n }\n // Calculate totalOutputRatio\n uint256 totalOutputRatio = 0;\n for (uint256 i = 0; i < assetCount; ++i) {\n uint256 unitPrice = _toUnitPrice(allAssets[i], false);\n uint256 ratio = (assetUnits[i] * unitPrice) / totalUnits;\n totalOutputRatio = totalOutputRatio + ratio;\n }\n // Calculate final outputs\n uint256 factor = _amount.divPrecisely(totalOutputRatio);\n for (uint256 i = 0; i < assetCount; ++i) {\n outputs[i] = (assetBalances[i] * factor) / totalUnits;\n }\n }\n\n /***************************************\n Pricing\n ****************************************/\n\n /**\n * @notice Returns the total price in 18 digit units for a given asset.\n * Never goes above 1, since that is how we price mints.\n * @param asset address of the asset\n * @return price uint256: unit (USD / ETH) price for 1 unit of the asset, in 18 decimal fixed\n */\n function priceUnitMint(address asset)\n external\n view\n returns (uint256 price)\n {\n /* need to supply 1 asset unit in asset's decimals and can not just hard-code\n * to 1e18 and ignore calling `_toUnits` since we need to consider assets\n * with the exchange rate\n */\n uint256 units = _toUnits(\n uint256(1e18).scaleBy(_getDecimals(asset), 18),\n asset\n );\n price = (_toUnitPrice(asset, true) * units) / 1e18;\n }\n\n /**\n * @notice Returns the total price in 18 digit unit for a given asset.\n * Never goes below 1, since that is how we price redeems\n * @param asset Address of the asset\n * @return price uint256: unit (USD / ETH) price for 1 unit of the asset, in 18 decimal fixed\n */\n function priceUnitRedeem(address asset)\n external\n view\n returns (uint256 price)\n {\n /* need to supply 1 asset unit in asset's decimals and can not just hard-code\n * to 1e18 and ignore calling `_toUnits` since we need to consider assets\n * with the exchange rate\n */\n uint256 units = _toUnits(\n uint256(1e18).scaleBy(_getDecimals(asset), 18),\n asset\n );\n price = (_toUnitPrice(asset, false) * units) / 1e18;\n }\n\n /***************************************\n Utils\n ****************************************/\n\n /**\n * @dev Convert a quantity of a token into 1e18 fixed decimal \"units\"\n * in the underlying base (USD/ETH) used by the vault.\n * Price is not taken into account, only quantity.\n *\n * Examples of this conversion:\n *\n * - 1e18 DAI becomes 1e18 units (same decimals)\n * - 1e6 USDC becomes 1e18 units (decimal conversion)\n * - 1e18 rETH becomes 1.2e18 units (exchange rate conversion)\n *\n * @param _raw Quantity of asset\n * @param _asset Core Asset address\n * @return value 1e18 normalized quantity of units\n */\n function _toUnits(uint256 _raw, address _asset)\n internal\n view\n returns (uint256)\n {\n UnitConversion conversion = assets[_asset].unitConversion;\n if (conversion == UnitConversion.DECIMALS) {\n return _raw.scaleBy(18, _getDecimals(_asset));\n } else if (conversion == UnitConversion.GETEXCHANGERATE) {\n uint256 exchangeRate = IGetExchangeRateToken(_asset)\n .getExchangeRate();\n return (_raw * exchangeRate) / 1e18;\n } else {\n revert(\"Unsupported conversion type\");\n }\n }\n\n /**\n * @dev Returns asset's unit price accounting for different asset types\n * and takes into account the context in which that price exists -\n * - mint or redeem.\n *\n * Note: since we are returning the price of the unit and not the one of the\n * asset (see comment above how 1 rETH exchanges for 1.2 units) we need\n * to make the Oracle price adjustment as well since we are pricing the\n * units and not the assets.\n *\n * The price also snaps to a \"full unit price\" in case a mint or redeem\n * action would be unfavourable to the protocol.\n *\n */\n function _toUnitPrice(address _asset, bool isMint)\n internal\n view\n returns (uint256 price)\n {\n UnitConversion conversion = assets[_asset].unitConversion;\n price = IOracle(priceProvider).price(_asset);\n\n if (conversion == UnitConversion.GETEXCHANGERATE) {\n uint256 exchangeRate = IGetExchangeRateToken(_asset)\n .getExchangeRate();\n price = (price * 1e18) / exchangeRate;\n } else if (conversion != UnitConversion.DECIMALS) {\n revert(\"Unsupported conversion type\");\n }\n\n /* At this stage the price is already adjusted to the unit\n * so the price checks are agnostic to underlying asset being\n * pegged to a USD or to an ETH or having a custom exchange rate.\n */\n require(price <= MAX_UNIT_PRICE_DRIFT, \"Vault: Price exceeds max\");\n require(price >= MIN_UNIT_PRICE_DRIFT, \"Vault: Price under min\");\n\n if (isMint) {\n /* Never price a normalized unit price for more than one\n * unit of OETH/OUSD when minting.\n */\n if (price > 1e18) {\n price = 1e18;\n }\n require(price >= MINT_MINIMUM_UNIT_PRICE, \"Asset price below peg\");\n } else {\n /* Never give out more than 1 normalized unit amount of assets\n * for one unit of OETH/OUSD when redeeming.\n */\n if (price < 1e18) {\n price = 1e18;\n }\n }\n }\n\n function _getDecimals(address _asset)\n internal\n view\n returns (uint256 decimals)\n {\n decimals = assets[_asset].decimals;\n require(decimals > 0, \"Decimals not cached\");\n }\n\n /**\n * @notice Return the number of assets supported by the Vault.\n */\n function getAssetCount() public view returns (uint256) {\n return allAssets.length;\n }\n\n /**\n * @notice Gets the vault configuration of a supported asset.\n */\n function getAssetConfig(address _asset)\n public\n view\n returns (Asset memory config)\n {\n config = assets[_asset];\n }\n\n /**\n * @notice Return all vault asset addresses in order\n */\n function getAllAssets() external view returns (address[] memory) {\n return allAssets;\n }\n\n /**\n * @notice Return the number of strategies active on the Vault.\n */\n function getStrategyCount() external view returns (uint256) {\n return allStrategies.length;\n }\n\n /**\n * @notice Return the array of all strategies\n */\n function getAllStrategies() external view returns (address[] memory) {\n return allStrategies;\n }\n\n /**\n * @notice Returns whether the vault supports the asset\n * @param _asset address of the asset\n * @return true if supported\n */\n function isSupportedAsset(address _asset) external view returns (bool) {\n return assets[_asset].isSupported;\n }\n\n /**\n * @dev Falldown to the admin implementation\n * @notice This is a catch all for all functions not declared in core\n */\n // solhint-disable-next-line no-complex-fallback\n fallback() external {\n bytes32 slot = adminImplPosition;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n // Copy msg.data. We take full control of memory in this inline assembly\n // block because it will not return to Solidity code. We overwrite the\n // Solidity scratch pad at memory position 0.\n calldatacopy(0, 0, calldatasize())\n\n // Call the implementation.\n // out and outsize are 0 because we don't know the size yet.\n let result := delegatecall(\n gas(),\n sload(slot),\n 0,\n calldatasize(),\n 0,\n 0\n )\n\n // Copy the returned data.\n returndatacopy(0, 0, returndatasize())\n\n switch result\n // delegatecall returns 0 on error.\n case 0 {\n revert(0, returndatasize())\n }\n default {\n return(0, returndatasize())\n }\n }\n }\n\n function abs(int256 x) private pure returns (uint256) {\n require(x < int256(MAX_INT), \"Amount too high\");\n return x >= 0 ? uint256(x) : uint256(-x);\n }\n}\n" + }, + "contracts/vault/VaultInitializer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title OToken VaultInitializer contract\n * @notice The Vault contract initializes the vault.\n * @author Origin Protocol Inc\n */\n\nimport \"./VaultStorage.sol\";\n\ncontract VaultInitializer is VaultStorage {\n function initialize(address _priceProvider, address _oToken)\n external\n onlyGovernor\n initializer\n {\n require(_priceProvider != address(0), \"PriceProvider address is zero\");\n require(_oToken != address(0), \"oToken address is zero\");\n\n oUSD = OUSD(_oToken);\n\n priceProvider = _priceProvider;\n\n rebasePaused = false;\n capitalPaused = true;\n\n // Initial redeem fee of 0 basis points\n redeemFeeBps = 0;\n // Initial Vault buffer of 0%\n vaultBuffer = 0;\n // Initial allocate threshold of 25,000 OUSD\n autoAllocateThreshold = 25000e18;\n // Threshold for rebasing\n rebaseThreshold = 1000e18;\n // Initialize all strategies\n allStrategies = new address[](0);\n }\n}\n" + }, + "contracts/vault/VaultStorage.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title OToken VaultStorage contract\n * @notice The VaultStorage contract defines the storage for the Vault contracts\n * @author Origin Protocol Inc\n */\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { Address } from \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport { IStrategy } from \"../interfaces/IStrategy.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\nimport { OUSD } from \"../token/OUSD.sol\";\nimport { Initializable } from \"../utils/Initializable.sol\";\nimport \"../utils/Helpers.sol\";\n\ncontract VaultStorage is Initializable, Governable {\n using SafeERC20 for IERC20;\n\n event AssetSupported(address _asset);\n event AssetRemoved(address _asset);\n event AssetDefaultStrategyUpdated(address _asset, address _strategy);\n event AssetAllocated(address _asset, address _strategy, uint256 _amount);\n event StrategyApproved(address _addr);\n event StrategyRemoved(address _addr);\n event Mint(address _addr, uint256 _value);\n event Redeem(address _addr, uint256 _value);\n event CapitalPaused();\n event CapitalUnpaused();\n event RebasePaused();\n event RebaseUnpaused();\n event VaultBufferUpdated(uint256 _vaultBuffer);\n event OusdMetaStrategyUpdated(address _ousdMetaStrategy);\n event RedeemFeeUpdated(uint256 _redeemFeeBps);\n event PriceProviderUpdated(address _priceProvider);\n event AllocateThresholdUpdated(uint256 _threshold);\n event RebaseThresholdUpdated(uint256 _threshold);\n event StrategistUpdated(address _address);\n event MaxSupplyDiffChanged(uint256 maxSupplyDiff);\n event YieldDistribution(address _to, uint256 _yield, uint256 _fee);\n event TrusteeFeeBpsChanged(uint256 _basis);\n event TrusteeAddressChanged(address _address);\n event NetOusdMintForStrategyThresholdChanged(uint256 _threshold);\n event SwapperChanged(address _address);\n event SwapAllowedUndervalueChanged(uint256 _basis);\n event SwapSlippageChanged(address _asset, uint256 _basis);\n event Swapped(\n address indexed _fromAsset,\n address indexed _toAsset,\n uint256 _fromAssetAmount,\n uint256 _toAssetAmount\n );\n event DripperChanged(address indexed _dripper);\n event WithdrawalRequested(\n address indexed _withdrawer,\n uint256 indexed _requestId,\n uint256 _amount,\n uint256 _queued\n );\n event WithdrawalClaimed(\n address indexed _withdrawer,\n uint256 indexed _requestId,\n uint256 _amount\n );\n event WithdrawalClaimable(uint256 _claimable, uint256 _newClaimable);\n\n // Assets supported by the Vault, i.e. Stablecoins\n enum UnitConversion {\n DECIMALS,\n GETEXCHANGERATE\n }\n // Changed to fit into a single storage slot so the decimals needs to be recached\n struct Asset {\n // Note: OETHVaultCore doesn't use `isSupported` when minting,\n // redeeming or checking balance of assets.\n bool isSupported;\n UnitConversion unitConversion;\n uint8 decimals;\n // Max allowed slippage from the Oracle price when swapping collateral assets in basis points.\n // For example 40 == 0.4% slippage\n uint16 allowedOracleSlippageBps;\n }\n\n /// @dev mapping of supported vault assets to their configuration\n // slither-disable-next-line uninitialized-state\n mapping(address => Asset) internal assets;\n /// @dev list of all assets supported by the vault.\n // slither-disable-next-line uninitialized-state\n address[] internal allAssets;\n\n // Strategies approved for use by the Vault\n struct Strategy {\n bool isSupported;\n uint256 _deprecated; // Deprecated storage slot\n }\n /// @dev mapping of strategy contracts to their configuration\n mapping(address => Strategy) internal strategies;\n /// @dev list of all vault strategies\n address[] internal allStrategies;\n\n /// @notice Address of the Oracle price provider contract\n // slither-disable-next-line uninitialized-state\n address public priceProvider;\n /// @notice pause rebasing if true\n bool public rebasePaused = false;\n /// @notice pause operations that change the OToken supply.\n /// eg mint, redeem, allocate, mint/burn for strategy\n bool public capitalPaused = true;\n /// @notice Redemption fee in basis points. eg 50 = 0.5%\n uint256 public redeemFeeBps;\n /// @notice Percentage of assets to keep in Vault to handle (most) withdrawals. 100% = 1e18.\n uint256 public vaultBuffer;\n /// @notice OToken mints over this amount automatically allocate funds. 18 decimals.\n uint256 public autoAllocateThreshold;\n /// @notice OToken mints over this amount automatically rebase. 18 decimals.\n uint256 public rebaseThreshold;\n\n /// @dev Address of the OToken token. eg OUSD or OETH.\n // slither-disable-next-line uninitialized-state\n OUSD internal oUSD;\n\n //keccak256(\"OUSD.vault.governor.admin.impl\");\n bytes32 constant adminImplPosition =\n 0xa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd9;\n\n // Address of the contract responsible for post rebase syncs with AMMs\n address private _deprecated_rebaseHooksAddr = address(0);\n\n // Deprecated: Address of Uniswap\n // slither-disable-next-line constable-states\n address private _deprecated_uniswapAddr = address(0);\n\n /// @notice Address of the Strategist\n address public strategistAddr = address(0);\n\n /// @notice Mapping of asset address to the Strategy that they should automatically\n // be allocated to\n // slither-disable-next-line uninitialized-state\n mapping(address => address) public assetDefaultStrategies;\n\n /// @notice Max difference between total supply and total value of assets. 18 decimals.\n // slither-disable-next-line uninitialized-state\n uint256 public maxSupplyDiff;\n\n /// @notice Trustee contract that can collect a percentage of yield\n address public trusteeAddress;\n\n /// @notice Amount of yield collected in basis points. eg 2000 = 20%\n uint256 public trusteeFeeBps;\n\n /// @dev Deprecated: Tokens that should be swapped for stablecoins\n address[] private _deprecated_swapTokens;\n\n uint256 constant MINT_MINIMUM_UNIT_PRICE = 0.998e18;\n\n /// @notice Metapool strategy that is allowed to mint/burn OTokens without changing collateral\n address public ousdMetaStrategy = address(0);\n\n /// @notice How much OTokens are currently minted by the strategy\n int256 public netOusdMintedForStrategy = 0;\n\n /// @notice How much net total OTokens are allowed to be minted by all strategies\n uint256 public netOusdMintForStrategyThreshold = 0;\n\n uint256 constant MIN_UNIT_PRICE_DRIFT = 0.7e18;\n uint256 constant MAX_UNIT_PRICE_DRIFT = 1.3e18;\n\n /// @notice Collateral swap configuration.\n /// @dev is packed into a single storage slot to save gas.\n struct SwapConfig {\n // Contract that swaps the vault's collateral assets\n address swapper;\n // Max allowed percentage the total value can drop below the total supply in basis points.\n // For example 100 == 1%\n uint16 allowedUndervalueBps;\n }\n SwapConfig internal swapConfig = SwapConfig(address(0), 0);\n\n /// @notice Address of the Dripper contract that streams harvested rewards to the Vault\n /// @dev The vault is proxied so needs to be set with setDripper against the proxy contract.\n // slither-disable-start constable-states\n // slither-disable-next-line uninitialized-state\n address public dripper;\n // slither-disable-end constable-states\n\n /// Withdrawal Queue Storage /////\n\n struct WithdrawalQueueMetadata {\n // cumulative total of all withdrawal requests included the ones that have already been claimed\n uint128 queued;\n // cumulative total of all the requests that can be claimed included the ones that have already been claimed\n uint128 claimable;\n // total of all the requests that have been claimed\n uint128 claimed;\n // index of the next withdrawal request starting at 0\n uint128 nextWithdrawalIndex;\n }\n\n // slither-disable-next-line uninitialized-state\n WithdrawalQueueMetadata public withdrawalQueueMetadata;\n\n struct WithdrawalRequest {\n address withdrawer;\n bool claimed;\n // Amount of oTokens to redeem\n uint128 amount;\n // cumulative total of all withdrawal requests including this one.\n // this request can be claimed when this queued amount is less than or equal to the queue's claimable amount.\n uint128 queued;\n }\n\n // Mapping of withdrawal requests indexes to the user withdrawal request data\n mapping(uint256 => WithdrawalRequest) public withdrawalRequests;\n\n // For future use\n uint256[46] private __gap;\n\n /**\n * @notice set the implementation for the admin, this needs to be in a base class else we cannot set it\n * @param newImpl address of the implementation\n */\n function setAdminImpl(address newImpl) external onlyGovernor {\n require(\n Address.isContract(newImpl),\n \"new implementation is not a contract\"\n );\n bytes32 position = adminImplPosition;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n sstore(position, newImpl)\n }\n }\n}\n" + }, + "hardhat/console.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >= 0.4.22 <0.9.0;\n\nlibrary console {\n\taddress constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67);\n\n\tfunction _sendLogPayload(bytes memory payload) private view {\n\t\tuint256 payloadLength = payload.length;\n\t\taddress consoleAddress = CONSOLE_ADDRESS;\n\t\tassembly {\n\t\t\tlet payloadStart := add(payload, 32)\n\t\t\tlet r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0)\n\t\t}\n\t}\n\n\tfunction log() internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log()\"));\n\t}\n\n\tfunction logInt(int256 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(int256)\", p0));\n\t}\n\n\tfunction logUint(uint256 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256)\", p0));\n\t}\n\n\tfunction logString(string memory p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string)\", p0));\n\t}\n\n\tfunction logBool(bool p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool)\", p0));\n\t}\n\n\tfunction logAddress(address p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address)\", p0));\n\t}\n\n\tfunction logBytes(bytes memory p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes)\", p0));\n\t}\n\n\tfunction logBytes1(bytes1 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes1)\", p0));\n\t}\n\n\tfunction logBytes2(bytes2 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes2)\", p0));\n\t}\n\n\tfunction logBytes3(bytes3 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes3)\", p0));\n\t}\n\n\tfunction logBytes4(bytes4 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes4)\", p0));\n\t}\n\n\tfunction logBytes5(bytes5 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes5)\", p0));\n\t}\n\n\tfunction logBytes6(bytes6 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes6)\", p0));\n\t}\n\n\tfunction logBytes7(bytes7 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes7)\", p0));\n\t}\n\n\tfunction logBytes8(bytes8 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes8)\", p0));\n\t}\n\n\tfunction logBytes9(bytes9 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes9)\", p0));\n\t}\n\n\tfunction logBytes10(bytes10 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes10)\", p0));\n\t}\n\n\tfunction logBytes11(bytes11 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes11)\", p0));\n\t}\n\n\tfunction logBytes12(bytes12 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes12)\", p0));\n\t}\n\n\tfunction logBytes13(bytes13 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes13)\", p0));\n\t}\n\n\tfunction logBytes14(bytes14 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes14)\", p0));\n\t}\n\n\tfunction logBytes15(bytes15 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes15)\", p0));\n\t}\n\n\tfunction logBytes16(bytes16 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes16)\", p0));\n\t}\n\n\tfunction logBytes17(bytes17 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes17)\", p0));\n\t}\n\n\tfunction logBytes18(bytes18 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes18)\", p0));\n\t}\n\n\tfunction logBytes19(bytes19 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes19)\", p0));\n\t}\n\n\tfunction logBytes20(bytes20 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes20)\", p0));\n\t}\n\n\tfunction logBytes21(bytes21 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes21)\", p0));\n\t}\n\n\tfunction logBytes22(bytes22 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes22)\", p0));\n\t}\n\n\tfunction logBytes23(bytes23 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes23)\", p0));\n\t}\n\n\tfunction logBytes24(bytes24 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes24)\", p0));\n\t}\n\n\tfunction logBytes25(bytes25 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes25)\", p0));\n\t}\n\n\tfunction logBytes26(bytes26 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes26)\", p0));\n\t}\n\n\tfunction logBytes27(bytes27 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes27)\", p0));\n\t}\n\n\tfunction logBytes28(bytes28 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes28)\", p0));\n\t}\n\n\tfunction logBytes29(bytes29 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes29)\", p0));\n\t}\n\n\tfunction logBytes30(bytes30 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes30)\", p0));\n\t}\n\n\tfunction logBytes31(bytes31 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes31)\", p0));\n\t}\n\n\tfunction logBytes32(bytes32 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes32)\", p0));\n\t}\n\n\tfunction log(uint256 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256)\", p0));\n\t}\n\n\tfunction log(string memory p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string)\", p0));\n\t}\n\n\tfunction log(bool p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool)\", p0));\n\t}\n\n\tfunction log(address p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address)\", p0));\n\t}\n\n\tfunction log(uint256 p0, uint256 p1) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256)\", p0, p1));\n\t}\n\n\tfunction log(uint256 p0, string memory p1) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,string)\", p0, p1));\n\t}\n\n\tfunction log(uint256 p0, bool p1) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool)\", p0, p1));\n\t}\n\n\tfunction log(uint256 p0, address p1) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,address)\", p0, p1));\n\t}\n\n\tfunction log(string memory p0, uint256 p1) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint256)\", p0, p1));\n\t}\n\n\tfunction log(string memory p0, string memory p1) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string)\", p0, p1));\n\t}\n\n\tfunction log(string memory p0, bool p1) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool)\", p0, p1));\n\t}\n\n\tfunction log(string memory p0, address p1) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address)\", p0, p1));\n\t}\n\n\tfunction log(bool p0, uint256 p1) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256)\", p0, p1));\n\t}\n\n\tfunction log(bool p0, string memory p1) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string)\", p0, p1));\n\t}\n\n\tfunction log(bool p0, bool p1) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool)\", p0, p1));\n\t}\n\n\tfunction log(bool p0, address p1) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address)\", p0, p1));\n\t}\n\n\tfunction log(address p0, uint256 p1) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint256)\", p0, p1));\n\t}\n\n\tfunction log(address p0, string memory p1) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string)\", p0, p1));\n\t}\n\n\tfunction log(address p0, bool p1) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool)\", p0, p1));\n\t}\n\n\tfunction log(address p0, address p1) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address)\", p0, p1));\n\t}\n\n\tfunction log(uint256 p0, uint256 p1, uint256 p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,uint256)\", p0, p1, p2));\n\t}\n\n\tfunction log(uint256 p0, uint256 p1, string memory p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,string)\", p0, p1, p2));\n\t}\n\n\tfunction log(uint256 p0, uint256 p1, bool p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,bool)\", p0, p1, p2));\n\t}\n\n\tfunction log(uint256 p0, uint256 p1, address p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,address)\", p0, p1, p2));\n\t}\n\n\tfunction log(uint256 p0, string memory p1, uint256 p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,uint256)\", p0, p1, p2));\n\t}\n\n\tfunction log(uint256 p0, string memory p1, string memory p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,string)\", p0, p1, p2));\n\t}\n\n\tfunction log(uint256 p0, string memory p1, bool p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,bool)\", p0, p1, p2));\n\t}\n\n\tfunction log(uint256 p0, string memory p1, address p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,address)\", p0, p1, p2));\n\t}\n\n\tfunction log(uint256 p0, bool p1, uint256 p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,uint256)\", p0, p1, p2));\n\t}\n\n\tfunction log(uint256 p0, bool p1, string memory p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,string)\", p0, p1, p2));\n\t}\n\n\tfunction log(uint256 p0, bool p1, bool p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,bool)\", p0, p1, p2));\n\t}\n\n\tfunction log(uint256 p0, bool p1, address p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,address)\", p0, p1, p2));\n\t}\n\n\tfunction log(uint256 p0, address p1, uint256 p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,uint256)\", p0, p1, p2));\n\t}\n\n\tfunction log(uint256 p0, address p1, string memory p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,string)\", p0, p1, p2));\n\t}\n\n\tfunction log(uint256 p0, address p1, bool p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,bool)\", p0, p1, p2));\n\t}\n\n\tfunction log(uint256 p0, address p1, address p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,address)\", p0, p1, p2));\n\t}\n\n\tfunction log(string memory p0, uint256 p1, uint256 p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,uint256)\", p0, p1, p2));\n\t}\n\n\tfunction log(string memory p0, uint256 p1, string memory p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,string)\", p0, p1, p2));\n\t}\n\n\tfunction log(string memory p0, uint256 p1, bool p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,bool)\", p0, p1, p2));\n\t}\n\n\tfunction log(string memory p0, uint256 p1, address p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,address)\", p0, p1, p2));\n\t}\n\n\tfunction log(string memory p0, string memory p1, uint256 p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,uint256)\", p0, p1, p2));\n\t}\n\n\tfunction log(string memory p0, string memory p1, string memory p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,string)\", p0, p1, p2));\n\t}\n\n\tfunction log(string memory p0, string memory p1, bool p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,bool)\", p0, p1, p2));\n\t}\n\n\tfunction log(string memory p0, string memory p1, address p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,address)\", p0, p1, p2));\n\t}\n\n\tfunction log(string memory p0, bool p1, uint256 p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,uint256)\", p0, p1, p2));\n\t}\n\n\tfunction log(string memory p0, bool p1, string memory p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,string)\", p0, p1, p2));\n\t}\n\n\tfunction log(string memory p0, bool p1, bool p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,bool)\", p0, p1, p2));\n\t}\n\n\tfunction log(string memory p0, bool p1, address p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,address)\", p0, p1, p2));\n\t}\n\n\tfunction log(string memory p0, address p1, uint256 p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,uint256)\", p0, p1, p2));\n\t}\n\n\tfunction log(string memory p0, address p1, string memory p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,string)\", p0, p1, p2));\n\t}\n\n\tfunction log(string memory p0, address p1, bool p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,bool)\", p0, p1, p2));\n\t}\n\n\tfunction log(string memory p0, address p1, address p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,address)\", p0, p1, p2));\n\t}\n\n\tfunction log(bool p0, uint256 p1, uint256 p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,uint256)\", p0, p1, p2));\n\t}\n\n\tfunction log(bool p0, uint256 p1, string memory p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,string)\", p0, p1, p2));\n\t}\n\n\tfunction log(bool p0, uint256 p1, bool p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,bool)\", p0, p1, p2));\n\t}\n\n\tfunction log(bool p0, uint256 p1, address p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,address)\", p0, p1, p2));\n\t}\n\n\tfunction log(bool p0, string memory p1, uint256 p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,uint256)\", p0, p1, p2));\n\t}\n\n\tfunction log(bool p0, string memory p1, string memory p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,string)\", p0, p1, p2));\n\t}\n\n\tfunction log(bool p0, string memory p1, bool p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,bool)\", p0, p1, p2));\n\t}\n\n\tfunction log(bool p0, string memory p1, address p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,address)\", p0, p1, p2));\n\t}\n\n\tfunction log(bool p0, bool p1, uint256 p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,uint256)\", p0, p1, p2));\n\t}\n\n\tfunction log(bool p0, bool p1, string memory p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,string)\", p0, p1, p2));\n\t}\n\n\tfunction log(bool p0, bool p1, bool p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,bool)\", p0, p1, p2));\n\t}\n\n\tfunction log(bool p0, bool p1, address p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,address)\", p0, p1, p2));\n\t}\n\n\tfunction log(bool p0, address p1, uint256 p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,uint256)\", p0, p1, p2));\n\t}\n\n\tfunction log(bool p0, address p1, string memory p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,string)\", p0, p1, p2));\n\t}\n\n\tfunction log(bool p0, address p1, bool p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,bool)\", p0, p1, p2));\n\t}\n\n\tfunction log(bool p0, address p1, address p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,address)\", p0, p1, p2));\n\t}\n\n\tfunction log(address p0, uint256 p1, uint256 p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,uint256)\", p0, p1, p2));\n\t}\n\n\tfunction log(address p0, uint256 p1, string memory p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,string)\", p0, p1, p2));\n\t}\n\n\tfunction log(address p0, uint256 p1, bool p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,bool)\", p0, p1, p2));\n\t}\n\n\tfunction log(address p0, uint256 p1, address p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,address)\", p0, p1, p2));\n\t}\n\n\tfunction log(address p0, string memory p1, uint256 p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,uint256)\", p0, p1, p2));\n\t}\n\n\tfunction log(address p0, string memory p1, string memory p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,string)\", p0, p1, p2));\n\t}\n\n\tfunction log(address p0, string memory p1, bool p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,bool)\", p0, p1, p2));\n\t}\n\n\tfunction log(address p0, string memory p1, address p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,address)\", p0, p1, p2));\n\t}\n\n\tfunction log(address p0, bool p1, uint256 p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,uint256)\", p0, p1, p2));\n\t}\n\n\tfunction log(address p0, bool p1, string memory p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,string)\", p0, p1, p2));\n\t}\n\n\tfunction log(address p0, bool p1, bool p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,bool)\", p0, p1, p2));\n\t}\n\n\tfunction log(address p0, bool p1, address p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,address)\", p0, p1, p2));\n\t}\n\n\tfunction log(address p0, address p1, uint256 p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,uint256)\", p0, p1, p2));\n\t}\n\n\tfunction log(address p0, address p1, string memory p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,string)\", p0, p1, p2));\n\t}\n\n\tfunction log(address p0, address p1, bool p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,bool)\", p0, p1, p2));\n\t}\n\n\tfunction log(address p0, address p1, address p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,address)\", p0, p1, p2));\n\t}\n\n\tfunction log(uint256 p0, uint256 p1, uint256 p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,uint256,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, uint256 p1, uint256 p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,uint256,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, uint256 p1, uint256 p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,uint256,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, uint256 p1, uint256 p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,uint256,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, uint256 p1, string memory p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,string,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, uint256 p1, string memory p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,string,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, uint256 p1, string memory p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,string,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, uint256 p1, string memory p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,string,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, uint256 p1, bool p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,bool,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, uint256 p1, bool p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,bool,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, uint256 p1, bool p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,bool,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, uint256 p1, bool p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,bool,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, uint256 p1, address p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,address,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, uint256 p1, address p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,address,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, uint256 p1, address p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,address,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, uint256 p1, address p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,address,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, string memory p1, uint256 p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,uint256,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, string memory p1, uint256 p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,uint256,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, string memory p1, uint256 p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,uint256,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, string memory p1, uint256 p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,uint256,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, string memory p1, string memory p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,string,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, string memory p1, string memory p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,string,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, string memory p1, string memory p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,string,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, string memory p1, string memory p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,string,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, string memory p1, bool p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,bool,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, string memory p1, bool p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,bool,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, string memory p1, bool p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,bool,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, string memory p1, bool p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,bool,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, string memory p1, address p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,address,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, string memory p1, address p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,address,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, string memory p1, address p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,address,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, string memory p1, address p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,address,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, bool p1, uint256 p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,uint256,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, bool p1, uint256 p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,uint256,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, bool p1, uint256 p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,uint256,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, bool p1, uint256 p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,uint256,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, bool p1, string memory p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,string,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, bool p1, string memory p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,string,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, bool p1, string memory p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,string,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, bool p1, string memory p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,string,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, bool p1, bool p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,bool,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, bool p1, bool p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,bool,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, bool p1, bool p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,bool,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, bool p1, bool p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,bool,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, bool p1, address p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,address,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, bool p1, address p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,address,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, bool p1, address p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,address,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, bool p1, address p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,address,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, address p1, uint256 p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,uint256,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, address p1, uint256 p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,uint256,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, address p1, uint256 p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,uint256,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, address p1, uint256 p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,uint256,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, address p1, string memory p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,string,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, address p1, string memory p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,string,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, address p1, string memory p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,string,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, address p1, string memory p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,string,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, address p1, bool p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,bool,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, address p1, bool p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,bool,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, address p1, bool p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,bool,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, address p1, bool p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,bool,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, address p1, address p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,address,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, address p1, address p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,address,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, address p1, address p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,address,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, address p1, address p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,address,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, uint256 p1, uint256 p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,uint256,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, uint256 p1, uint256 p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,uint256,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, uint256 p1, uint256 p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,uint256,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, uint256 p1, uint256 p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,uint256,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, uint256 p1, string memory p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,string,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, uint256 p1, string memory p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,string,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, uint256 p1, string memory p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,string,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, uint256 p1, string memory p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,string,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, uint256 p1, bool p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,bool,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, uint256 p1, bool p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,bool,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, uint256 p1, bool p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,bool,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, uint256 p1, bool p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,bool,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, uint256 p1, address p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,address,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, uint256 p1, address p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,address,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, uint256 p1, address p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,address,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, uint256 p1, address p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,address,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, string memory p1, uint256 p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,uint256,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, string memory p1, uint256 p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,uint256,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, string memory p1, uint256 p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,uint256,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, string memory p1, uint256 p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,uint256,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, string memory p1, string memory p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,string,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, string memory p1, string memory p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,string,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, string memory p1, string memory p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,string,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, string memory p1, string memory p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,string,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, string memory p1, bool p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,bool,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, string memory p1, bool p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,bool,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, string memory p1, bool p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,bool,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, string memory p1, bool p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,bool,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, string memory p1, address p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,address,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, string memory p1, address p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,address,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, string memory p1, address p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,address,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, string memory p1, address p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,address,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, bool p1, uint256 p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,uint256,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, bool p1, uint256 p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,uint256,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, bool p1, uint256 p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,uint256,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, bool p1, uint256 p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,uint256,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, bool p1, string memory p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,string,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, bool p1, string memory p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,string,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, bool p1, string memory p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,string,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, bool p1, string memory p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,string,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, bool p1, bool p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,bool,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, bool p1, bool p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,bool,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, bool p1, bool p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,bool,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, bool p1, bool p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,bool,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, bool p1, address p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,address,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, bool p1, address p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,address,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, bool p1, address p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,address,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, bool p1, address p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,address,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, address p1, uint256 p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,uint256,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, address p1, uint256 p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,uint256,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, address p1, uint256 p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,uint256,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, address p1, uint256 p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,uint256,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, address p1, string memory p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,string,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, address p1, string memory p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,string,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, address p1, string memory p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,string,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, address p1, string memory p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,string,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, address p1, bool p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,bool,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, address p1, bool p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,bool,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, address p1, bool p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,bool,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, address p1, bool p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,bool,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, address p1, address p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,address,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, address p1, address p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,address,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, address p1, address p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,address,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, address p1, address p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,address,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, uint256 p1, uint256 p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,uint256,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, uint256 p1, uint256 p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,uint256,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, uint256 p1, uint256 p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,uint256,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, uint256 p1, uint256 p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,uint256,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, uint256 p1, string memory p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,string,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, uint256 p1, string memory p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,string,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, uint256 p1, string memory p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,string,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, uint256 p1, string memory p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,string,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, uint256 p1, bool p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,bool,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, uint256 p1, bool p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,bool,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, uint256 p1, bool p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,bool,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, uint256 p1, bool p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,bool,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, uint256 p1, address p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,address,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, uint256 p1, address p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,address,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, uint256 p1, address p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,address,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, uint256 p1, address p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,address,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, string memory p1, uint256 p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,uint256,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, string memory p1, uint256 p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,uint256,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, string memory p1, uint256 p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,uint256,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, string memory p1, uint256 p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,uint256,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, string memory p1, string memory p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,string,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, string memory p1, string memory p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,string,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, string memory p1, string memory p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,string,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, string memory p1, string memory p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,string,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, string memory p1, bool p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,bool,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, string memory p1, bool p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,bool,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, string memory p1, bool p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,bool,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, string memory p1, bool p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,bool,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, string memory p1, address p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,address,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, string memory p1, address p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,address,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, string memory p1, address p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,address,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, string memory p1, address p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,address,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, bool p1, uint256 p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,uint256,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, bool p1, uint256 p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,uint256,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, bool p1, uint256 p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,uint256,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, bool p1, uint256 p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,uint256,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, bool p1, string memory p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,string,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, bool p1, string memory p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,string,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, bool p1, string memory p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,string,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, bool p1, string memory p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,string,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, bool p1, bool p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,bool,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, bool p1, bool p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,bool,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, bool p1, bool p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,bool,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, bool p1, bool p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,bool,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, bool p1, address p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,address,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, bool p1, address p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,address,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, bool p1, address p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,address,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, bool p1, address p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,address,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, address p1, uint256 p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,uint256,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, address p1, uint256 p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,uint256,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, address p1, uint256 p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,uint256,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, address p1, uint256 p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,uint256,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, address p1, string memory p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,string,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, address p1, string memory p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,string,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, address p1, string memory p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,string,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, address p1, string memory p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,string,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, address p1, bool p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,bool,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, address p1, bool p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,bool,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, address p1, bool p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,bool,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, address p1, bool p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,bool,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, address p1, address p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,address,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, address p1, address p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,address,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, address p1, address p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,address,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, address p1, address p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,address,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, uint256 p1, uint256 p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,uint256,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, uint256 p1, uint256 p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,uint256,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, uint256 p1, uint256 p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,uint256,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, uint256 p1, uint256 p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,uint256,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, uint256 p1, string memory p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,string,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, uint256 p1, string memory p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,string,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, uint256 p1, string memory p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,string,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, uint256 p1, string memory p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,string,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, uint256 p1, bool p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,bool,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, uint256 p1, bool p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,bool,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, uint256 p1, bool p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,bool,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, uint256 p1, bool p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,bool,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, uint256 p1, address p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,address,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, uint256 p1, address p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,address,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, uint256 p1, address p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,address,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, uint256 p1, address p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,address,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, string memory p1, uint256 p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,uint256,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, string memory p1, uint256 p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,uint256,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, string memory p1, uint256 p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,uint256,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, string memory p1, uint256 p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,uint256,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, string memory p1, string memory p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,string,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, string memory p1, string memory p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,string,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, string memory p1, string memory p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,string,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, string memory p1, string memory p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,string,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, string memory p1, bool p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,bool,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, string memory p1, bool p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,bool,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, string memory p1, bool p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,bool,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, string memory p1, bool p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,bool,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, string memory p1, address p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,address,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, string memory p1, address p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,address,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, string memory p1, address p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,address,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, string memory p1, address p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,address,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, bool p1, uint256 p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,uint256,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, bool p1, uint256 p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,uint256,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, bool p1, uint256 p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,uint256,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, bool p1, uint256 p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,uint256,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, bool p1, string memory p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,string,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, bool p1, string memory p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,string,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, bool p1, string memory p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,string,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, bool p1, string memory p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,string,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, bool p1, bool p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,bool,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, bool p1, bool p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,bool,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, bool p1, bool p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,bool,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, bool p1, bool p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,bool,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, bool p1, address p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,address,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, bool p1, address p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,address,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, bool p1, address p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,address,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, bool p1, address p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,address,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, address p1, uint256 p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,uint256,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, address p1, uint256 p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,uint256,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, address p1, uint256 p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,uint256,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, address p1, uint256 p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,uint256,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, address p1, string memory p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,string,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, address p1, string memory p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,string,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, address p1, string memory p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,string,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, address p1, string memory p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,string,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, address p1, bool p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,bool,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, address p1, bool p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,bool,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, address p1, bool p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,bool,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, address p1, bool p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,bool,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, address p1, address p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,address,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, address p1, address p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,address,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, address p1, address p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,address,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, address p1, address p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,address,address)\", p0, p1, p2, p3));\n\t}\n\n}\n" + }, + "lib/openzeppelin/interfaces/IERC4626.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\ninterface IERC4626 is IERC20, IERC20Metadata {\n event Deposit(address indexed caller, address indexed owner, uint256 assets, uint256 shares);\n\n event Withdraw(\n address indexed caller,\n address indexed receiver,\n address indexed owner,\n uint256 assets,\n uint256 shares\n );\n\n /**\n * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.\n *\n * - MUST be an ERC-20 token contract.\n * - MUST NOT revert.\n */\n function asset() external view returns (address assetTokenAddress);\n\n /**\n * @dev Returns the total amount of the underlying asset that is “managed” by Vault.\n *\n * - SHOULD include any compounding that occurs from yield.\n * - MUST be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT revert.\n */\n function totalAssets() external view returns (uint256 totalManagedAssets);\n\n /**\n * @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal\n * scenario where all the conditions are met.\n *\n * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n * - MUST NOT revert.\n *\n * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n * from.\n */\n function convertToShares(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal\n * scenario where all the conditions are met.\n *\n * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n * - MUST NOT revert.\n *\n * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n * from.\n */\n function convertToAssets(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,\n * through a deposit call.\n *\n * - MUST return a limited value if receiver is subject to some deposit limit.\n * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.\n * - MUST NOT revert.\n */\n function maxDeposit(address receiver) external view returns (uint256 maxAssets);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given\n * current on-chain conditions.\n *\n * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit\n * call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called\n * in the same transaction.\n * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the\n * deposit would be accepted, regardless if the user has enough tokens approved, etc.\n * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n */\n function previewDeposit(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.\n *\n * - MUST emit the Deposit event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * deposit execution, and are accounted for during deposit.\n * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not\n * approving enough underlying tokens to the Vault contract, etc).\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n */\n function deposit(uint256 assets, address receiver) external returns (uint256 shares);\n\n /**\n * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.\n * - MUST return a limited value if receiver is subject to some mint limit.\n * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.\n * - MUST NOT revert.\n */\n function maxMint(address receiver) external view returns (uint256 maxShares);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given\n * current on-chain conditions.\n *\n * - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call\n * in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the\n * same transaction.\n * - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint\n * would be accepted, regardless if the user has enough tokens approved, etc.\n * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by minting.\n */\n function previewMint(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.\n *\n * - MUST emit the Deposit event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint\n * execution, and are accounted for during mint.\n * - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not\n * approving enough underlying tokens to the Vault contract, etc).\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n */\n function mint(uint256 shares, address receiver) external returns (uint256 assets);\n\n /**\n * @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the\n * Vault, through a withdraw call.\n *\n * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n * - MUST NOT revert.\n */\n function maxWithdraw(address owner) external view returns (uint256 maxAssets);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,\n * given current on-chain conditions.\n *\n * - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw\n * call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if\n * called\n * in the same transaction.\n * - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though\n * the withdrawal would be accepted, regardless if the user has enough shares, etc.\n * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n */\n function previewWithdraw(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.\n *\n * - MUST emit the Withdraw event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * withdraw execution, and are accounted for during withdraw.\n * - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner\n * not having enough shares, etc).\n *\n * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n * Those methods should be performed separately.\n */\n function withdraw(\n uint256 assets,\n address receiver,\n address owner\n ) external returns (uint256 shares);\n\n /**\n * @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,\n * through a redeem call.\n *\n * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n * - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.\n * - MUST NOT revert.\n */\n function maxRedeem(address owner) external view returns (uint256 maxShares);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,\n * given current on-chain conditions.\n *\n * - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call\n * in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the\n * same transaction.\n * - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the\n * redemption would be accepted, regardless if the user has enough shares, etc.\n * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by redeeming.\n */\n function previewRedeem(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.\n *\n * - MUST emit the Withdraw event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * redeem execution, and are accounted for during redeem.\n * - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner\n * not having enough shares, etc).\n *\n * NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n * Those methods should be performed separately.\n */\n function redeem(\n uint256 shares,\n address receiver,\n address owner\n ) external returns (uint256 assets);\n}" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": [ + "ast" + ] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} \ No newline at end of file diff --git a/contracts/dev.env b/contracts/dev.env index e68f3e0a30..eae459ee53 100644 --- a/contracts/dev.env +++ b/contracts/dev.env @@ -63,4 +63,4 @@ VALIDATOR_KEYS_S3_BUCKET_NAME=[validator-keys-test | validator-keys] VALIDATOR_MASTER_ENCRYPTED_PRIVATE_KEY= # Beaconcha.in API key can be obtained by creating an account -BEACONCHAIN_API_KEY= \ No newline at end of file +BEACONCHAIN_API_KEY= diff --git a/contracts/docs/OETHVaultAdminSquashed.svg b/contracts/docs/OETHVaultAdminSquashed.svg index f95c5d2dc2..5eb606d36e 100644 --- a/contracts/docs/OETHVaultAdminSquashed.svg +++ b/contracts/docs/OETHVaultAdminSquashed.svg @@ -4,142 +4,156 @@ - - + + UmlClassDiagram - - + + -218 - -OETHVaultAdmin -../contracts/vault/OETHVaultAdmin.sol - -Private: -   initialized: bool <<Initializable>> -   initializing: bool <<Initializable>> -   ______gap: uint256[50] <<Initializable>> -   governorPosition: bytes32 <<Governable>> -   pendingGovernorPosition: bytes32 <<Governable>> -   reentryStatusPosition: bytes32 <<Governable>> -   _deprecated_rebaseHooksAddr: address <<VaultStorage>> -   _deprecated_uniswapAddr: address <<VaultStorage>> -   _deprecated_swapTokens: address[] <<VaultStorage>> -   __gap: uint256[50] <<VaultStorage>> -Internal: -   assets: mapping(address=>Asset) <<VaultStorage>> -   allAssets: address[] <<VaultStorage>> -   strategies: mapping(address=>Strategy) <<VaultStorage>> -   allStrategies: address[] <<VaultStorage>> -   oUSD: OUSD <<VaultStorage>> -   swapConfig: SwapConfig <<VaultStorage>> -Public: -   _NOT_ENTERED: uint256 <<Governable>> -   _ENTERED: uint256 <<Governable>> -   priceProvider: address <<VaultStorage>> -   rebasePaused: bool <<VaultStorage>> -   capitalPaused: bool <<VaultStorage>> -   redeemFeeBps: uint256 <<VaultStorage>> -   vaultBuffer: uint256 <<VaultStorage>> -   autoAllocateThreshold: uint256 <<VaultStorage>> -   rebaseThreshold: uint256 <<VaultStorage>> -   adminImplPosition: bytes32 <<VaultStorage>> -   strategistAddr: address <<VaultStorage>> -   assetDefaultStrategies: mapping(address=>address) <<VaultStorage>> -   maxSupplyDiff: uint256 <<VaultStorage>> -   trusteeAddress: address <<VaultStorage>> -   trusteeFeeBps: uint256 <<VaultStorage>> -   MINT_MINIMUM_UNIT_PRICE: uint256 <<VaultStorage>> -   ousdMetaStrategy: address <<VaultStorage>> -   netOusdMintedForStrategy: int256 <<VaultStorage>> -   netOusdMintForStrategyThreshold: uint256 <<VaultStorage>> -   MIN_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> -   MAX_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> - -Internal: -    _governor(): (governorOut: address) <<Governable>> -    _pendingGovernor(): (pendingGovernor: address) <<Governable>> -    _setGovernor(newGovernor: address) <<Governable>> -    _setPendingGovernor(newGovernor: address) <<Governable>> -    _changeGovernor(_newGovernor: address) <<Governable>> -    _depositToStrategy(_strategyToAddress: address, _assets: address[], _amounts: uint256[]) <<VaultAdmin>> -    _withdrawFromStrategy(_recipient: address, _strategyFromAddress: address, _assets: address[], _amounts: uint256[]) <<VaultAdmin>> -    _cacheDecimals(token: address) <<VaultAdmin>> -External: -    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>> -    claimGovernance() <<Governable>> -    setAdminImpl(newImpl: address) <<onlyGovernor>> <<VaultStorage>> -    setPriceProvider(_priceProvider: address) <<onlyGovernor>> <<VaultAdmin>> -    setRedeemFeeBps(_redeemFeeBps: uint256) <<onlyGovernor>> <<VaultAdmin>> -    setVaultBuffer(_vaultBuffer: uint256) <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    setAutoAllocateThreshold(_threshold: uint256) <<onlyGovernor>> <<VaultAdmin>> -    setRebaseThreshold(_threshold: uint256) <<onlyGovernor>> <<VaultAdmin>> -    setStrategistAddr(_address: address) <<onlyGovernor>> <<VaultAdmin>> -    setAssetDefaultStrategy(_asset: address, _strategy: address) <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    setNetOusdMintForStrategyThreshold(_threshold: uint256) <<onlyGovernor>> <<VaultAdmin>> -    swapCollateral(_fromAsset: address, _toAsset: address, _fromAssetAmount: uint256, _minToAssetAmount: uint256, _data: bytes): (toAssetAmount: uint256) <<nonReentrant, onlyGovernorOrStrategist>> <<VaultAdmin>> -    setSwapper(_swapperAddr: address) <<onlyGovernor>> <<VaultAdmin>> -    swapper(): (swapper_: address) <<VaultAdmin>> -    setSwapAllowedUndervalue(_basis: uint16) <<onlyGovernor>> <<VaultAdmin>> -    allowedSwapUndervalue(): (value: uint256) <<VaultAdmin>> -    setOracleSlippage(_asset: address, _allowedOracleSlippageBps: uint16) <<onlyGovernor>> <<VaultAdmin>> -    supportAsset(_asset: address, _unitConversion: uint8) <<onlyGovernor>> <<VaultAdmin>> -    removeAsset(_asset: address) <<onlyGovernor>> <<VaultAdmin>> -    cacheDecimals(_asset: address) <<onlyGovernor>> <<VaultAdmin>> -    approveStrategy(_addr: address) <<onlyGovernor>> <<VaultAdmin>> -    removeStrategy(_addr: address) <<onlyGovernor>> <<VaultAdmin>> -    depositToStrategy(_strategyToAddress: address, _assets: address[], _amounts: uint256[]) <<onlyGovernorOrStrategist, nonReentrant>> <<VaultAdmin>> -    withdrawFromStrategy(_strategyFromAddress: address, _assets: address[], _amounts: uint256[]) <<onlyGovernorOrStrategist, nonReentrant>> <<VaultAdmin>> -    setMaxSupplyDiff(_maxSupplyDiff: uint256) <<onlyGovernor>> <<VaultAdmin>> -    setTrusteeAddress(_address: address) <<onlyGovernor>> <<VaultAdmin>> -    setTrusteeFeeBps(_basis: uint256) <<onlyGovernor>> <<VaultAdmin>> -    setOusdMetaStrategy(_ousdMetaStrategy: address) <<onlyGovernor>> <<VaultAdmin>> -    pauseRebase() <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    unpauseRebase() <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    pauseCapital() <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    unpauseCapital() <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    transferToken(_asset: address, _amount: uint256) <<onlyGovernor>> <<VaultAdmin>> -    withdrawAllFromStrategy(_strategyAddr: address) <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    withdrawAllFromStrategies() <<onlyGovernorOrStrategist>> <<VaultAdmin>> -Public: -    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> -    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> -    <<event>> AssetSupported(_asset: address) <<VaultStorage>> -    <<event>> AssetRemoved(_asset: address) <<VaultStorage>> -    <<event>> AssetDefaultStrategyUpdated(_asset: address, _strategy: address) <<VaultStorage>> -    <<event>> AssetAllocated(_asset: address, _strategy: address, _amount: uint256) <<VaultStorage>> -    <<event>> StrategyApproved(_addr: address) <<VaultStorage>> -    <<event>> StrategyRemoved(_addr: address) <<VaultStorage>> -    <<event>> Mint(_addr: address, _value: uint256) <<VaultStorage>> -    <<event>> Redeem(_addr: address, _value: uint256) <<VaultStorage>> -    <<event>> CapitalPaused() <<VaultStorage>> -    <<event>> CapitalUnpaused() <<VaultStorage>> -    <<event>> RebasePaused() <<VaultStorage>> -    <<event>> RebaseUnpaused() <<VaultStorage>> -    <<event>> VaultBufferUpdated(_vaultBuffer: uint256) <<VaultStorage>> -    <<event>> OusdMetaStrategyUpdated(_ousdMetaStrategy: address) <<VaultStorage>> -    <<event>> RedeemFeeUpdated(_redeemFeeBps: uint256) <<VaultStorage>> -    <<event>> PriceProviderUpdated(_priceProvider: address) <<VaultStorage>> -    <<event>> AllocateThresholdUpdated(_threshold: uint256) <<VaultStorage>> -    <<event>> RebaseThresholdUpdated(_threshold: uint256) <<VaultStorage>> -    <<event>> StrategistUpdated(_address: address) <<VaultStorage>> -    <<event>> MaxSupplyDiffChanged(maxSupplyDiff: uint256) <<VaultStorage>> -    <<event>> YieldDistribution(_to: address, _yield: uint256, _fee: uint256) <<VaultStorage>> -    <<event>> TrusteeFeeBpsChanged(_basis: uint256) <<VaultStorage>> -    <<event>> TrusteeAddressChanged(_address: address) <<VaultStorage>> -    <<event>> NetOusdMintForStrategyThresholdChanged(_threshold: uint256) <<VaultStorage>> -    <<event>> SwapperChanged(_address: address) <<VaultStorage>> -    <<event>> SwapAllowedUndervalueChanged(_basis: uint256) <<VaultStorage>> -    <<event>> SwapSlippageChanged(_asset: address, _basis: uint256) <<VaultStorage>> -    <<event>> Swapped(_fromAsset: address, _toAsset: address, _fromAssetAmount: uint256, _toAssetAmount: uint256) <<VaultStorage>> -    <<modifier>> initializer() <<Initializable>> -    <<modifier>> onlyGovernor() <<Governable>> -    <<modifier>> nonReentrant() <<Governable>> -    <<modifier>> onlyGovernorOrStrategist() <<VaultAdmin>> -    constructor() <<Governable>> -    governor(): address <<Governable>> -    isGovernor(): bool <<Governable>> +225 + +OETHVaultAdmin +../contracts/vault/OETHVaultAdmin.sol + +Private: +   initialized: bool <<Initializable>> +   initializing: bool <<Initializable>> +   ______gap: uint256[50] <<Initializable>> +   governorPosition: bytes32 <<Governable>> +   pendingGovernorPosition: bytes32 <<Governable>> +   reentryStatusPosition: bytes32 <<Governable>> +   _deprecated_rebaseHooksAddr: address <<VaultStorage>> +   _deprecated_uniswapAddr: address <<VaultStorage>> +   _deprecated_swapTokens: address[] <<VaultStorage>> +   __gap: uint256[46] <<VaultStorage>> +Internal: +   assets: mapping(address=>Asset) <<VaultStorage>> +   allAssets: address[] <<VaultStorage>> +   strategies: mapping(address=>Strategy) <<VaultStorage>> +   allStrategies: address[] <<VaultStorage>> +   oUSD: OUSD <<VaultStorage>> +   swapConfig: SwapConfig <<VaultStorage>> +Public: +   _NOT_ENTERED: uint256 <<Governable>> +   _ENTERED: uint256 <<Governable>> +   priceProvider: address <<VaultStorage>> +   rebasePaused: bool <<VaultStorage>> +   capitalPaused: bool <<VaultStorage>> +   redeemFeeBps: uint256 <<VaultStorage>> +   vaultBuffer: uint256 <<VaultStorage>> +   autoAllocateThreshold: uint256 <<VaultStorage>> +   rebaseThreshold: uint256 <<VaultStorage>> +   adminImplPosition: bytes32 <<VaultStorage>> +   strategistAddr: address <<VaultStorage>> +   assetDefaultStrategies: mapping(address=>address) <<VaultStorage>> +   maxSupplyDiff: uint256 <<VaultStorage>> +   trusteeAddress: address <<VaultStorage>> +   trusteeFeeBps: uint256 <<VaultStorage>> +   MINT_MINIMUM_UNIT_PRICE: uint256 <<VaultStorage>> +   ousdMetaStrategy: address <<VaultStorage>> +   netOusdMintedForStrategy: int256 <<VaultStorage>> +   netOusdMintForStrategyThreshold: uint256 <<VaultStorage>> +   MIN_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> +   MAX_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> +   dripper: address <<VaultStorage>> +   withdrawalQueueMetadata: WithdrawalQueueMetadata <<VaultStorage>> +   withdrawalRequests: mapping(uint256=>WithdrawalRequest) <<VaultStorage>> +   weth: address <<OETHVaultAdmin>> + +Internal: +    _governor(): (governorOut: address) <<Governable>> +    _pendingGovernor(): (pendingGovernor: address) <<Governable>> +    _setGovernor(newGovernor: address) <<Governable>> +    _setPendingGovernor(newGovernor: address) <<Governable>> +    _changeGovernor(_newGovernor: address) <<Governable>> +    _swapCollateral(_fromAsset: address, _toAsset: address, _fromAssetAmount: uint256, _minToAssetAmount: uint256, _data: bytes): (toAssetAmount: uint256) <<OETHVaultAdmin>> +    _depositToStrategy(_strategyToAddress: address, _assets: address[], _amounts: uint256[]) <<OETHVaultAdmin>> +    _withdrawFromStrategy(_recipient: address, _strategyFromAddress: address, _assets: address[], _amounts: uint256[]) <<OETHVaultAdmin>> +    _withdrawAllFromStrategy(_strategyAddr: address) <<OETHVaultAdmin>> +    _withdrawAllFromStrategies() <<OETHVaultAdmin>> +    _cacheDecimals(token: address) <<VaultAdmin>> +    _wethAvailable(): (wethAvailable: uint256) <<OETHVaultAdmin>> +External: +    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>> +    claimGovernance() <<Governable>> +    setAdminImpl(newImpl: address) <<onlyGovernor>> <<VaultStorage>> +    setPriceProvider(_priceProvider: address) <<onlyGovernor>> <<VaultAdmin>> +    setRedeemFeeBps(_redeemFeeBps: uint256) <<onlyGovernor>> <<VaultAdmin>> +    setVaultBuffer(_vaultBuffer: uint256) <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    setAutoAllocateThreshold(_threshold: uint256) <<onlyGovernor>> <<VaultAdmin>> +    setRebaseThreshold(_threshold: uint256) <<onlyGovernor>> <<VaultAdmin>> +    setStrategistAddr(_address: address) <<onlyGovernor>> <<VaultAdmin>> +    setAssetDefaultStrategy(_asset: address, _strategy: address) <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    setNetOusdMintForStrategyThreshold(_threshold: uint256) <<onlyGovernor>> <<VaultAdmin>> +    setDripper(_dripper: address) <<onlyGovernor>> <<VaultAdmin>> +    swapCollateral(_fromAsset: address, _toAsset: address, _fromAssetAmount: uint256, _minToAssetAmount: uint256, _data: bytes): (toAssetAmount: uint256) <<nonReentrant, onlyGovernorOrStrategist>> <<VaultAdmin>> +    setSwapper(_swapperAddr: address) <<onlyGovernor>> <<VaultAdmin>> +    swapper(): (swapper_: address) <<VaultAdmin>> +    setSwapAllowedUndervalue(_basis: uint16) <<onlyGovernor>> <<VaultAdmin>> +    allowedSwapUndervalue(): (value: uint256) <<VaultAdmin>> +    setOracleSlippage(_asset: address, _allowedOracleSlippageBps: uint16) <<onlyGovernor>> <<VaultAdmin>> +    supportAsset(_asset: address, _unitConversion: uint8) <<onlyGovernor>> <<VaultAdmin>> +    removeAsset(_asset: address) <<onlyGovernor>> <<VaultAdmin>> +    cacheDecimals(_asset: address) <<onlyGovernor>> <<VaultAdmin>> +    approveStrategy(_addr: address) <<onlyGovernor>> <<VaultAdmin>> +    removeStrategy(_addr: address) <<onlyGovernor>> <<VaultAdmin>> +    depositToStrategy(_strategyToAddress: address, _assets: address[], _amounts: uint256[]) <<onlyGovernorOrStrategist, nonReentrant>> <<VaultAdmin>> +    withdrawFromStrategy(_strategyFromAddress: address, _assets: address[], _amounts: uint256[]) <<onlyGovernorOrStrategist, nonReentrant>> <<VaultAdmin>> +    setMaxSupplyDiff(_maxSupplyDiff: uint256) <<onlyGovernor>> <<VaultAdmin>> +    setTrusteeAddress(_address: address) <<onlyGovernor>> <<VaultAdmin>> +    setTrusteeFeeBps(_basis: uint256) <<onlyGovernor>> <<VaultAdmin>> +    setOusdMetaStrategy(_ousdMetaStrategy: address) <<onlyGovernor>> <<VaultAdmin>> +    pauseRebase() <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    unpauseRebase() <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    pauseCapital() <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    unpauseCapital() <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    transferToken(_asset: address, _amount: uint256) <<onlyGovernor>> <<VaultAdmin>> +    withdrawAllFromStrategy(_strategyAddr: address) <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    withdrawAllFromStrategies() <<onlyGovernorOrStrategist>> <<VaultAdmin>> +Public: +    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> AssetSupported(_asset: address) <<VaultStorage>> +    <<event>> AssetRemoved(_asset: address) <<VaultStorage>> +    <<event>> AssetDefaultStrategyUpdated(_asset: address, _strategy: address) <<VaultStorage>> +    <<event>> AssetAllocated(_asset: address, _strategy: address, _amount: uint256) <<VaultStorage>> +    <<event>> StrategyApproved(_addr: address) <<VaultStorage>> +    <<event>> StrategyRemoved(_addr: address) <<VaultStorage>> +    <<event>> Mint(_addr: address, _value: uint256) <<VaultStorage>> +    <<event>> Redeem(_addr: address, _value: uint256) <<VaultStorage>> +    <<event>> CapitalPaused() <<VaultStorage>> +    <<event>> CapitalUnpaused() <<VaultStorage>> +    <<event>> RebasePaused() <<VaultStorage>> +    <<event>> RebaseUnpaused() <<VaultStorage>> +    <<event>> VaultBufferUpdated(_vaultBuffer: uint256) <<VaultStorage>> +    <<event>> OusdMetaStrategyUpdated(_ousdMetaStrategy: address) <<VaultStorage>> +    <<event>> RedeemFeeUpdated(_redeemFeeBps: uint256) <<VaultStorage>> +    <<event>> PriceProviderUpdated(_priceProvider: address) <<VaultStorage>> +    <<event>> AllocateThresholdUpdated(_threshold: uint256) <<VaultStorage>> +    <<event>> RebaseThresholdUpdated(_threshold: uint256) <<VaultStorage>> +    <<event>> StrategistUpdated(_address: address) <<VaultStorage>> +    <<event>> MaxSupplyDiffChanged(maxSupplyDiff: uint256) <<VaultStorage>> +    <<event>> YieldDistribution(_to: address, _yield: uint256, _fee: uint256) <<VaultStorage>> +    <<event>> TrusteeFeeBpsChanged(_basis: uint256) <<VaultStorage>> +    <<event>> TrusteeAddressChanged(_address: address) <<VaultStorage>> +    <<event>> NetOusdMintForStrategyThresholdChanged(_threshold: uint256) <<VaultStorage>> +    <<event>> SwapperChanged(_address: address) <<VaultStorage>> +    <<event>> SwapAllowedUndervalueChanged(_basis: uint256) <<VaultStorage>> +    <<event>> SwapSlippageChanged(_asset: address, _basis: uint256) <<VaultStorage>> +    <<event>> Swapped(_fromAsset: address, _toAsset: address, _fromAssetAmount: uint256, _toAssetAmount: uint256) <<VaultStorage>> +    <<event>> DripperChanged(_dripper: address) <<VaultStorage>> +    <<event>> WithdrawalRequested(_withdrawer: address, _requestId: uint256, _amount: uint256, _queued: uint256) <<VaultStorage>> +    <<event>> WithdrawalClaimed(_withdrawer: address, _requestId: uint256, _amount: uint256) <<VaultStorage>> +    <<event>> WithdrawalClaimable(_claimable: uint256, _newClaimable: uint256) <<VaultStorage>> +    <<modifier>> initializer() <<Initializable>> +    <<modifier>> onlyGovernor() <<Governable>> +    <<modifier>> nonReentrant() <<Governable>> +    <<modifier>> onlyGovernorOrStrategist() <<VaultAdmin>> +    constructor() <<Governable>> +    governor(): address <<Governable>> +    isGovernor(): bool <<Governable>> +    constructor(_weth: address) <<OETHVaultAdmin>> diff --git a/contracts/docs/OETHVaultCoreSquashed.svg b/contracts/docs/OETHVaultCoreSquashed.svg index 320d7fd8d5..dfca8fbe99 100644 --- a/contracts/docs/OETHVaultCoreSquashed.svg +++ b/contracts/docs/OETHVaultCoreSquashed.svg @@ -4,139 +4,154 @@ - - + + UmlClassDiagram - - + + -219 - -OETHVaultCore -../contracts/vault/OETHVaultCore.sol - -Private: -   initialized: bool <<Initializable>> -   initializing: bool <<Initializable>> -   ______gap: uint256[50] <<Initializable>> -   governorPosition: bytes32 <<Governable>> -   pendingGovernorPosition: bytes32 <<Governable>> -   reentryStatusPosition: bytes32 <<Governable>> -   _deprecated_rebaseHooksAddr: address <<VaultStorage>> -   _deprecated_uniswapAddr: address <<VaultStorage>> -   _deprecated_swapTokens: address[] <<VaultStorage>> -   __gap: uint256[50] <<VaultStorage>> -Internal: -   assets: mapping(address=>Asset) <<VaultStorage>> -   allAssets: address[] <<VaultStorage>> -   strategies: mapping(address=>Strategy) <<VaultStorage>> -   allStrategies: address[] <<VaultStorage>> -   oUSD: OUSD <<VaultStorage>> -   swapConfig: SwapConfig <<VaultStorage>> -   MAX_INT: uint256 <<VaultCore>> -   MAX_UINT: uint256 <<VaultCore>> -Public: -   _NOT_ENTERED: uint256 <<Governable>> -   _ENTERED: uint256 <<Governable>> -   priceProvider: address <<VaultStorage>> -   rebasePaused: bool <<VaultStorage>> -   capitalPaused: bool <<VaultStorage>> -   redeemFeeBps: uint256 <<VaultStorage>> -   vaultBuffer: uint256 <<VaultStorage>> -   autoAllocateThreshold: uint256 <<VaultStorage>> -   rebaseThreshold: uint256 <<VaultStorage>> -   adminImplPosition: bytes32 <<VaultStorage>> -   strategistAddr: address <<VaultStorage>> -   assetDefaultStrategies: mapping(address=>address) <<VaultStorage>> -   maxSupplyDiff: uint256 <<VaultStorage>> -   trusteeAddress: address <<VaultStorage>> -   trusteeFeeBps: uint256 <<VaultStorage>> -   MINT_MINIMUM_UNIT_PRICE: uint256 <<VaultStorage>> -   ousdMetaStrategy: address <<VaultStorage>> -   netOusdMintedForStrategy: int256 <<VaultStorage>> -   netOusdMintForStrategyThreshold: uint256 <<VaultStorage>> -   MIN_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> -   MAX_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> -   weth: address <<OETHVaultCore>> -   wethAssetIndex: uint256 <<OETHVaultCore>> - -Private: -    abs(x: int256): uint256 <<VaultCore>> -Internal: -    _governor(): (governorOut: address) <<Governable>> -    _pendingGovernor(): (pendingGovernor: address) <<Governable>> -    _setGovernor(newGovernor: address) <<Governable>> -    _setPendingGovernor(newGovernor: address) <<Governable>> -    _changeGovernor(_newGovernor: address) <<Governable>> -    _mint(_asset: address, _amount: uint256, _minimumOusdAmount: uint256) <<OETHVaultCore>> -    _redeem(_amount: uint256, _minimumUnitAmount: uint256) <<OETHVaultCore>> -    _postRedeem(_amount: uint256) <<VaultCore>> -    _allocate() <<VaultCore>> -    _rebase(): uint256 <<whenNotRebasePaused>> <<VaultCore>> -    _totalValue(): (value: uint256) <<VaultCore>> -    _totalValueInVault(): (value: uint256) <<VaultCore>> -    _totalValueInStrategies(): (value: uint256) <<VaultCore>> -    _totalValueInStrategy(_strategyAddr: address): (value: uint256) <<VaultCore>> -    _checkBalance(_asset: address): (balance: uint256) <<VaultCore>> -    _calculateRedeemOutputs(_amount: uint256): (outputs: uint256[]) <<OETHVaultCore>> -    _toUnits(_raw: uint256, _asset: address): uint256 <<VaultCore>> -    _toUnitPrice(_asset: address, isMint: bool): (price: uint256) <<VaultCore>> -    _getDecimals(_asset: address): (decimals: uint256) <<VaultCore>> -External: -    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>> -    claimGovernance() <<Governable>> -    setAdminImpl(newImpl: address) <<onlyGovernor>> <<VaultStorage>> -    initialize(_priceProvider: address, _oToken: address) <<onlyGovernor, initializer>> <<VaultInitializer>> -    mint(_asset: address, _amount: uint256, _minimumOusdAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> -    mintForStrategy(_amount: uint256) <<whenNotCapitalPaused, onlyOusdMetaStrategy>> <<VaultCore>> -    redeem(_amount: uint256, _minimumUnitAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> -    burnForStrategy(_amount: uint256) <<whenNotCapitalPaused, onlyOusdMetaStrategy>> <<VaultCore>> -    redeemAll(_minimumUnitAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> -    allocate() <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> -    rebase() <<nonReentrant>> <<VaultCore>> -    totalValue(): (value: uint256) <<VaultCore>> -    checkBalance(_asset: address): uint256 <<VaultCore>> -    calculateRedeemOutputs(_amount: uint256): uint256[] <<VaultCore>> -    priceUnitMint(asset: address): (price: uint256) <<VaultCore>> -    priceUnitRedeem(asset: address): (price: uint256) <<VaultCore>> -    getAllAssets(): address[] <<VaultCore>> -    getStrategyCount(): uint256 <<VaultCore>> -    getAllStrategies(): address[] <<VaultCore>> -    isSupportedAsset(_asset: address): bool <<VaultCore>> -    null() <<VaultCore>> -    cacheWETHAssetIndex() <<onlyGovernor>> <<OETHVaultCore>> -Public: -    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> -    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> -    <<event>> AssetSupported(_asset: address) <<VaultStorage>> -    <<event>> AssetRemoved(_asset: address) <<VaultStorage>> -    <<event>> AssetDefaultStrategyUpdated(_asset: address, _strategy: address) <<VaultStorage>> -    <<event>> AssetAllocated(_asset: address, _strategy: address, _amount: uint256) <<VaultStorage>> -    <<event>> StrategyApproved(_addr: address) <<VaultStorage>> -    <<event>> StrategyRemoved(_addr: address) <<VaultStorage>> -    <<event>> Mint(_addr: address, _value: uint256) <<VaultStorage>> -    <<event>> Redeem(_addr: address, _value: uint256) <<VaultStorage>> -    <<event>> CapitalPaused() <<VaultStorage>> -    <<event>> CapitalUnpaused() <<VaultStorage>> -    <<event>> RebasePaused() <<VaultStorage>> -    <<event>> RebaseUnpaused() <<VaultStorage>> -    <<event>> VaultBufferUpdated(_vaultBuffer: uint256) <<VaultStorage>> -    <<event>> OusdMetaStrategyUpdated(_ousdMetaStrategy: address) <<VaultStorage>> -    <<event>> RedeemFeeUpdated(_redeemFeeBps: uint256) <<VaultStorage>> -    <<event>> PriceProviderUpdated(_priceProvider: address) <<VaultStorage>> -    <<event>> AllocateThresholdUpdated(_threshold: uint256) <<VaultStorage>> -    <<event>> RebaseThresholdUpdated(_threshold: uint256) <<VaultStorage>> -    <<event>> StrategistUpdated(_address: address) <<VaultStorage>> -    <<event>> MaxSupplyDiffChanged(maxSupplyDiff: uint256) <<VaultStorage>> -    <<event>> YieldDistribution(_to: address, _yield: uint256, _fee: uint256) <<VaultStorage>> -    <<event>> TrusteeFeeBpsChanged(_basis: uint256) <<VaultStorage>> -    <<event>> TrusteeAddressChanged(_address: address) <<VaultStorage>> -    <<event>> NetOusdMintForStrategyThresholdChanged(_threshold: uint256) <<VaultStorage>> -    <<event>> SwapperChanged(_address: address) <<VaultStorage>> -    <<event>> SwapAllowedUndervalueChanged(_basis: uint256) <<VaultStorage>> -    <<event>> SwapSlippageChanged(_asset: address, _basis: uint256) <<VaultStorage>> -    <<event>> Swapped(_fromAsset: address, _toAsset: address, _fromAssetAmount: uint256, _toAssetAmount: uint256) <<VaultStorage>> +226 + +OETHVaultCore +../contracts/vault/OETHVaultCore.sol + +Private: +   initialized: bool <<Initializable>> +   initializing: bool <<Initializable>> +   ______gap: uint256[50] <<Initializable>> +   governorPosition: bytes32 <<Governable>> +   pendingGovernorPosition: bytes32 <<Governable>> +   reentryStatusPosition: bytes32 <<Governable>> +   _deprecated_rebaseHooksAddr: address <<VaultStorage>> +   _deprecated_uniswapAddr: address <<VaultStorage>> +   _deprecated_swapTokens: address[] <<VaultStorage>> +   __gap: uint256[46] <<VaultStorage>> +Internal: +   assets: mapping(address=>Asset) <<VaultStorage>> +   allAssets: address[] <<VaultStorage>> +   strategies: mapping(address=>Strategy) <<VaultStorage>> +   allStrategies: address[] <<VaultStorage>> +   oUSD: OUSD <<VaultStorage>> +   swapConfig: SwapConfig <<VaultStorage>> +   MAX_INT: uint256 <<VaultCore>> +   MAX_UINT: uint256 <<VaultCore>> +Public: +   _NOT_ENTERED: uint256 <<Governable>> +   _ENTERED: uint256 <<Governable>> +   priceProvider: address <<VaultStorage>> +   rebasePaused: bool <<VaultStorage>> +   capitalPaused: bool <<VaultStorage>> +   redeemFeeBps: uint256 <<VaultStorage>> +   vaultBuffer: uint256 <<VaultStorage>> +   autoAllocateThreshold: uint256 <<VaultStorage>> +   rebaseThreshold: uint256 <<VaultStorage>> +   adminImplPosition: bytes32 <<VaultStorage>> +   strategistAddr: address <<VaultStorage>> +   assetDefaultStrategies: mapping(address=>address) <<VaultStorage>> +   maxSupplyDiff: uint256 <<VaultStorage>> +   trusteeAddress: address <<VaultStorage>> +   trusteeFeeBps: uint256 <<VaultStorage>> +   MINT_MINIMUM_UNIT_PRICE: uint256 <<VaultStorage>> +   ousdMetaStrategy: address <<VaultStorage>> +   netOusdMintedForStrategy: int256 <<VaultStorage>> +   netOusdMintForStrategyThreshold: uint256 <<VaultStorage>> +   MIN_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> +   MAX_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> +   dripper: address <<VaultStorage>> +   withdrawalQueueMetadata: WithdrawalQueueMetadata <<VaultStorage>> +   withdrawalRequests: mapping(uint256=>WithdrawalRequest) <<VaultStorage>> +   CLAIM_DELAY: uint256 <<OETHVaultCore>> +   weth: address <<OETHVaultCore>> +   wethAssetIndex: uint256 <<OETHVaultCore>> + +Private: +    abs(x: int256): uint256 <<VaultCore>> +Internal: +    _governor(): (governorOut: address) <<Governable>> +    _pendingGovernor(): (pendingGovernor: address) <<Governable>> +    _setGovernor(newGovernor: address) <<Governable>> +    _setPendingGovernor(newGovernor: address) <<Governable>> +    _changeGovernor(_newGovernor: address) <<Governable>> +    _mint(_asset: address, _amount: uint256, _minimumOusdAmount: uint256) <<OETHVaultCore>> +    _redeem(_amount: uint256, _minimumUnitAmount: uint256) <<OETHVaultCore>> +    _postRedeem(_amount: uint256) <<VaultCore>> +    _allocate() <<OETHVaultCore>> +    _rebase(): uint256 <<whenNotRebasePaused>> <<VaultCore>> +    _totalValue(): (value: uint256) <<OETHVaultCore>> +    _totalValueInVault(): (value: uint256) <<OETHVaultCore>> +    _totalValueInStrategies(): (value: uint256) <<VaultCore>> +    _totalValueInStrategy(_strategyAddr: address): (value: uint256) <<VaultCore>> +    _checkBalance(_asset: address): (balance: uint256) <<OETHVaultCore>> +    _calculateRedeemOutputs(_amount: uint256): (outputs: uint256[]) <<OETHVaultCore>> +    _toUnits(_raw: uint256, _asset: address): uint256 <<VaultCore>> +    _toUnitPrice(_asset: address, isMint: bool): (price: uint256) <<VaultCore>> +    _getDecimals(_asset: address): (decimals: uint256) <<VaultCore>> +    _claimWithdrawal(requestId: uint256): (amount: uint256) <<OETHVaultCore>> +    _addWithdrawalQueueLiquidity(): (addedClaimable: uint256) <<OETHVaultCore>> +    _wethAvailable(): (wethAvailable: uint256) <<OETHVaultCore>> +External: +    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>> +    claimGovernance() <<Governable>> +    setAdminImpl(newImpl: address) <<onlyGovernor>> <<VaultStorage>> +    initialize(_priceProvider: address, _oToken: address) <<onlyGovernor, initializer>> <<VaultInitializer>> +    mint(_asset: address, _amount: uint256, _minimumOusdAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> +    mintForStrategy(_amount: uint256) <<whenNotCapitalPaused, onlyOusdMetaStrategy>> <<VaultCore>> +    redeem(_amount: uint256, _minimumUnitAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> +    burnForStrategy(_amount: uint256) <<whenNotCapitalPaused, onlyOusdMetaStrategy>> <<VaultCore>> +    redeemAll(_minimumUnitAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> +    allocate() <<whenNotCapitalPaused, nonReentrant>> <<OETHVaultCore>> +    rebase() <<nonReentrant>> <<VaultCore>> +    totalValue(): (value: uint256) <<VaultCore>> +    checkBalance(_asset: address): uint256 <<VaultCore>> +    calculateRedeemOutputs(_amount: uint256): uint256[] <<VaultCore>> +    priceUnitMint(asset: address): (price: uint256) <<VaultCore>> +    priceUnitRedeem(asset: address): (price: uint256) <<VaultCore>> +    getAllAssets(): address[] <<VaultCore>> +    getStrategyCount(): uint256 <<VaultCore>> +    getAllStrategies(): address[] <<VaultCore>> +    isSupportedAsset(_asset: address): bool <<VaultCore>> +    null() <<VaultCore>> +    cacheWETHAssetIndex() <<onlyGovernor>> <<OETHVaultCore>> +    requestWithdrawal(_amount: uint256): (requestId: uint256, queued: uint256) <<whenNotCapitalPaused, nonReentrant>> <<OETHVaultCore>> +    claimWithdrawal(_requestId: uint256): (amount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<OETHVaultCore>> +    claimWithdrawals(_requestIds: uint256[]): (amounts: uint256[], totalAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<OETHVaultCore>> +    addWithdrawalQueueLiquidity() <<OETHVaultCore>> +Public: +    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> AssetSupported(_asset: address) <<VaultStorage>> +    <<event>> AssetRemoved(_asset: address) <<VaultStorage>> +    <<event>> AssetDefaultStrategyUpdated(_asset: address, _strategy: address) <<VaultStorage>> +    <<event>> AssetAllocated(_asset: address, _strategy: address, _amount: uint256) <<VaultStorage>> +    <<event>> StrategyApproved(_addr: address) <<VaultStorage>> +    <<event>> StrategyRemoved(_addr: address) <<VaultStorage>> +    <<event>> Mint(_addr: address, _value: uint256) <<VaultStorage>> +    <<event>> Redeem(_addr: address, _value: uint256) <<VaultStorage>> +    <<event>> CapitalPaused() <<VaultStorage>> +    <<event>> CapitalUnpaused() <<VaultStorage>> +    <<event>> RebasePaused() <<VaultStorage>> +    <<event>> RebaseUnpaused() <<VaultStorage>> +    <<event>> VaultBufferUpdated(_vaultBuffer: uint256) <<VaultStorage>> +    <<event>> OusdMetaStrategyUpdated(_ousdMetaStrategy: address) <<VaultStorage>> +    <<event>> RedeemFeeUpdated(_redeemFeeBps: uint256) <<VaultStorage>> +    <<event>> PriceProviderUpdated(_priceProvider: address) <<VaultStorage>> +    <<event>> AllocateThresholdUpdated(_threshold: uint256) <<VaultStorage>> +    <<event>> RebaseThresholdUpdated(_threshold: uint256) <<VaultStorage>> +    <<event>> StrategistUpdated(_address: address) <<VaultStorage>> +    <<event>> MaxSupplyDiffChanged(maxSupplyDiff: uint256) <<VaultStorage>> +    <<event>> YieldDistribution(_to: address, _yield: uint256, _fee: uint256) <<VaultStorage>> +    <<event>> TrusteeFeeBpsChanged(_basis: uint256) <<VaultStorage>> +    <<event>> TrusteeAddressChanged(_address: address) <<VaultStorage>> +    <<event>> NetOusdMintForStrategyThresholdChanged(_threshold: uint256) <<VaultStorage>> +    <<event>> SwapperChanged(_address: address) <<VaultStorage>> +    <<event>> SwapAllowedUndervalueChanged(_basis: uint256) <<VaultStorage>> +    <<event>> SwapSlippageChanged(_asset: address, _basis: uint256) <<VaultStorage>> +    <<event>> Swapped(_fromAsset: address, _toAsset: address, _fromAssetAmount: uint256, _toAssetAmount: uint256) <<VaultStorage>> +    <<event>> DripperChanged(_dripper: address) <<VaultStorage>> +    <<event>> WithdrawalRequested(_withdrawer: address, _requestId: uint256, _amount: uint256, _queued: uint256) <<VaultStorage>> +    <<event>> WithdrawalClaimed(_withdrawer: address, _requestId: uint256, _amount: uint256) <<VaultStorage>> +    <<event>> WithdrawalClaimable(_claimable: uint256, _newClaimable: uint256) <<VaultStorage>>    <<modifier>> initializer() <<Initializable>>    <<modifier>> onlyGovernor() <<Governable>>    <<modifier>> nonReentrant() <<Governable>> diff --git a/contracts/docs/OETHVaultHierarchy.svg b/contracts/docs/OETHVaultHierarchy.svg index 2d05c5e79d..0e7d267fbb 100644 --- a/contracts/docs/OETHVaultHierarchy.svg +++ b/contracts/docs/OETHVaultHierarchy.svg @@ -4,280 +4,154 @@ - - + + UmlClassDiagram - + 20 - -Governable -../contracts/governance/Governable.sol + +Governable +../contracts/governance/Governable.sol - + -43 - -<<Interface>> -IGetExchangeRateToken -../contracts/interfaces/IGetExchangeRateToken.sol +208 + +OUSD +../contracts/token/OUSD.sol - - -50 - -<<Interface>> -IOracle -../contracts/interfaces/IOracle.sol + + +208->20 + + - - -56 - -<<Interface>> -IStrategy -../contracts/interfaces/IStrategy.sol + + +217 + +<<Abstract>> +Initializable +../contracts/utils/Initializable.sol - - -57 - -<<Interface>> -ISwapper -../contracts/interfaces/ISwapper.sol + + +208->217 + + - - -60 - -<<Interface>> -IVault -../contracts/interfaces/IVault.sol + + +220 + +<<Abstract>> +InitializableERC20Detailed +../contracts/utils/InitializableERC20Detailed.sol - - -225 - -VaultStorage -../contracts/vault/VaultStorage.sol + + +208->220 + + - - -60->225 - - + + +223 + +OETHVaultAdmin +../contracts/vault/OETHVaultAdmin.sol - + -203 - -OUSD -../contracts/token/OUSD.sol +227 + +VaultAdmin +../contracts/vault/VaultAdmin.sol - + -203->20 - - +223->227 + + - - -212 - -<<Abstract>> -Initializable -../contracts/utils/Initializable.sol - - - -203->212 - - - - - -215 - -<<Abstract>> -InitializableERC20Detailed -../contracts/utils/InitializableERC20Detailed.sol - - - -203->215 - - + + +224 + +OETHVaultCore +../contracts/vault/OETHVaultCore.sol - - -694 - -<<Interface>> -IERC20 -../node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol + + +228 + +VaultCore +../contracts/vault/VaultCore.sol - + -215->694 - - +224->228 + + - + -218 - -OETHVaultAdmin -../contracts/vault/OETHVaultAdmin.sol - - - -222 - -VaultAdmin -../contracts/vault/VaultAdmin.sol +230 + +VaultStorage +../contracts/vault/VaultStorage.sol - + -218->222 - - - - - -219 - -OETHVaultCore -../contracts/vault/OETHVaultCore.sol +227->230 + + - - -219->56 - - - - - -223 - -VaultCore -../contracts/vault/VaultCore.sol + + +229 + +VaultInitializer +../contracts/vault/VaultInitializer.sol - + -219->223 - - +228->229 + + - - -219->694 - - + + +229->208 + + - - -222->50 - - + + +229->230 + + - + -222->56 - - - - - -222->57 - - - - - -222->60 - - +230->20 + + - - -222->225 - - - - + -222->694 - - - - - -223->43 - - +230->208 + + - - -223->50 - - - - - -223->56 - - - - - -224 - -VaultInitializer -../contracts/vault/VaultInitializer.sol - - - -223->224 - - - - - -223->694 - - - - - -224->203 - - - - - -224->225 - - - - - -225->20 - - - - - -225->203 - - - - - -225->212 - - + + +230->217 + + diff --git a/contracts/docs/OETHVaultStorage.svg b/contracts/docs/OETHVaultStorage.svg index 0d73565a93..5c2084d795 100644 --- a/contracts/docs/OETHVaultStorage.svg +++ b/contracts/docs/OETHVaultStorage.svg @@ -4,306 +4,344 @@ - - + + StorageDiagram - - + + -7 - -OETHVaultCore <<Contract>> - -slot - -0 - -1-50 - -51 - -52 - -53 - -54 - -55 - -56 - -57 - -58 - -59 - -60 - -61 - -62 - -63 - -64 - -65 - -66 - -67 - -68 - -69 - -70 - -71 - -72 - -73-122 - -123 - -type: <inherited contract>.variable (bytes) - -unallocated (30) - -bool: Initializable.initializing (1) - -bool: Initializable.initialized (1) - -uint256[50]: Initializable.______gap (1600) - -mapping(address=>Asset): VaultStorage.assets (32) - -address[]: VaultStorage.allAssets (32) - -mapping(address=>Strategy): VaultStorage.strategies (32) - -address[]: VaultStorage.allStrategies (32) - -unallocated (10) - -bool: VaultStorage.capitalPaused (1) - -bool: VaultStorage.rebasePaused (1) - -address: VaultStorage.priceProvider (20) - -uint256: VaultStorage.redeemFeeBps (32) - -uint256: VaultStorage.vaultBuffer (32) - -uint256: VaultStorage.autoAllocateThreshold (32) - -uint256: VaultStorage.rebaseThreshold (32) - -unallocated (12) - -OUSD: VaultStorage.oUSD (20) - -unallocated (12) - -address: VaultStorage._deprecated_rebaseHooksAddr (20) - -unallocated (12) - -address: VaultStorage._deprecated_uniswapAddr (20) - -unallocated (12) - -address: VaultStorage.strategistAddr (20) - -mapping(address=>address): VaultStorage.assetDefaultStrategies (32) - -uint256: VaultStorage.maxSupplyDiff (32) - -unallocated (12) - -address: VaultStorage.trusteeAddress (20) - -uint256: VaultStorage.trusteeFeeBps (32) - -address[]: VaultStorage._deprecated_swapTokens (32) - -unallocated (12) - -address: VaultStorage.ousdMetaStrategy (20) - -int256: VaultStorage.netOusdMintedForStrategy (32) - -uint256: VaultStorage.netOusdMintForStrategyThreshold (32) - -SwapConfig: VaultStorage.swapConfig (32) - -uint256[50]: VaultStorage.__gap (1600) - -uint256: wethAssetIndex (32) +8 + +OETHVaultCore <<Contract>> + +slot + +0 + +1-50 + +51 + +52 + +53 + +54 + +55 + +56 + +57 + +58 + +59 + +60 + +61 + +62 + +63 + +64 + +65 + +66 + +67 + +68 + +69 + +70 + +71 + +72 + +73 + +74-75 + +76 + +77-122 + +123 + +type: <inherited contract>.variable (bytes) + +unallocated (30) + +bool: Initializable.initializing (1) + +bool: Initializable.initialized (1) + +uint256[50]: Initializable.______gap (1600) + +mapping(address=>Asset): VaultStorage.assets (32) + +address[]: VaultStorage.allAssets (32) + +mapping(address=>Strategy): VaultStorage.strategies (32) + +address[]: VaultStorage.allStrategies (32) + +unallocated (10) + +bool: VaultStorage.capitalPaused (1) + +bool: VaultStorage.rebasePaused (1) + +address: VaultStorage.priceProvider (20) + +uint256: VaultStorage.redeemFeeBps (32) + +uint256: VaultStorage.vaultBuffer (32) + +uint256: VaultStorage.autoAllocateThreshold (32) + +uint256: VaultStorage.rebaseThreshold (32) + +unallocated (12) + +OUSD: VaultStorage.oUSD (20) + +unallocated (12) + +address: VaultStorage._deprecated_rebaseHooksAddr (20) + +unallocated (12) + +address: VaultStorage._deprecated_uniswapAddr (20) + +unallocated (12) + +address: VaultStorage.strategistAddr (20) + +mapping(address=>address): VaultStorage.assetDefaultStrategies (32) + +uint256: VaultStorage.maxSupplyDiff (32) + +unallocated (12) + +address: VaultStorage.trusteeAddress (20) + +uint256: VaultStorage.trusteeFeeBps (32) + +address[]: VaultStorage._deprecated_swapTokens (32) + +unallocated (12) + +address: VaultStorage.ousdMetaStrategy (20) + +int256: VaultStorage.netOusdMintedForStrategy (32) + +uint256: VaultStorage.netOusdMintForStrategyThreshold (32) + +SwapConfig: VaultStorage.swapConfig (32) + +unallocated (12) + +address: VaultStorage.dripper (20) + +WithdrawalQueueMetadata: VaultStorage.withdrawalQueueMetadata (64) + +mapping(uint256=>WithdrawalRequest): VaultStorage.withdrawalRequests (32) + +uint256[46]: VaultStorage.__gap (1472) + +uint256: wethAssetIndex (32) 1 - -Asset <<Struct>> - -offset - -0 - -type: variable (bytes) - -unallocated (27) - -uint16: allowedOracleSlippageBps (2) - -uint8: decimals (1) - -UnitConversion: unitConversion (1) - -bool: isSupported (1) + +Asset <<Struct>> + +offset + +0 + +type: variable (bytes) + +unallocated (27) + +uint16: allowedOracleSlippageBps (2) + +uint8: decimals (1) + +UnitConversion: unitConversion (1) + +bool: isSupported (1) - + -7:8->1 - - +8:8->1 + + 2 - -address[]: allAssets <<Array>> -0x46bddb1178e94d7f2892ff5f366840eb658911794f2c3a44c450aa2c505186c1 - -offset - -0 - -type: variable (bytes) - -unallocated (12) - -address (20) + +address[]: allAssets <<Array>> +0x46bddb1178e94d7f2892ff5f366840eb658911794f2c3a44c450aa2c505186c1 + +offset + +0 + +type: variable (bytes) + +unallocated (12) + +address (20) - + -7:10->2 - - +8:10->2 + + 3 - -Strategy <<Struct>> - -offset - -0 - -1 - -type: variable (bytes) - -unallocated (31) - -bool: isSupported (1) - -uint256: _deprecated (32) + +Strategy <<Struct>> + +offset + +0 + +1 + +type: variable (bytes) + +unallocated (31) + +bool: isSupported (1) + +uint256: _deprecated (32) - + -7:13->3 - - +8:13->3 + + 4 - -address[]: allStrategies <<Array>> -0x4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b8 - -offset - -0 - -type: variable (bytes) - -unallocated (12) - -address (20) + +address[]: allStrategies <<Array>> +0x4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b8 + +offset + +0 + +type: variable (bytes) + +unallocated (12) + +address (20) - + -7:15->4 - - +8:15->4 + + 5 - -SwapConfig <<Struct>> - -slot - -72 - -type: variable (bytes) - -unallocated (10) - -uint16: allowedUndervalueBps (2) - -address: swapper (20) + +SwapConfig <<Struct>> + +slot + +72 + +type: variable (bytes) + +unallocated (10) + +uint16: allowedUndervalueBps (2) + +address: swapper (20) - + -7:37->5 - - +8:37->5 + + 6 - -uint256[50]: __gap <<Array>> - -slot - -73 - -74 - -75-120 - -121 - -122 - -type: variable (bytes) - -uint256 (32) - -uint256 (32) - ----- (1472) - -uint256 (32) - -uint256 (32) + +WithdrawalQueueMetadata <<Struct>> + +slot + +74 + +75 + +type: variable (bytes) + +uint128: claimable (16) + +uint128: queued (16) + +uint128: nextWithdrawalIndex (16) + +uint128: claimed (16) - + -7:43->6 - - +8:43->6 + + + + + +7 + +WithdrawalRequest <<Struct>> + +offset + +0 + +1 + +type: variable (bytes) + +unallocated (6) + +uint40: timestamp (5) + +bool: claimed (1) + +address: withdrawer (20) + +uint128: queued (16) + +uint128: amount (16) + + + +8:49->7 + + diff --git a/contracts/docs/VaultAdminSquashed.svg b/contracts/docs/VaultAdminSquashed.svg index 939e2c043f..97415e45e7 100644 --- a/contracts/docs/VaultAdminSquashed.svg +++ b/contracts/docs/VaultAdminSquashed.svg @@ -4,132 +4,143 @@ - - + + UmlClassDiagram - - + + -204 - -VaultAdmin -../contracts/vault/VaultAdmin.sol - -Private: -   initialized: bool <<Initializable>> -   initializing: bool <<Initializable>> -   ______gap: uint256[50] <<Initializable>> -   governorPosition: bytes32 <<Governable>> -   pendingGovernorPosition: bytes32 <<Governable>> -   reentryStatusPosition: bytes32 <<Governable>> -   _deprecated_rebaseHooksAddr: address <<VaultStorage>> -   _deprecated_uniswapAddr: address <<VaultStorage>> -   _deprecated_swapTokens: address[] <<VaultStorage>> -Internal: -   assets: mapping(address=>Asset) <<VaultStorage>> -   allAssets: address[] <<VaultStorage>> -   strategies: mapping(address=>Strategy) <<VaultStorage>> -   allStrategies: address[] <<VaultStorage>> -   oUSD: OUSD <<VaultStorage>> -   swapConfig: SwapConfig <<VaultStorage>> -Public: -   _NOT_ENTERED: uint256 <<Governable>> -   _ENTERED: uint256 <<Governable>> -   priceProvider: address <<VaultStorage>> -   rebasePaused: bool <<VaultStorage>> -   capitalPaused: bool <<VaultStorage>> -   redeemFeeBps: uint256 <<VaultStorage>> -   vaultBuffer: uint256 <<VaultStorage>> -   autoAllocateThreshold: uint256 <<VaultStorage>> -   rebaseThreshold: uint256 <<VaultStorage>> -   adminImplPosition: bytes32 <<VaultStorage>> -   strategistAddr: address <<VaultStorage>> -   assetDefaultStrategies: mapping(address=>address) <<VaultStorage>> -   maxSupplyDiff: uint256 <<VaultStorage>> -   trusteeAddress: address <<VaultStorage>> -   trusteeFeeBps: uint256 <<VaultStorage>> -   MINT_MINIMUM_UNIT_PRICE: uint256 <<VaultStorage>> -   ousdMetaStrategy: address <<VaultStorage>> -   netOusdMintedForStrategy: int256 <<VaultStorage>> -   netOusdMintForStrategyThreshold: uint256 <<VaultStorage>> -   MIN_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> -   MAX_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> - -Internal: -    _governor(): (governorOut: address) <<Governable>> -    _pendingGovernor(): (pendingGovernor: address) <<Governable>> -    _setGovernor(newGovernor: address) <<Governable>> -    _setPendingGovernor(newGovernor: address) <<Governable>> -    _changeGovernor(_newGovernor: address) <<Governable>> -    _depositToStrategy(_strategyToAddress: address, _assets: address[], _amounts: uint256[]) <<VaultAdmin>> -    _withdrawFromStrategy(_recipient: address, _strategyFromAddress: address, _assets: address[], _amounts: uint256[]) <<VaultAdmin>> -    _cacheDecimals(token: address) <<VaultAdmin>> -External: -    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>> -    claimGovernance() <<Governable>> -    setAdminImpl(newImpl: address) <<onlyGovernor>> <<VaultStorage>> -    setPriceProvider(_priceProvider: address) <<onlyGovernor>> <<VaultAdmin>> -    setRedeemFeeBps(_redeemFeeBps: uint256) <<onlyGovernor>> <<VaultAdmin>> -    setVaultBuffer(_vaultBuffer: uint256) <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    setAutoAllocateThreshold(_threshold: uint256) <<onlyGovernor>> <<VaultAdmin>> -    setRebaseThreshold(_threshold: uint256) <<onlyGovernor>> <<VaultAdmin>> -    setStrategistAddr(_address: address) <<onlyGovernor>> <<VaultAdmin>> -    setAssetDefaultStrategy(_asset: address, _strategy: address) <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    setNetOusdMintForStrategyThreshold(_threshold: uint256) <<onlyGovernor>> <<VaultAdmin>> -    swapCollateral(_fromAsset: address, _toAsset: address, _fromAssetAmount: uint256, _minToAssetAmount: uint256, _data: bytes): (toAssetAmount: uint256) <<nonReentrant, onlyGovernorOrStrategist>> <<VaultAdmin>> -    setSwapper(_swapperAddr: address) <<onlyGovernor>> <<VaultAdmin>> -    swapper(): (swapper_: address) <<VaultAdmin>> -    setSwapAllowedUndervalue(_basis: uint16) <<onlyGovernor>> <<VaultAdmin>> -    allowedSwapUndervalue(): (value: uint256) <<VaultAdmin>> -    setOracleSlippage(_asset: address, _allowedOracleSlippageBps: uint16) <<onlyGovernor>> <<VaultAdmin>> -    supportAsset(_asset: address, _unitConversion: uint8) <<onlyGovernor>> <<VaultAdmin>> -    cacheDecimals(_asset: address) <<onlyGovernor>> <<VaultAdmin>> -    approveStrategy(_addr: address) <<onlyGovernor>> <<VaultAdmin>> -    removeStrategy(_addr: address) <<onlyGovernor>> <<VaultAdmin>> -    depositToStrategy(_strategyToAddress: address, _assets: address[], _amounts: uint256[]) <<onlyGovernorOrStrategist, nonReentrant>> <<VaultAdmin>> -    withdrawFromStrategy(_strategyFromAddress: address, _assets: address[], _amounts: uint256[]) <<onlyGovernorOrStrategist, nonReentrant>> <<VaultAdmin>> -    setMaxSupplyDiff(_maxSupplyDiff: uint256) <<onlyGovernor>> <<VaultAdmin>> -    setTrusteeAddress(_address: address) <<onlyGovernor>> <<VaultAdmin>> -    setTrusteeFeeBps(_basis: uint256) <<onlyGovernor>> <<VaultAdmin>> -    setOusdMetaStrategy(_ousdMetaStrategy: address) <<onlyGovernor>> <<VaultAdmin>> -    pauseRebase() <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    unpauseRebase() <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    pauseCapital() <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    unpauseCapital() <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    transferToken(_asset: address, _amount: uint256) <<onlyGovernor>> <<VaultAdmin>> -    withdrawAllFromStrategy(_strategyAddr: address) <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    withdrawAllFromStrategies() <<onlyGovernorOrStrategist>> <<VaultAdmin>> -Public: -    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> -    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> -    <<event>> AssetSupported(_asset: address) <<VaultStorage>> -    <<event>> AssetDefaultStrategyUpdated(_asset: address, _strategy: address) <<VaultStorage>> -    <<event>> AssetAllocated(_asset: address, _strategy: address, _amount: uint256) <<VaultStorage>> -    <<event>> StrategyApproved(_addr: address) <<VaultStorage>> -    <<event>> StrategyRemoved(_addr: address) <<VaultStorage>> -    <<event>> Mint(_addr: address, _value: uint256) <<VaultStorage>> -    <<event>> Redeem(_addr: address, _value: uint256) <<VaultStorage>> -    <<event>> CapitalPaused() <<VaultStorage>> -    <<event>> CapitalUnpaused() <<VaultStorage>> -    <<event>> RebasePaused() <<VaultStorage>> -    <<event>> RebaseUnpaused() <<VaultStorage>> -    <<event>> VaultBufferUpdated(_vaultBuffer: uint256) <<VaultStorage>> -    <<event>> OusdMetaStrategyUpdated(_ousdMetaStrategy: address) <<VaultStorage>> -    <<event>> RedeemFeeUpdated(_redeemFeeBps: uint256) <<VaultStorage>> -    <<event>> PriceProviderUpdated(_priceProvider: address) <<VaultStorage>> -    <<event>> AllocateThresholdUpdated(_threshold: uint256) <<VaultStorage>> -    <<event>> RebaseThresholdUpdated(_threshold: uint256) <<VaultStorage>> -    <<event>> StrategistUpdated(_address: address) <<VaultStorage>> -    <<event>> MaxSupplyDiffChanged(maxSupplyDiff: uint256) <<VaultStorage>> -    <<event>> YieldDistribution(_to: address, _yield: uint256, _fee: uint256) <<VaultStorage>> -    <<event>> TrusteeFeeBpsChanged(_basis: uint256) <<VaultStorage>> -    <<event>> TrusteeAddressChanged(_address: address) <<VaultStorage>> -    <<event>> NetOusdMintForStrategyThresholdChanged(_threshold: uint256) <<VaultStorage>> -    <<event>> SwapperChanged(_address: address) <<VaultStorage>> -    <<event>> SwapAllowedUndervalueChanged(_basis: uint256) <<VaultStorage>> -    <<event>> SwapSlippageChanged(_asset: address, _basis: uint256) <<VaultStorage>> -    <<event>> Swapped(_fromAsset: address, _toAsset: address, _fromAssetAmount: uint256, _toAssetAmount: uint256) <<VaultStorage>> +223 + +VaultAdmin +../contracts/vault/VaultAdmin.sol + +Private: +   initialized: bool <<Initializable>> +   initializing: bool <<Initializable>> +   ______gap: uint256[50] <<Initializable>> +   governorPosition: bytes32 <<Governable>> +   pendingGovernorPosition: bytes32 <<Governable>> +   reentryStatusPosition: bytes32 <<Governable>> +   _deprecated_rebaseHooksAddr: address <<VaultStorage>> +   _deprecated_uniswapAddr: address <<VaultStorage>> +   _deprecated_swapTokens: address[] <<VaultStorage>> +   __gap: uint256[46] <<VaultStorage>> +Internal: +   assets: mapping(address=>Asset) <<VaultStorage>> +   allAssets: address[] <<VaultStorage>> +   strategies: mapping(address=>Strategy) <<VaultStorage>> +   allStrategies: address[] <<VaultStorage>> +   oUSD: OUSD <<VaultStorage>> +   swapConfig: SwapConfig <<VaultStorage>> +Public: +   _NOT_ENTERED: uint256 <<Governable>> +   _ENTERED: uint256 <<Governable>> +   priceProvider: address <<VaultStorage>> +   rebasePaused: bool <<VaultStorage>> +   capitalPaused: bool <<VaultStorage>> +   redeemFeeBps: uint256 <<VaultStorage>> +   vaultBuffer: uint256 <<VaultStorage>> +   autoAllocateThreshold: uint256 <<VaultStorage>> +   rebaseThreshold: uint256 <<VaultStorage>> +   adminImplPosition: bytes32 <<VaultStorage>> +   strategistAddr: address <<VaultStorage>> +   assetDefaultStrategies: mapping(address=>address) <<VaultStorage>> +   maxSupplyDiff: uint256 <<VaultStorage>> +   trusteeAddress: address <<VaultStorage>> +   trusteeFeeBps: uint256 <<VaultStorage>> +   MINT_MINIMUM_UNIT_PRICE: uint256 <<VaultStorage>> +   ousdMetaStrategy: address <<VaultStorage>> +   netOusdMintedForStrategy: int256 <<VaultStorage>> +   netOusdMintForStrategyThreshold: uint256 <<VaultStorage>> +   MIN_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> +   MAX_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> +   dripper: address <<VaultStorage>> +   withdrawalQueueMetadata: WithdrawalQueueMetadata <<VaultStorage>> +   withdrawalRequests: mapping(uint256=>WithdrawalRequest) <<VaultStorage>> + +Internal: +    _governor(): (governorOut: address) <<Governable>> +    _pendingGovernor(): (pendingGovernor: address) <<Governable>> +    _setGovernor(newGovernor: address) <<Governable>> +    _setPendingGovernor(newGovernor: address) <<Governable>> +    _changeGovernor(_newGovernor: address) <<Governable>> +    _depositToStrategy(_strategyToAddress: address, _assets: address[], _amounts: uint256[]) <<VaultAdmin>> +    _withdrawFromStrategy(_recipient: address, _strategyFromAddress: address, _assets: address[], _amounts: uint256[]) <<VaultAdmin>> +    _withdrawAllFromStrategy(_strategyAddr: address) <<VaultAdmin>> +    _withdrawAllFromStrategies() <<VaultAdmin>> +    _cacheDecimals(token: address) <<VaultAdmin>> +External: +    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>> +    claimGovernance() <<Governable>> +    setAdminImpl(newImpl: address) <<onlyGovernor>> <<VaultStorage>> +    setPriceProvider(_priceProvider: address) <<onlyGovernor>> <<VaultAdmin>> +    setRedeemFeeBps(_redeemFeeBps: uint256) <<onlyGovernor>> <<VaultAdmin>> +    setVaultBuffer(_vaultBuffer: uint256) <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    setAutoAllocateThreshold(_threshold: uint256) <<onlyGovernor>> <<VaultAdmin>> +    setRebaseThreshold(_threshold: uint256) <<onlyGovernor>> <<VaultAdmin>> +    setStrategistAddr(_address: address) <<onlyGovernor>> <<VaultAdmin>> +    setAssetDefaultStrategy(_asset: address, _strategy: address) <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    setNetOusdMintForStrategyThreshold(_threshold: uint256) <<onlyGovernor>> <<VaultAdmin>> +    setDripper(_dripper: address) <<onlyGovernor>> <<VaultAdmin>> +    swapCollateral(_fromAsset: address, _toAsset: address, _fromAssetAmount: uint256, _minToAssetAmount: uint256, _data: bytes): (toAssetAmount: uint256) <<nonReentrant, onlyGovernorOrStrategist>> <<VaultAdmin>> +    setSwapper(_swapperAddr: address) <<onlyGovernor>> <<VaultAdmin>> +    swapper(): (swapper_: address) <<VaultAdmin>> +    setSwapAllowedUndervalue(_basis: uint16) <<onlyGovernor>> <<VaultAdmin>> +    allowedSwapUndervalue(): (value: uint256) <<VaultAdmin>> +    setOracleSlippage(_asset: address, _allowedOracleSlippageBps: uint16) <<onlyGovernor>> <<VaultAdmin>> +    supportAsset(_asset: address, _unitConversion: uint8) <<onlyGovernor>> <<VaultAdmin>> +    cacheDecimals(_asset: address) <<onlyGovernor>> <<VaultAdmin>> +    approveStrategy(_addr: address) <<onlyGovernor>> <<VaultAdmin>> +    removeStrategy(_addr: address) <<onlyGovernor>> <<VaultAdmin>> +    depositToStrategy(_strategyToAddress: address, _assets: address[], _amounts: uint256[]) <<onlyGovernorOrStrategist, nonReentrant>> <<VaultAdmin>> +    withdrawFromStrategy(_strategyFromAddress: address, _assets: address[], _amounts: uint256[]) <<onlyGovernorOrStrategist, nonReentrant>> <<VaultAdmin>> +    setMaxSupplyDiff(_maxSupplyDiff: uint256) <<onlyGovernor>> <<VaultAdmin>> +    setTrusteeAddress(_address: address) <<onlyGovernor>> <<VaultAdmin>> +    setTrusteeFeeBps(_basis: uint256) <<onlyGovernor>> <<VaultAdmin>> +    setOusdMetaStrategy(_ousdMetaStrategy: address) <<onlyGovernor>> <<VaultAdmin>> +    pauseRebase() <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    unpauseRebase() <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    pauseCapital() <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    unpauseCapital() <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    transferToken(_asset: address, _amount: uint256) <<onlyGovernor>> <<VaultAdmin>> +    withdrawAllFromStrategy(_strategyAddr: address) <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    withdrawAllFromStrategies() <<onlyGovernorOrStrategist>> <<VaultAdmin>> +Public: +    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> AssetSupported(_asset: address) <<VaultStorage>> +    <<event>> AssetDefaultStrategyUpdated(_asset: address, _strategy: address) <<VaultStorage>> +    <<event>> AssetAllocated(_asset: address, _strategy: address, _amount: uint256) <<VaultStorage>> +    <<event>> StrategyApproved(_addr: address) <<VaultStorage>> +    <<event>> StrategyRemoved(_addr: address) <<VaultStorage>> +    <<event>> Mint(_addr: address, _value: uint256) <<VaultStorage>> +    <<event>> Redeem(_addr: address, _value: uint256) <<VaultStorage>> +    <<event>> CapitalPaused() <<VaultStorage>> +    <<event>> CapitalUnpaused() <<VaultStorage>> +    <<event>> RebasePaused() <<VaultStorage>> +    <<event>> RebaseUnpaused() <<VaultStorage>> +    <<event>> VaultBufferUpdated(_vaultBuffer: uint256) <<VaultStorage>> +    <<event>> OusdMetaStrategyUpdated(_ousdMetaStrategy: address) <<VaultStorage>> +    <<event>> RedeemFeeUpdated(_redeemFeeBps: uint256) <<VaultStorage>> +    <<event>> PriceProviderUpdated(_priceProvider: address) <<VaultStorage>> +    <<event>> AllocateThresholdUpdated(_threshold: uint256) <<VaultStorage>> +    <<event>> RebaseThresholdUpdated(_threshold: uint256) <<VaultStorage>> +    <<event>> StrategistUpdated(_address: address) <<VaultStorage>> +    <<event>> MaxSupplyDiffChanged(maxSupplyDiff: uint256) <<VaultStorage>> +    <<event>> YieldDistribution(_to: address, _yield: uint256, _fee: uint256) <<VaultStorage>> +    <<event>> TrusteeFeeBpsChanged(_basis: uint256) <<VaultStorage>> +    <<event>> TrusteeAddressChanged(_address: address) <<VaultStorage>> +    <<event>> NetOusdMintForStrategyThresholdChanged(_threshold: uint256) <<VaultStorage>> +    <<event>> SwapperChanged(_address: address) <<VaultStorage>> +    <<event>> SwapAllowedUndervalueChanged(_basis: uint256) <<VaultStorage>> +    <<event>> SwapSlippageChanged(_asset: address, _basis: uint256) <<VaultStorage>> +    <<event>> Swapped(_fromAsset: address, _toAsset: address, _fromAssetAmount: uint256, _toAssetAmount: uint256) <<VaultStorage>> +    <<event>> DripperChanged(_dripper: address) <<VaultStorage>> +    <<event>> WithdrawalRequested(_withdrawer: address, _requestId: uint256, _amount: uint256, _queued: uint256) <<VaultStorage>> +    <<event>> WithdrawalClaimed(_withdrawer: address, _requestId: uint256, _amount: uint256) <<VaultStorage>> +    <<event>> WithdrawalClaimable(_claimable: uint256, _newClaimable: uint256) <<VaultStorage>>    <<modifier>> initializer() <<Initializable>>    <<modifier>> onlyGovernor() <<Governable>>    <<modifier>> nonReentrant() <<Governable>> diff --git a/contracts/docs/VaultCoreSquashed.svg b/contracts/docs/VaultCoreSquashed.svg index 64e07ea5fe..86049bb13a 100644 --- a/contracts/docs/VaultCoreSquashed.svg +++ b/contracts/docs/VaultCoreSquashed.svg @@ -4,132 +4,142 @@ - - + + UmlClassDiagram - - + + -205 - -VaultCore -../contracts/vault/VaultCore.sol - -Private: -   initialized: bool <<Initializable>> -   initializing: bool <<Initializable>> -   ______gap: uint256[50] <<Initializable>> -   governorPosition: bytes32 <<Governable>> -   pendingGovernorPosition: bytes32 <<Governable>> -   reentryStatusPosition: bytes32 <<Governable>> -   _deprecated_rebaseHooksAddr: address <<VaultStorage>> -   _deprecated_uniswapAddr: address <<VaultStorage>> -   _deprecated_swapTokens: address[] <<VaultStorage>> -Internal: -   assets: mapping(address=>Asset) <<VaultStorage>> -   allAssets: address[] <<VaultStorage>> -   strategies: mapping(address=>Strategy) <<VaultStorage>> -   allStrategies: address[] <<VaultStorage>> -   oUSD: OUSD <<VaultStorage>> -   swapConfig: SwapConfig <<VaultStorage>> -   MAX_INT: uint256 <<VaultCore>> -   MAX_UINT: uint256 <<VaultCore>> -Public: -   _NOT_ENTERED: uint256 <<Governable>> -   _ENTERED: uint256 <<Governable>> -   priceProvider: address <<VaultStorage>> -   rebasePaused: bool <<VaultStorage>> -   capitalPaused: bool <<VaultStorage>> -   redeemFeeBps: uint256 <<VaultStorage>> -   vaultBuffer: uint256 <<VaultStorage>> -   autoAllocateThreshold: uint256 <<VaultStorage>> -   rebaseThreshold: uint256 <<VaultStorage>> -   adminImplPosition: bytes32 <<VaultStorage>> -   strategistAddr: address <<VaultStorage>> -   assetDefaultStrategies: mapping(address=>address) <<VaultStorage>> -   maxSupplyDiff: uint256 <<VaultStorage>> -   trusteeAddress: address <<VaultStorage>> -   trusteeFeeBps: uint256 <<VaultStorage>> -   MINT_MINIMUM_UNIT_PRICE: uint256 <<VaultStorage>> -   ousdMetaStrategy: address <<VaultStorage>> -   netOusdMintedForStrategy: int256 <<VaultStorage>> -   netOusdMintForStrategyThreshold: uint256 <<VaultStorage>> -   MIN_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> -   MAX_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> - -Private: -    abs(x: int256): uint256 <<VaultCore>> -Internal: -    _governor(): (governorOut: address) <<Governable>> -    _pendingGovernor(): (pendingGovernor: address) <<Governable>> -    _setGovernor(newGovernor: address) <<Governable>> -    _setPendingGovernor(newGovernor: address) <<Governable>> -    _changeGovernor(_newGovernor: address) <<Governable>> -    _redeem(_amount: uint256, _minimumUnitAmount: uint256) <<VaultCore>> -    _allocate() <<VaultCore>> -    _rebase(): uint256 <<whenNotRebasePaused>> <<VaultCore>> -    _totalValue(): (value: uint256) <<VaultCore>> -    _totalValueInVault(): (value: uint256) <<VaultCore>> -    _totalValueInStrategies(): (value: uint256) <<VaultCore>> -    _totalValueInStrategy(_strategyAddr: address): (value: uint256) <<VaultCore>> -    _checkBalance(_asset: address): (balance: uint256) <<VaultCore>> -    _calculateRedeemOutputs(_amount: uint256): (outputs: uint256[]) <<VaultCore>> -    _toUnits(_raw: uint256, _asset: address): uint256 <<VaultCore>> -    _toUnitPrice(_asset: address, isMint: bool): (price: uint256) <<VaultCore>> -    _getDecimals(_asset: address): (decimals: uint256) <<VaultCore>> -External: -    <<payable>> null() <<VaultCore>> -    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>> -    claimGovernance() <<Governable>> -    setAdminImpl(newImpl: address) <<onlyGovernor>> <<VaultStorage>> -    initialize(_priceProvider: address, _oToken: address) <<onlyGovernor, initializer>> <<VaultInitializer>> -    mint(_asset: address, _amount: uint256, _minimumOusdAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> -    mintForStrategy(_amount: uint256) <<whenNotCapitalPaused, onlyOusdMetaStrategy>> <<VaultCore>> -    redeem(_amount: uint256, _minimumUnitAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> -    burnForStrategy(_amount: uint256) <<whenNotCapitalPaused, onlyOusdMetaStrategy>> <<VaultCore>> -    redeemAll(_minimumUnitAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> -    allocate() <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> -    rebase() <<nonReentrant>> <<VaultCore>> -    totalValue(): (value: uint256) <<VaultCore>> -    checkBalance(_asset: address): uint256 <<VaultCore>> -    calculateRedeemOutputs(_amount: uint256): uint256[] <<VaultCore>> -    priceUnitMint(asset: address): (price: uint256) <<VaultCore>> -    priceUnitRedeem(asset: address): (price: uint256) <<VaultCore>> -    getAllAssets(): address[] <<VaultCore>> -    getStrategyCount(): uint256 <<VaultCore>> -    getAllStrategies(): address[] <<VaultCore>> -    isSupportedAsset(_asset: address): bool <<VaultCore>> -Public: -    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> -    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> -    <<event>> AssetSupported(_asset: address) <<VaultStorage>> -    <<event>> AssetDefaultStrategyUpdated(_asset: address, _strategy: address) <<VaultStorage>> -    <<event>> AssetAllocated(_asset: address, _strategy: address, _amount: uint256) <<VaultStorage>> -    <<event>> StrategyApproved(_addr: address) <<VaultStorage>> -    <<event>> StrategyRemoved(_addr: address) <<VaultStorage>> -    <<event>> Mint(_addr: address, _value: uint256) <<VaultStorage>> -    <<event>> Redeem(_addr: address, _value: uint256) <<VaultStorage>> -    <<event>> CapitalPaused() <<VaultStorage>> -    <<event>> CapitalUnpaused() <<VaultStorage>> -    <<event>> RebasePaused() <<VaultStorage>> -    <<event>> RebaseUnpaused() <<VaultStorage>> -    <<event>> VaultBufferUpdated(_vaultBuffer: uint256) <<VaultStorage>> -    <<event>> OusdMetaStrategyUpdated(_ousdMetaStrategy: address) <<VaultStorage>> -    <<event>> RedeemFeeUpdated(_redeemFeeBps: uint256) <<VaultStorage>> -    <<event>> PriceProviderUpdated(_priceProvider: address) <<VaultStorage>> -    <<event>> AllocateThresholdUpdated(_threshold: uint256) <<VaultStorage>> -    <<event>> RebaseThresholdUpdated(_threshold: uint256) <<VaultStorage>> -    <<event>> StrategistUpdated(_address: address) <<VaultStorage>> -    <<event>> MaxSupplyDiffChanged(maxSupplyDiff: uint256) <<VaultStorage>> -    <<event>> YieldDistribution(_to: address, _yield: uint256, _fee: uint256) <<VaultStorage>> -    <<event>> TrusteeFeeBpsChanged(_basis: uint256) <<VaultStorage>> -    <<event>> TrusteeAddressChanged(_address: address) <<VaultStorage>> -    <<event>> NetOusdMintForStrategyThresholdChanged(_threshold: uint256) <<VaultStorage>> -    <<event>> SwapperChanged(_address: address) <<VaultStorage>> -    <<event>> SwapAllowedUndervalueChanged(_basis: uint256) <<VaultStorage>> -    <<event>> SwapSlippageChanged(_asset: address, _basis: uint256) <<VaultStorage>> -    <<event>> Swapped(_fromAsset: address, _toAsset: address, _fromAssetAmount: uint256, _toAssetAmount: uint256) <<VaultStorage>> +224 + +VaultCore +../contracts/vault/VaultCore.sol + +Private: +   initialized: bool <<Initializable>> +   initializing: bool <<Initializable>> +   ______gap: uint256[50] <<Initializable>> +   governorPosition: bytes32 <<Governable>> +   pendingGovernorPosition: bytes32 <<Governable>> +   reentryStatusPosition: bytes32 <<Governable>> +   _deprecated_rebaseHooksAddr: address <<VaultStorage>> +   _deprecated_uniswapAddr: address <<VaultStorage>> +   _deprecated_swapTokens: address[] <<VaultStorage>> +   __gap: uint256[46] <<VaultStorage>> +Internal: +   assets: mapping(address=>Asset) <<VaultStorage>> +   allAssets: address[] <<VaultStorage>> +   strategies: mapping(address=>Strategy) <<VaultStorage>> +   allStrategies: address[] <<VaultStorage>> +   oUSD: OUSD <<VaultStorage>> +   swapConfig: SwapConfig <<VaultStorage>> +   MAX_INT: uint256 <<VaultCore>> +   MAX_UINT: uint256 <<VaultCore>> +Public: +   _NOT_ENTERED: uint256 <<Governable>> +   _ENTERED: uint256 <<Governable>> +   priceProvider: address <<VaultStorage>> +   rebasePaused: bool <<VaultStorage>> +   capitalPaused: bool <<VaultStorage>> +   redeemFeeBps: uint256 <<VaultStorage>> +   vaultBuffer: uint256 <<VaultStorage>> +   autoAllocateThreshold: uint256 <<VaultStorage>> +   rebaseThreshold: uint256 <<VaultStorage>> +   adminImplPosition: bytes32 <<VaultStorage>> +   strategistAddr: address <<VaultStorage>> +   assetDefaultStrategies: mapping(address=>address) <<VaultStorage>> +   maxSupplyDiff: uint256 <<VaultStorage>> +   trusteeAddress: address <<VaultStorage>> +   trusteeFeeBps: uint256 <<VaultStorage>> +   MINT_MINIMUM_UNIT_PRICE: uint256 <<VaultStorage>> +   ousdMetaStrategy: address <<VaultStorage>> +   netOusdMintedForStrategy: int256 <<VaultStorage>> +   netOusdMintForStrategyThreshold: uint256 <<VaultStorage>> +   MIN_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> +   MAX_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> +   dripper: address <<VaultStorage>> +   withdrawalQueueMetadata: WithdrawalQueueMetadata <<VaultStorage>> +   withdrawalRequests: mapping(uint256=>WithdrawalRequest) <<VaultStorage>> + +Private: +    abs(x: int256): uint256 <<VaultCore>> +Internal: +    _governor(): (governorOut: address) <<Governable>> +    _pendingGovernor(): (pendingGovernor: address) <<Governable>> +    _setGovernor(newGovernor: address) <<Governable>> +    _setPendingGovernor(newGovernor: address) <<Governable>> +    _changeGovernor(_newGovernor: address) <<Governable>> +    _mint(_asset: address, _amount: uint256, _minimumOusdAmount: uint256) <<VaultCore>> +    _redeem(_amount: uint256, _minimumUnitAmount: uint256) <<VaultCore>> +    _postRedeem(_amount: uint256) <<VaultCore>> +    _allocate() <<VaultCore>> +    _rebase(): uint256 <<whenNotRebasePaused>> <<VaultCore>> +    _totalValue(): (value: uint256) <<VaultCore>> +    _totalValueInVault(): (value: uint256) <<VaultCore>> +    _totalValueInStrategies(): (value: uint256) <<VaultCore>> +    _totalValueInStrategy(_strategyAddr: address): (value: uint256) <<VaultCore>> +    _checkBalance(_asset: address): (balance: uint256) <<VaultCore>> +    _calculateRedeemOutputs(_amount: uint256): (outputs: uint256[]) <<VaultCore>> +    _toUnits(_raw: uint256, _asset: address): uint256 <<VaultCore>> +    _toUnitPrice(_asset: address, isMint: bool): (price: uint256) <<VaultCore>> +    _getDecimals(_asset: address): (decimals: uint256) <<VaultCore>> +External: +    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>> +    claimGovernance() <<Governable>> +    setAdminImpl(newImpl: address) <<onlyGovernor>> <<VaultStorage>> +    initialize(_priceProvider: address, _oToken: address) <<onlyGovernor, initializer>> <<VaultInitializer>> +    mint(_asset: address, _amount: uint256, _minimumOusdAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> +    mintForStrategy(_amount: uint256) <<whenNotCapitalPaused, onlyOusdMetaStrategy>> <<VaultCore>> +    redeem(_amount: uint256, _minimumUnitAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> +    burnForStrategy(_amount: uint256) <<whenNotCapitalPaused, onlyOusdMetaStrategy>> <<VaultCore>> +    redeemAll(_minimumUnitAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> +    allocate() <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> +    rebase() <<nonReentrant>> <<VaultCore>> +    totalValue(): (value: uint256) <<VaultCore>> +    checkBalance(_asset: address): uint256 <<VaultCore>> +    calculateRedeemOutputs(_amount: uint256): uint256[] <<VaultCore>> +    priceUnitMint(asset: address): (price: uint256) <<VaultCore>> +    priceUnitRedeem(asset: address): (price: uint256) <<VaultCore>> +    getAllAssets(): address[] <<VaultCore>> +    getStrategyCount(): uint256 <<VaultCore>> +    getAllStrategies(): address[] <<VaultCore>> +    isSupportedAsset(_asset: address): bool <<VaultCore>> +    null() <<VaultCore>> +Public: +    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> AssetSupported(_asset: address) <<VaultStorage>> +    <<event>> AssetDefaultStrategyUpdated(_asset: address, _strategy: address) <<VaultStorage>> +    <<event>> AssetAllocated(_asset: address, _strategy: address, _amount: uint256) <<VaultStorage>> +    <<event>> StrategyApproved(_addr: address) <<VaultStorage>> +    <<event>> StrategyRemoved(_addr: address) <<VaultStorage>> +    <<event>> Mint(_addr: address, _value: uint256) <<VaultStorage>> +    <<event>> Redeem(_addr: address, _value: uint256) <<VaultStorage>> +    <<event>> CapitalPaused() <<VaultStorage>> +    <<event>> CapitalUnpaused() <<VaultStorage>> +    <<event>> RebasePaused() <<VaultStorage>> +    <<event>> RebaseUnpaused() <<VaultStorage>> +    <<event>> VaultBufferUpdated(_vaultBuffer: uint256) <<VaultStorage>> +    <<event>> OusdMetaStrategyUpdated(_ousdMetaStrategy: address) <<VaultStorage>> +    <<event>> RedeemFeeUpdated(_redeemFeeBps: uint256) <<VaultStorage>> +    <<event>> PriceProviderUpdated(_priceProvider: address) <<VaultStorage>> +    <<event>> AllocateThresholdUpdated(_threshold: uint256) <<VaultStorage>> +    <<event>> RebaseThresholdUpdated(_threshold: uint256) <<VaultStorage>> +    <<event>> StrategistUpdated(_address: address) <<VaultStorage>> +    <<event>> MaxSupplyDiffChanged(maxSupplyDiff: uint256) <<VaultStorage>> +    <<event>> YieldDistribution(_to: address, _yield: uint256, _fee: uint256) <<VaultStorage>> +    <<event>> TrusteeFeeBpsChanged(_basis: uint256) <<VaultStorage>> +    <<event>> TrusteeAddressChanged(_address: address) <<VaultStorage>> +    <<event>> NetOusdMintForStrategyThresholdChanged(_threshold: uint256) <<VaultStorage>> +    <<event>> SwapperChanged(_address: address) <<VaultStorage>> +    <<event>> SwapAllowedUndervalueChanged(_basis: uint256) <<VaultStorage>> +    <<event>> SwapSlippageChanged(_asset: address, _basis: uint256) <<VaultStorage>> +    <<event>> Swapped(_fromAsset: address, _toAsset: address, _fromAssetAmount: uint256, _toAssetAmount: uint256) <<VaultStorage>> +    <<event>> DripperChanged(_dripper: address) <<VaultStorage>> +    <<event>> WithdrawalRequested(_withdrawer: address, _requestId: uint256, _amount: uint256, _queued: uint256) <<VaultStorage>> +    <<event>> WithdrawalClaimed(_withdrawer: address, _requestId: uint256, _amount: uint256) <<VaultStorage>> +    <<event>> WithdrawalClaimable(_claimable: uint256, _newClaimable: uint256) <<VaultStorage>>    <<modifier>> initializer() <<Initializable>>    <<modifier>> onlyGovernor() <<Governable>>    <<modifier>> nonReentrant() <<Governable>> diff --git a/contracts/docs/VaultHierarchy.svg b/contracts/docs/VaultHierarchy.svg index 626d89b4bb..9b58831412 100644 --- a/contracts/docs/VaultHierarchy.svg +++ b/contracts/docs/VaultHierarchy.svg @@ -4,242 +4,128 @@ - - + + UmlClassDiagram - + 20 - -Governable -../contracts/governance/Governable.sol + +Governable +../contracts/governance/Governable.sol - + -42 - -<<Interface>> -IGetExchangeRateToken -../contracts/interfaces/IGetExchangeRateToken.sol +205 + +OUSD +../contracts/token/OUSD.sol + + + +205->20 + + - + -48 - -<<Interface>> -IOracle -../contracts/interfaces/IOracle.sol +213 + +<<Abstract>> +Initializable +../contracts/utils/Initializable.sol - + + +205->213 + + + + -52 - -<<Interface>> -IStrategy -../contracts/interfaces/IStrategy.sol +216 + +<<Abstract>> +InitializableERC20Detailed +../contracts/utils/InitializableERC20Detailed.sol - - -53 - -<<Interface>> -ISwapper -../contracts/interfaces/ISwapper.sol + + +205->216 + + - - -55 - -<<Interface>> -IVault -../contracts/interfaces/IVault.sol - - - -207 - -VaultStorage -../contracts/vault/VaultStorage.sol - - - -55->207 - - + + +223 + +VaultAdmin +../contracts/vault/VaultAdmin.sol - - -186 - -OUSD -../contracts/token/OUSD.sol + + +226 + +VaultStorage +../contracts/vault/VaultStorage.sol - + -186->20 - - +223->226 + + - - -194 - -<<Abstract>> -Initializable -../contracts/utils/Initializable.sol + + +224 + +VaultCore +../contracts/vault/VaultCore.sol - - -186->194 - - - - - -197 - -<<Abstract>> -InitializableERC20Detailed -../contracts/utils/InitializableERC20Detailed.sol - - - -186->197 - - - - - -392 - -<<Interface>> -IERC20 -../node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol - - + + +225 + +VaultInitializer +../contracts/vault/VaultInitializer.sol + + -197->392 - - - - - -204 - -VaultAdmin -../contracts/vault/VaultAdmin.sol - - - -204->48 - - +224->225 + + - + -204->52 - - +225->205 + + - - -204->53 - - + + +225->226 + + - - -204->55 - - + + +226->20 + + - - -204->207 - - + + +226->205 + + - + -204->392 - - - - - -205 - -VaultCore -../contracts/vault/VaultCore.sol - - - -205->42 - - - - - -205->48 - - - - - -205->52 - - - - - -206 - -VaultInitializer -../contracts/vault/VaultInitializer.sol - - - -205->206 - - - - - -205->392 - - - - - -206->186 - - - - - -206->207 - - - - - -207->20 - - - - - -207->186 - - - - - -207->194 - - +226->213 + + diff --git a/contracts/docs/VaultStorage.svg b/contracts/docs/VaultStorage.svg index bb504649df..af65b4197f 100644 --- a/contracts/docs/VaultStorage.svg +++ b/contracts/docs/VaultStorage.svg @@ -4,262 +4,340 @@ - - + + StorageDiagram - - + + -6 - -VaultCore <<Contract>> - -slot - -0 - -1-50 - -51 - -52 - -53 - -54 - -55 - -56 - -57 - -58 - -59 - -60 - -61 - -62 - -63 - -64 - -65 - -66 - -67 - -68 - -69 - -70 - -71 - -72 - -type: <inherited contract>.variable (bytes) - -unallocated (30) - -bool: Initializable.initializing (1) - -bool: Initializable.initialized (1) - -uint256[50]: Initializable.______gap (1600) - -mapping(address=>Asset): VaultStorage.assets (32) - -address[]: VaultStorage.allAssets (32) - -mapping(address=>Strategy): VaultStorage.strategies (32) - -address[]: VaultStorage.allStrategies (32) - -unallocated (10) - -bool: VaultStorage.capitalPaused (1) - -bool: VaultStorage.rebasePaused (1) - -address: VaultStorage.priceProvider (20) - -uint256: VaultStorage.redeemFeeBps (32) - -uint256: VaultStorage.vaultBuffer (32) - -uint256: VaultStorage.autoAllocateThreshold (32) - -uint256: VaultStorage.rebaseThreshold (32) - -unallocated (12) - -OUSD: VaultStorage.oUSD (20) - -unallocated (12) - -address: VaultStorage._deprecated_rebaseHooksAddr (20) - -unallocated (12) - -address: VaultStorage._deprecated_uniswapAddr (20) - -unallocated (12) - -address: VaultStorage.strategistAddr (20) - -mapping(address=>address): VaultStorage.assetDefaultStrategies (32) - -uint256: VaultStorage.maxSupplyDiff (32) - -unallocated (12) - -address: VaultStorage.trusteeAddress (20) - -uint256: VaultStorage.trusteeFeeBps (32) - -address[]: VaultStorage._deprecated_swapTokens (32) - -unallocated (12) - -address: VaultStorage.ousdMetaStrategy (20) - -int256: VaultStorage.netOusdMintedForStrategy (32) - -uint256: VaultStorage.netOusdMintForStrategyThreshold (32) - -SwapConfig: VaultStorage.swapConfig (32) +8 + +VaultCore <<Contract>> + +slot + +0 + +1-50 + +51 + +52 + +53 + +54 + +55 + +56 + +57 + +58 + +59 + +60 + +61 + +62 + +63 + +64 + +65 + +66 + +67 + +68 + +69 + +70 + +71 + +72 + +73 + +74-75 + +76 + +77-122 + +type: <inherited contract>.variable (bytes) + +unallocated (30) + +bool: Initializable.initializing (1) + +bool: Initializable.initialized (1) + +uint256[50]: Initializable.______gap (1600) + +mapping(address=>Asset): VaultStorage.assets (32) + +address[]: VaultStorage.allAssets (32) + +mapping(address=>Strategy): VaultStorage.strategies (32) + +address[]: VaultStorage.allStrategies (32) + +unallocated (10) + +bool: VaultStorage.capitalPaused (1) + +bool: VaultStorage.rebasePaused (1) + +address: VaultStorage.priceProvider (20) + +uint256: VaultStorage.redeemFeeBps (32) + +uint256: VaultStorage.vaultBuffer (32) + +uint256: VaultStorage.autoAllocateThreshold (32) + +uint256: VaultStorage.rebaseThreshold (32) + +unallocated (12) + +OUSD: VaultStorage.oUSD (20) + +unallocated (12) + +address: VaultStorage._deprecated_rebaseHooksAddr (20) + +unallocated (12) + +address: VaultStorage._deprecated_uniswapAddr (20) + +unallocated (12) + +address: VaultStorage.strategistAddr (20) + +mapping(address=>address): VaultStorage.assetDefaultStrategies (32) + +uint256: VaultStorage.maxSupplyDiff (32) + +unallocated (12) + +address: VaultStorage.trusteeAddress (20) + +uint256: VaultStorage.trusteeFeeBps (32) + +address[]: VaultStorage._deprecated_swapTokens (32) + +unallocated (12) + +address: VaultStorage.ousdMetaStrategy (20) + +int256: VaultStorage.netOusdMintedForStrategy (32) + +uint256: VaultStorage.netOusdMintForStrategyThreshold (32) + +SwapConfig: VaultStorage.swapConfig (32) + +unallocated (12) + +address: VaultStorage.dripper (20) + +WithdrawalQueueMetadata: VaultStorage.withdrawalQueueMetadata (64) + +mapping(uint256=>WithdrawalRequest): VaultStorage.withdrawalRequests (32) + +uint256[46]: VaultStorage.__gap (1472) 1 - -Asset <<Struct>> - -offset - -0 - -type: variable (bytes) - -unallocated (27) - -uint16: allowedOracleSlippageBps (2) - -uint8: decimals (1) - -UnitConversion: unitConversion (1) - -bool: isSupported (1) + +Asset <<Struct>> + +offset + +0 + +type: variable (bytes) + +unallocated (27) + +uint16: allowedOracleSlippageBps (2) + +uint8: decimals (1) + +UnitConversion: unitConversion (1) + +bool: isSupported (1) - + -6:8->1 - - +8:8->1 + + 2 - -address[]: allAssets <<Array>> -0x46bddb1178e94d7f2892ff5f366840eb658911794f2c3a44c450aa2c505186c1 - -offset - -0 - -type: variable (bytes) - -unallocated (12) - -address (20) + +address[]: allAssets <<Array>> +0x46bddb1178e94d7f2892ff5f366840eb658911794f2c3a44c450aa2c505186c1 + +offset + +0 + +type: variable (bytes) + +unallocated (12) + +address (20) - + -6:10->2 - - +8:10->2 + + 3 - -Strategy <<Struct>> - -offset - -0 - -1 - -type: variable (bytes) - -unallocated (31) - -bool: isSupported (1) - -uint256: _deprecated (32) + +Strategy <<Struct>> + +offset + +0 + +1 + +type: variable (bytes) + +unallocated (31) + +bool: isSupported (1) + +uint256: _deprecated (32) - + -6:13->3 - - +8:13->3 + + 4 - -address[]: allStrategies <<Array>> -0x4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b8 - -offset - -0 - -type: variable (bytes) - -unallocated (12) - -address (20) + +address[]: allStrategies <<Array>> +0x4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b8 + +offset + +0 + +type: variable (bytes) + +unallocated (12) + +address (20) - + -6:15->4 - - +8:15->4 + + 5 - -SwapConfig <<Struct>> - -slot - -72 - -type: variable (bytes) - -unallocated (10) - -uint16: allowedUndervalueBps (2) - -address: swapper (20) + +SwapConfig <<Struct>> + +slot + +72 + +type: variable (bytes) + +unallocated (10) + +uint16: allowedUndervalueBps (2) + +address: swapper (20) - + -6:37->5 - - +8:37->5 + + + + + +6 + +WithdrawalQueueMetadata <<Struct>> + +slot + +74 + +75 + +type: variable (bytes) + +uint128: claimable (16) + +uint128: queued (16) + +uint128: nextWithdrawalIndex (16) + +uint128: claimed (16) + + + +8:43->6 + + + + + +7 + +WithdrawalRequest <<Struct>> + +offset + +0 + +1 + +type: variable (bytes) + +unallocated (6) + +uint40: timestamp (5) + +bool: claimed (1) + +address: withdrawer (20) + +uint128: queued (16) + +uint128: amount (16) + + + +8:49->7 + + diff --git a/contracts/docs/generate.sh b/contracts/docs/generate.sh index ed02d52347..c8bc5867eb 100644 --- a/contracts/docs/generate.sh +++ b/contracts/docs/generate.sh @@ -129,15 +129,15 @@ sol2uml .. -s -d 0 -b WOETH -o WOETHSquashed.svg sol2uml storage .. -c WOETH -o WOETHStorage.svg # contracts/vault -sol2uml .. -v -hv -hf -he -hs -hl -b VaultCore,VaultAdmin -o VaultHierarchy.svg +sol2uml .. -v -hv -hf -he -hs -hl -hi -b VaultCore,VaultAdmin -o VaultHierarchy.svg sol2uml .. -s -d 0 -b VaultCore -o VaultCoreSquashed.svg sol2uml .. -s -d 0 -b VaultAdmin -o VaultAdminSquashed.svg -sol2uml storage .. -c VaultCore -o VaultStorage.svg --hideExpand ______gap,_deprecated_swapTokens +sol2uml storage .. -c VaultCore -o VaultStorage.svg --hideExpand __gap,______gap,_deprecated_swapTokens -sol2uml .. -v -hv -hf -he -hs -hl -b OETHVaultCore,OETHVaultAdmin -o OETHVaultHierarchy.svg +sol2uml .. -v -hv -hf -he -hs -hl -hi -b OETHVaultCore,OETHVaultAdmin -o OETHVaultHierarchy.svg sol2uml .. -s -d 0 -b OETHVaultCore -o OETHVaultCoreSquashed.svg sol2uml .. -s -d 0 -b OETHVaultAdmin -o OETHVaultAdminSquashed.svg -sol2uml storage .. -c OETHVaultCore -o OETHVaultStorage.svg --hideExpand ______gap,_deprecated_swapTokens +sol2uml storage .. -c OETHVaultCore -o OETHVaultStorage.svg --hideExpand __gap,______gap,_deprecated_swapTokens # contracts/utils sol2uml .. -v -hv -hf -he -hs -hl -b InitializableAbstractStrategy -o InitializableAbstractStrategyHierarchy.svg diff --git a/contracts/docs/plantuml/oethContracts.png b/contracts/docs/plantuml/oethContracts.png index 1a60fc9b49..5651b42c04 100644 Binary files a/contracts/docs/plantuml/oethContracts.png and b/contracts/docs/plantuml/oethContracts.png differ diff --git a/contracts/docs/plantuml/oethContracts.puml b/contracts/docs/plantuml/oethContracts.puml index fc107fe844..c9f5ffa178 100644 --- a/contracts/docs/plantuml/oethContracts.puml +++ b/contracts/docs/plantuml/oethContracts.puml @@ -19,6 +19,14 @@ object "OETHZapper" as zap <> #$originColor { assets: ETH } +' object "ARM Router" as router <><> #$newColor { +' } + +object "OETH ARM" as arm <><> #$newColor { + assets: WETH, OETH +} + + object "OETHDripper" as drip <><> #$originColor { asset: WETH } @@ -99,9 +107,14 @@ object "FeeAccumulator2" as feeAcc2 <><> #$originColor { ' } ' object "BaseRewardPool" as cvxPool <> { ' } -' object "DepositToken" as cvxPoolLp <> { -' symbol: cvxOUSD3CRV-f -' name: Origin Dollar Convex Deposit +' ' object "DepositToken" as cvxPoolLp <> { +' ' symbol: cvxOUSD3CRV-f +' ' name: Origin Dollar Convex Deposit +' ' } + +' ' SSV +' object "SSV Network" as ssvNet <> #$thirdPartyColor { +' assets: ETH, SSV ' } ' ' SSV @@ -135,11 +148,14 @@ zap ..> oeth zap ..> oethv ' zap .....> weth +' router ..> arm +arm ..> oethv + ' drip .....> weth -oethv <. drip +oethv <.> drip -checker ..> oeth -checker ..> oethv +' checker ..> oeth +' checker ..> oethv oethv <.. harv drip <.. harv diff --git a/contracts/docs/plantuml/oethProcesses-pause.png b/contracts/docs/plantuml/oethProcesses-pause.png new file mode 100644 index 0000000000..30ad48ee42 Binary files /dev/null and b/contracts/docs/plantuml/oethProcesses-pause.png differ diff --git a/contracts/docs/plantuml/oethProcesses-register.png b/contracts/docs/plantuml/oethProcesses-register.png index e55e65c68f..03ac1f8f61 100644 Binary files a/contracts/docs/plantuml/oethProcesses-register.png and b/contracts/docs/plantuml/oethProcesses-register.png differ diff --git a/contracts/docs/plantuml/oethProcesses.png b/contracts/docs/plantuml/oethProcesses.png index 3a3eda591a..4bb4928a15 100644 Binary files a/contracts/docs/plantuml/oethProcesses.png and b/contracts/docs/plantuml/oethProcesses.png differ diff --git a/contracts/tasks/dripper.js b/contracts/tasks/dripper.js new file mode 100644 index 0000000000..c6a7859db8 --- /dev/null +++ b/contracts/tasks/dripper.js @@ -0,0 +1,40 @@ +const { resolveContract } = require("../utils/resolvers"); +const { getSigner } = require("../utils/signers"); +const { logTxDetails } = require("../utils/txLogger"); + +const log = require("../utils/logger")("task:vault"); + +async function getContract(symbol) { + const contractPrefix = symbol === "OUSD" ? "" : symbol; + const dripper = await resolveContract( + `${contractPrefix}DripperProxy`, + "IDripper" + ); + + return dripper; +} + +async function setDripDuration({ symbol, duration }) { + const signer = await getSigner(); + + const dripper = await getContract(symbol); + + log(`About setDripDuration to ${duration} seconds on the ${symbol} Dripper`); + const tx = await dripper.connect(signer).setDripDuration(duration); + await logTxDetails(tx, "setDripDuration"); +} + +async function collect({ symbol }) { + const signer = await getSigner(); + + const dripper = await getContract(symbol); + + log(`About collect from the ${symbol} Dripper`); + const tx = await dripper.connect(signer).collect(); + await logTxDetails(tx, "collect"); +} + +module.exports = { + collect, + setDripDuration, +}; diff --git a/contracts/tasks/storageSlots.js b/contracts/tasks/storageSlots.js index 9a5f507dc6..0ff0f45239 100644 --- a/contracts/tasks/storageSlots.js +++ b/contracts/tasks/storageSlots.js @@ -9,6 +9,9 @@ const { isCurrentValidationData, assertStorageUpgradeSafe, } = require("@openzeppelin/upgrades-core"); + +const log = require("../utils/logger")("task:storage"); + const isFork = process.env.FORK === "true"; const getStorageFileLocation = (hre, contractName) => { @@ -124,7 +127,7 @@ const showStorageLayout = async (taskArguments, hre) => { const assertUpgradeIsSafe = async (hre, contractName) => { if (!isContractEligible(contractName)) { - console.debug(`Skipping storage slot validation of ${contractName}.`); + log(`Skipping storage slot validation of ${contractName}.`); return true; } @@ -135,7 +138,7 @@ const assertUpgradeIsSafe = async (hre, contractName) => { contractName ); if (!oldLayout) { - console.debug( + log( `Previous storage layout for ${contractName} not found. Treating ${contractName} as a new contract.` ); } else { diff --git a/contracts/tasks/tasks.js b/contracts/tasks/tasks.js index 4665c8f9d8..e32f8df017 100644 --- a/contracts/tasks/tasks.js +++ b/contracts/tasks/tasks.js @@ -16,6 +16,7 @@ const { encryptMasterPrivateKey, decryptMasterPrivateKey, } = require("./amazon"); +const { collect, setDripDuration } = require("./dripper"); const { getSigner } = require("../utils/signers"); const { @@ -41,6 +42,7 @@ const { } = require("./tokens"); const { depositWETH, withdrawWETH } = require("./weth"); const { + addWithdrawalQueueLiquidity, allocate, capital, depositToStrategy, @@ -48,6 +50,9 @@ const { rebase, redeem, redeemAll, + requestWithdrawal, + claimWithdrawal, + snapVault, withdrawFromStrategy, withdrawAllFromStrategy, withdrawAllFromStrategies, @@ -269,6 +274,15 @@ task("withdrawWETH").setAction(async (_, __, runSuper) => { }); // Vault tasks. + +task( + "queueLiquidity", + "Call addWithdrawalQueueLiquidity() on the Vault to add WETH to the withdrawal queue" +).setAction(addWithdrawalQueueLiquidity); +task("queueLiquidity").setAction(async (_, __, runSuper) => { + return runSuper(); +}); + task("allocate", "Call allocate() on the Vault") .addOptionalParam( "symbol", @@ -477,6 +491,77 @@ task("withdrawAllFromStrategies").setAction(async (_, __, runSuper) => { return runSuper(); }); +subtask("requestWithdrawal", "Request a withdrawal from a vault") + .addParam( + "amount", + "The amount of oTokens to withdraw", + undefined, + types.float + ) + .addOptionalParam( + "symbol", + "Symbol of the OToken. eg OETH or OUSD", + "OETH", + types.string + ) + .setAction(requestWithdrawal); +task("requestWithdrawal").setAction(async (_, __, runSuper) => { + return runSuper(); +}); + +subtask( + "claimWithdrawal", + "Claim a previously requested withdrawal from a vault" +) + .addParam( + "requestId", + "The id from the previous withdrawal request", + undefined, + types.int + ) + .addOptionalParam( + "symbol", + "Symbol of the OToken. eg OETH or OUSD", + "OETH", + types.string + ) + .setAction(claimWithdrawal); +task("claimWithdrawal").setAction(async (_, __, runSuper) => { + return runSuper(); +}); + +// Dripper + +subtask("collect", "Collect harvested rewards from the Dripper to the Vault") + .addOptionalParam( + "symbol", + "Symbol of the OToken. eg OETH or OUSD", + "OETH", + types.string + ) + .setAction(collect); +task("collect").setAction(async (_, __, runSuper) => { + return runSuper(); +}); + +subtask("setDripDuration", "Set the Dripper duration") + .addParam( + "duration", + "The number of seconds to drip harvested rewards", + undefined, + types.int + ) + .addOptionalParam( + "symbol", + "Symbol of the OToken. eg OETH or OUSD", + "OETH", + types.string + ) + .setAction(setDripDuration); +task("setDripDuration").setAction(async (_, __, runSuper) => { + return runSuper(); +}); + // Governance tasks subtask("execute", "Execute a governance proposal") .addParam("id", "Proposal ID") @@ -1338,6 +1423,18 @@ task("snapStaking").setAction(async (_, __, runSuper) => { return runSuper(); }); +subtask("snapVault", "Takes a snapshot of a OETH Vault") + .addOptionalParam( + "block", + "Block number. (default: latest)", + undefined, + types.int + ) + .setAction(snapVault); +task("snapVault").setAction(async (_, __, runSuper) => { + return runSuper(); +}); + subtask( "depositRoot", "Calculates the Beacon chain deposit root for a validator" diff --git a/contracts/tasks/vault.js b/contracts/tasks/vault.js index ba49d4259b..3152dcb8ff 100644 --- a/contracts/tasks/vault.js +++ b/contracts/tasks/vault.js @@ -1,10 +1,12 @@ -const { parseUnits } = require("ethers/lib/utils"); +const { formatUnits, parseUnits } = require("ethers/lib/utils"); +const { getBlock } = require("./block"); const addresses = require("../utils/addresses"); const { resolveAsset } = require("../utils/resolvers"); const { getSigner } = require("../utils/signers"); const { logTxDetails } = require("../utils/txLogger"); const { ethereumAddress } = require("../utils/regex"); +const { networkMap } = require("../utils/hardhat-helpers"); const log = require("../utils/logger")("task:vault"); @@ -26,6 +28,91 @@ async function getContract(hre, symbol) { }; } +async function snapVault({ block }, hre) { + const blockTag = getBlock(block); + + const vaultProxy = await hre.ethers.getContract(`OETHVaultProxy`); + const vault = await hre.ethers.getContractAt("IVault", vaultProxy.address); + const oethProxy = await hre.ethers.getContract(`OETHProxy`); + const oeth = await hre.ethers.getContractAt("OETH", oethProxy.address); + + const { chainId } = await hre.ethers.provider.getNetwork(); + const wethAddress = addresses[networkMap[chainId]].WETH; + const weth = await ethers.getContractAt("IERC20", wethAddress); + + const wethBalance = await weth.balanceOf(vault.address, { + blockTag, + }); + + const queue = await vault.withdrawalQueueMetadata({ + blockTag, + }); + const shortfall = queue.queued.sub(queue.claimable); + const unclaimed = queue.queued.sub(queue.claimed); + const available = wethBalance.sub(unclaimed).sub(shortfall); + + const totalSupply = await oeth.totalSupply({ + blockTag, + }); + + const totalAssets = await vault.totalValue({ + blockTag, + }); + const assetSupplyDiff = totalAssets.sub(totalSupply); + const vaultBufferPercentage = await vault.vaultBuffer({ + blockTag, + }); + const vaultBuffer = totalSupply + .mul(vaultBufferPercentage) + .div(parseUnits("1")); + + console.log( + `Vault WETH : ${formatUnits(wethBalance)}, ${wethBalance} wei` + ); + + console.log( + `Queued : ${formatUnits(queue.queued)}, ${queue.queued} wei` + ); + console.log( + `Claimable : ${formatUnits(queue.claimable)}, ${queue.claimable} wei` + ); + console.log( + `Claimed : ${formatUnits(queue.claimed)}, ${queue.claimed} wei` + ); + console.log(`Shortfall : ${formatUnits(shortfall)}, ${shortfall} wei`); + console.log(`Unclaimed : ${formatUnits(unclaimed)}, ${unclaimed} wei`); + console.log(`Available : ${formatUnits(available)}, ${available} wei`); + console.log( + `Target Buffer : ${formatUnits(vaultBuffer)} (${formatUnits( + vaultBufferPercentage, + 16 + )}%)` + ); + + console.log( + `Total Asset : ${formatUnits(totalAssets)}, ${totalAssets} wei` + ); + console.log( + `Total Supply : ${formatUnits(totalSupply)}, ${totalSupply} wei` + ); + console.log( + `Asset - Supply: ${formatUnits(assetSupplyDiff)}, ${assetSupplyDiff} wei` + ); +} + +async function addWithdrawalQueueLiquidity(_, hre) { + const signer = await getSigner(); + + const vaultProxy = await hre.ethers.getContract(`OETHVaultProxy`); + const vault = await hre.ethers.getContractAt("IVault", vaultProxy.address); + + log( + `About to call addWithdrawalQueueLiquidity() on the vault with address ${vault.address}` + ); + const tx = await vault.connect(signer).addWithdrawalQueueLiquidity(); + await logTxDetails(tx, "addWithdrawalQueueLiquidity"); +} + async function allocate({ symbol }, hre) { const signer = await getSigner(); @@ -294,7 +381,39 @@ async function withdrawAllFromStrategies({ symbol }, hre) { await logTxDetails(tx, "withdrawAllFromStrategies"); } +async function requestWithdrawal({ amount, symbol }, hre) { + const signer = await getSigner(); + + const oTokenUnits = parseUnits(amount.toString()); + + const { vault } = await getContract(hre, symbol); + + // Get the withdrawal request ID by statically calling requestWithdrawal + const { requestId } = await vault + .connect(signer) + .callStatic.requestWithdrawal(oTokenUnits); + + log(`About to request withdrawal from the ${symbol} vault`); + const tx = await vault.connect(signer).requestWithdrawal(oTokenUnits); + await logTxDetails(tx, "requestWithdrawal"); + + console.log(`Withdrawal request id: ${requestId}`); +} + +async function claimWithdrawal({ requestId, symbol }, hre) { + const signer = await getSigner(); + + const { vault } = await getContract(hre, symbol); + + log( + `About to claim withdrawal from the ${symbol} vault for request ${requestId}` + ); + const tx = await vault.connect(signer).claimWithdrawal(requestId); + await logTxDetails(tx, "claimWithdrawal"); +} + module.exports = { + addWithdrawalQueueLiquidity, allocate, capital, depositToStrategy, @@ -302,6 +421,9 @@ module.exports = { rebase, redeem, redeemAll, + requestWithdrawal, + claimWithdrawal, + snapVault, withdrawFromStrategy, withdrawAllFromStrategy, withdrawAllFromStrategies, diff --git a/contracts/test/_fixture.js b/contracts/test/_fixture.js index bfb127f981..3bcbc106a0 100644 --- a/contracts/test/_fixture.js +++ b/contracts/test/_fixture.js @@ -834,8 +834,7 @@ async function oethDefaultFixture() { async function oethCollateralSwapFixture() { const fixture = await oethDefaultFixture(); - const { weth, matt, strategist, domen, frxETH, timelock, oethVault } = - fixture; + const { reth, stETH, matt, strategist, timelock, oethVault } = fixture; const bufferBps = await oethVault.vaultBuffer(); const shouldChangeBuffer = bufferBps.lt(oethUnits("1")); @@ -847,10 +846,7 @@ async function oethCollateralSwapFixture() { ); } - // Set frxETH/ETH price above 0.998 so we can mint OETH using frxETH - await setFraxOraclePrice(parseUnits("0.999", 18)); - - for (const token of [weth]) { + for (const token of [reth, stETH]) { await token .connect(matt) .approve( @@ -858,8 +854,8 @@ async function oethCollateralSwapFixture() { parseEther("100000000000000000000000000000000000") ); - // Mint some tokens, so it ends up in Vault - await oethVault.connect(matt).mint(token.address, parseEther("200"), "0"); + // Transfer some tokens to the Vault so they can be swapped out + await token.connect(matt).transfer(oethVault.address, parseEther("200")); } if (shouldChangeBuffer) { @@ -867,35 +863,6 @@ async function oethCollateralSwapFixture() { await oethVault.connect(strategist).setVaultBuffer(bufferBps); } - const allStrats = await oethVault.getAllStrategies(); - if ( - allStrats - .map((x) => x.toLowerCase()) - .includes(addresses.mainnet.FraxETHStrategy.toLowerCase()) - ) { - // Remove fraxETH strategy if it exists - // Because it no longer holds assets and causes this test to fail - - // Send some dust to that first - await frxETH.connect(domen).transfer(oethVault.address, oethUnits("1")); - - // Now make sure it's deposited - await oethVault - .connect(strategist) - .depositToStrategy( - addresses.mainnet.FraxETHStrategy, - [frxETH.address], - [oethUnits("1")] - ); - - await oethVault - .connect(timelock) - .setAssetDefaultStrategy(frxETH.address, addresses.zero); - await oethVault - .connect(timelock) - .removeStrategy(addresses.mainnet.FraxETHStrategy); - } - // Withdraw all from strategies so we have assets to swap await oethVault.connect(timelock).withdrawAllFromStrategies(); @@ -1834,6 +1801,10 @@ async function convexOETHMetaVaultFixture( .connect(timelock) .setNetOusdMintForStrategyThreshold(parseUnits("500", 21)); + await oethVault + .connect(timelock) + .setAssetDefaultStrategy(weth.address, addresses.zero); + // Impersonate the OETH Vault fixture.oethVaultSigner = await impersonateAndFund(oethVault.address); // Impersonate the Curve gauge that holds all the LP tokens diff --git a/contracts/test/_hot-deploy.js b/contracts/test/_hot-deploy.js index 58643c3b27..e64c07085c 100644 --- a/contracts/test/_hot-deploy.js +++ b/contracts/test/_hot-deploy.js @@ -214,6 +214,7 @@ async function hotDeployVaultAdmin( await deploy(vaultAdminName, { from: addresses.mainnet.Timelock, // doesn't matter which address deploys it contract: vaultAdminName, + args: isOeth ? [fixture.weth.address] : [], }); const implementation = await ethers.getContract(vaultAdminName); diff --git a/contracts/test/oracle/aura-feed.js b/contracts/test/oracle/aura-feed.js index 8ab2d0949a..6c189a05bd 100644 --- a/contracts/test/oracle/aura-feed.js +++ b/contracts/test/oracle/aura-feed.js @@ -2,7 +2,7 @@ const { expect } = require("chai"); const { loadDefaultFixture } = require("../_fixture"); const { oethUnits } = require("../helpers"); -describe("ForkTest: Aura/WETH Price Feed", function () { +describe.skip("ForkTest: Aura/WETH Price Feed", function () { this.timeout(0); let fixture; diff --git a/contracts/test/oracle/aura-feed.mainnet.fork-test.js b/contracts/test/oracle/aura-feed.mainnet.fork-test.js index 58c2466c8f..cd61fd3237 100644 --- a/contracts/test/oracle/aura-feed.mainnet.fork-test.js +++ b/contracts/test/oracle/aura-feed.mainnet.fork-test.js @@ -4,7 +4,7 @@ const { oethUnits } = require("../helpers"); const addresses = require("../../utils/addresses"); const { hotDeployOption } = require("../_hot-deploy"); -describe("ForkTest: Aura/WETH Price Feed", function () { +describe.skip("ForkTest: Aura/WETH Price Feed", function () { this.timeout(0); let fixture; diff --git a/contracts/test/oracle/oracle.mainnet.fork-test.js b/contracts/test/oracle/oracle.mainnet.fork-test.js index 46e3233736..9b84a68bc5 100644 --- a/contracts/test/oracle/oracle.mainnet.fork-test.js +++ b/contracts/test/oracle/oracle.mainnet.fork-test.js @@ -16,7 +16,23 @@ describe("ForkTest: OETH Oracle Routers", function () { oethOracleRouter = await ethers.getContract("OETHOracleRouter"); }); - it("should get rETH price", async () => { + it("should get WETH price", async () => { + const { weth } = fixture; + + const price = await oethOracleRouter.price(weth.address); + expect(price).to.eq(parseUnits("1", 18)); + }); + + it("should get gas costs of weth", async () => { + const { weth, josh } = fixture; + + const tx = await oethOracleRouter + .connect(josh) + .populateTransaction.price(weth.address); + await josh.sendTransaction(tx); + }); + + it.skip("should get rETH price", async () => { const { reth } = fixture; const price = await oethOracleRouter.price(reth.address); @@ -24,35 +40,17 @@ describe("ForkTest: OETH Oracle Routers", function () { expect(price).to.lt(parseUnits("112", 16)); }); - it("should get frxETH price", async () => { + it.skip("should get frxETH price", async () => { const { frxETH } = fixture; const price = await oethOracleRouter.price(frxETH.address); expect(price).to.lt(parseUnits("1", 18)); }); - it("should get WETH price", async () => { - const { weth } = fixture; - - const price = await oethOracleRouter.price(weth.address); - expect(price).to.eq(parseUnits("1", 18)); - }); - - it("should get stETH price", async () => { + it.skip("should get stETH price", async () => { const { stETH } = fixture; const price = await oethOracleRouter.price(stETH.address); expect(price).to.approxEqualTolerance(parseUnits("1", 18), 1); }); - - it("should get gas costs of assets", async () => { - const { reth, frxETH, stETH, weth, josh } = fixture; - - for (const asset of [frxETH, reth, stETH, weth]) { - const tx = await oethOracleRouter - .connect(josh) - .populateTransaction.price(asset.address); - await josh.sendTransaction(tx); - } - }); }); diff --git a/contracts/test/strategies/balancerMetaStablePool.mainnet.fork-test.js b/contracts/test/strategies/balancerMetaStablePool.mainnet.fork-test.js index cfc421ac00..72f293d820 100644 --- a/contracts/test/strategies/balancerMetaStablePool.mainnet.fork-test.js +++ b/contracts/test/strategies/balancerMetaStablePool.mainnet.fork-test.js @@ -1,7 +1,6 @@ const { expect } = require("chai"); const { formatUnits } = require("ethers").utils; const { BigNumber } = require("ethers"); -const { mine } = require("@nomicfoundation/hardhat-network-helpers"); const addresses = require("../../utils/addresses"); const { balancer_rETH_WETH_PID } = require("../../utils/constants"); @@ -167,7 +166,7 @@ describe.skip("ForkTest: Balancer MetaStablePool rETH/WETH Strategy", function ( }); }); - describe("Deposit", function () { + describe.skip("Deposit", function () { beforeEach(async () => { fixture = await loadBalancerREthFixtureNotDefault(); const { oethVault, josh, reth } = fixture; @@ -270,18 +269,6 @@ describe.skip("ForkTest: Balancer MetaStablePool rETH/WETH Strategy", function ( describe("Withdraw", function () { beforeEach(async () => { fixture = await loadBalancerREthFixtureNotDefault(); - const { balancerREthStrategy, oethVault, josh, strategist, reth, weth } = - fixture; - - await reth.connect(josh).transfer(oethVault.address, oethUnits("32")); - - await oethVault - .connect(strategist) - .depositToStrategy( - balancerREthStrategy.address, - [weth.address, reth.address], - [oethUnits("32"), oethUnits("32")] - ); }); // a list of WETH/RETH pairs @@ -554,23 +541,12 @@ describe.skip("ForkTest: Balancer MetaStablePool rETH/WETH Strategy", function ( await reth.connect(josh).transfer(oethVault.address, oethUnits("32")); }); it("Should be able to collect reward tokens", async function () { - const { - weth, - reth, - rEthBPT, - balancerREthStrategy, - oethHarvester, - bal, - aura, - } = fixture; + const { balancerREthStrategy, oethHarvester, bal, aura } = fixture; const sHarvester = await impersonateAndFund(oethHarvester.address); const balBefore = await bal.balanceOf(oethHarvester.address); const auraBefore = await aura.balanceOf(oethHarvester.address); - await depositTest(fixture, [5, 5], [weth, reth], rEthBPT); - await mine(1000); - await balancerREthStrategy.connect(sHarvester).collectRewardTokens(); expect(await bal.balanceOf(oethHarvester.address)).to.be.gt( @@ -586,18 +562,12 @@ describe.skip("ForkTest: Balancer MetaStablePool rETH/WETH Strategy", function ( josh, balancerREthStrategy, weth, - reth, oethHarvester, - rEthBPT, oethDripper, bal, aura, } = fixture; - // Deposite some LP to the pool so that we can harvest some tokens - await depositTest(fixture, [5, 5], [weth, reth], rEthBPT); - await mine(1000); - // Let the strategy have some tokens it can send to Harvester await setERC20TokenBalance( balancerREthStrategy.address, diff --git a/contracts/test/strategies/fraxeth.js b/contracts/test/strategies/fraxeth.js index 307253b7b4..6817d69002 100644 --- a/contracts/test/strategies/fraxeth.js +++ b/contracts/test/strategies/fraxeth.js @@ -11,7 +11,7 @@ const { } = require("./../_fixture"); const { impersonateAndFund } = require("../../utils/signers"); -describe("FraxETH Strategy", function () { +describe.skip("FraxETH Strategy", function () { let fixture; const loadFixture = createFixtureLoader(fraxETHStrategyFixture); beforeEach(async () => { diff --git a/contracts/test/strategies/lido_withdrawal_strategy.mainnet.fork-test.js b/contracts/test/strategies/lido_withdrawal_strategy.mainnet.fork-test.js index 4a5d261005..bb42515706 100644 --- a/contracts/test/strategies/lido_withdrawal_strategy.mainnet.fork-test.js +++ b/contracts/test/strategies/lido_withdrawal_strategy.mainnet.fork-test.js @@ -8,6 +8,7 @@ const { impersonateAccount } = require("../../utils/signers"); const { parseUnits } = require("ethers/lib/utils"); const { BigNumber } = require("ethers"); +// Skipping as Lido Withdrawal Strategy has already been used describe.skip("ForkTest: Lido Withdrawal Strategy", function () { this.timeout(360 * 1000); diff --git a/contracts/test/strategies/nativeSsvStaking.fork-test.js b/contracts/test/strategies/nativeSsvStaking.fork-test.js new file mode 100644 index 0000000000..dbaf6f7c81 --- /dev/null +++ b/contracts/test/strategies/nativeSsvStaking.fork-test.js @@ -0,0 +1,35 @@ +const { + createFixtureLoader, + nativeStakingSSVStrategyFixture, +} = require("./../_fixture"); + +const addresses = require("../../utils/addresses"); +const loadFixture = createFixtureLoader(nativeStakingSSVStrategyFixture); +const { shouldBehaveLikeAnSsvStrategy } = require("../behaviour/ssvStrategy"); + +describe("ForkTest: Native SSV Staking Strategy", function () { + this.timeout(0); + + let fixture; + beforeEach(async () => { + fixture = await loadFixture(); + }); + + shouldBehaveLikeAnSsvStrategy(async () => { + return { + ...fixture, + addresses: addresses.mainnet, + testValidator: { + publicKey: + "0xaba6acd335d524a89fb89b9977584afdb23f34a6742547fa9ec1c656fbd2bfc0e7a234460328c2731828c9a43be06e25", + operatorIds: [348, 352, 361, 377], + sharesData: + "0x859f01c8f609cb5cb91f0c98e9b39b077775f10302d0db0edc4ea65e692c97920d5169f6281845a956404c0ba90b88060b74aa3755347441a5729b90bf30a449fa568e21915d11733c7135602b2a3d1a4dce41218ecb0fdb1788ee7e48a9ebd4b4b34f62deea20e9212ce78040dcad2e6382c2f4d4c8b3515a840e1693574068e26c0d58f17dc47d30efe4393f2660dc988aba6166b67732e8df7d9a69d316f330779b2fa4d14712d3bb60436d912bab4464c7c31ae8d2a966d7829063821fc899cc3ec4a8c7098b042323eb9d9cc4d5e945c6d5e6d4eb1b2484163d4b8cd83eea4cc195a68320f023b4d2405cda5110a2eea2c12b70abd9b6bfb567a7850a95fe073a0485c787744efc8658789b0faaff0d942b3c7b89540f594d007936f23c3e7c79fabfe1e2c49199a3f374198e231ca391909ca05ee3c89a7292207131653f6f2f5f5d638d4789a8029001b93827f6f45ef062c9a9d1360a3aedae00fbb8c34495056bacc98c6cecfc1171c84a1e47f3bc328539dbbcd6c79c2aebf7833c684bd807cc8c4dfd6b660e64aece6adf659a969851cf976dead050e9d14aa9c358326c0c0f0cb747041830e124ec872fcf6f82e7f05024da9e6bad10319ca085a0d1519b04c60738043babc1f5a144655e6a28922c2734701c5c93b845996589b8fd246e1bcd97570951cdbed032eeb9c2ac49ac8aeb2e988b6a5513ddcef9ca9bd592c0bce7d38041b52e69e85cda5fd0b84f905c7212b299cf265ee603add20d6459e0841dd05524e96574eebb46473151ec10a08873f7075e15342852f9f16aeb8305211706632475c39ccd8da33969390d035f8a68324e7adced66a726f80532b425cc82dd52a2edc10989db0167317b472a0016215dae35b4c26b28c0ebcf56e115eb32231449812e9ce866a8c0b3128878d3878f5be0670051a8bf94807123c54e6ea2f51607e32c2fe1b132c905c81965dd6d2a7474aa40b65f18d34084a74ba9a21fbdfba3bfaf6b11175d85f03181d655fda086d8dbe2f03dfa2e1b7140b1d9dc68fc9e22f184ed278599d29f6660af128e4c548de6926912d920e35575db90338a1a840f8d8842685f5b459fda573eaf5c5180e3369fc50faa681941dbe7dec83ee9649f30c1a0eac1f8a42fb3083d9274f4c622e2aa1e74b70fa6c027b4f23e1f80bfc4f69248b4d0b3e0eee9372869f97eb89d8d155e469191c48834ad58dd831f1b73409d71fccb958b6582a4ac3f98bcffff2abd393cbe64d7397ada699ecc75301e3be9e9b4ee92a990202c6a5e5112de5ea9cd666f41cdac4611575c8efe2137d6132cd4d4eea0de159eab44588a88f887e4263f673fb365415df537c77a4aaaee12dceff022eafcb8e6973eec7e18eb65cfeefa845b79754ec52a9270f0a7e570b1dd2171e629d498f34e6371726fa8cfe6863f9263c5222a953a44612944183789ad1020de8da527bf850429558dda7896059476e497284512c946d7a57acda3c3ee722d280c0d0daf758d6be88db48e96e14124832c38aa6d0dd38baeb4f246b01d7b0beb55c3983fb182cbf630b778384cc13ab6216611bc1eab94ffe17bb1e829700c99ec28fae1a87eaefd9c8edc4cdf3b6f2b07d85e0d8090ddfb2df4280dacd13a1f30cf946f5606940dc3f75622159b1c6f84bfdbd4ba9fa0f1d522f52bc2049da53f0d06931d650ef1274eb0247844c36349617095f9734e89be683fd7bd5001b416d800c53ec8e8eb533c418a83e803daf6fdfd552ca745bb2b24d8abe899ea89572524343386a035b675e9d5eeae81aefb3a24397f36fe501c66b27d1c0e453fcc975c888d9d6d5a4ca0a4b32b41deebed70", + signature: + "0x90157a1c1b26384f0b4d41bec867d1a000f75e7b634ac7c4c6d8dfc0b0eaeb73bcc99586333d42df98c6b0a8c5ef0d8d071c68991afcd8fbbaa8b423e3632ee4fe0782bc03178a30a8bc6261f64f84a6c833fb96a0f29de1c34ede42c4a859b0", + depositDataRoot: + "0xf7d704e25a2b5bea06fafa2dfe5c6fa906816e5c1622400339b2088a11d5f446", + }, + }; + }); +}); diff --git a/contracts/test/strategies/oeth-morpho-aave.mainnet.fork-test.js b/contracts/test/strategies/oeth-morpho-aave.mainnet.fork-test.js index 0ad076add8..3ad0e5660f 100644 --- a/contracts/test/strategies/oeth-morpho-aave.mainnet.fork-test.js +++ b/contracts/test/strategies/oeth-morpho-aave.mainnet.fork-test.js @@ -10,7 +10,7 @@ const { const { createFixtureLoader, oethMorphoAaveFixture } = require("../_fixture"); const { impersonateAndFund } = require("../../utils/signers"); -describe("ForkTest: Morpho Aave OETH Strategy", function () { +describe.skip("ForkTest: Morpho Aave OETH Strategy", function () { this.timeout(0); // Retry up to 3 times on CI diff --git a/contracts/test/vault/collateral-swaps.mainnet.fork-test.js b/contracts/test/vault/collateral-swaps.mainnet.fork-test.js index 5464747164..196335b197 100644 --- a/contracts/test/vault/collateral-swaps.mainnet.fork-test.js +++ b/contracts/test/vault/collateral-swaps.mainnet.fork-test.js @@ -14,6 +14,7 @@ const { resolveAsset } = require("../../utils/resolvers"); const log = require("../../utils/logger")("test:fork:swaps"); +// Skipping as the OETH vault should now only contain WETH so no more swaps describe.skip("ForkTest: OETH Vault", function () { this.timeout(0); diff --git a/contracts/test/vault/index.js b/contracts/test/vault/index.js index 816674198b..a056d26627 100644 --- a/contracts/test/vault/index.js +++ b/contracts/test/vault/index.js @@ -1,6 +1,6 @@ const { expect } = require("chai"); const hre = require("hardhat"); -const { utils } = require("ethers"); +const { utils, Wallet } = require("ethers"); const { loadDefaultFixture } = require("../_fixture"); const { @@ -361,6 +361,26 @@ describe("Vault", function () { ); }); + it("Should allow governor to change the dripper", async () => { + const { vault, governor } = fixture; + + const newDripper = Wallet.createRandom().address; + + const tx = await vault.connect(governor).setDripper(newDripper); + + await expect(tx).to.emit(vault, "DripperChanged").withArgs(newDripper); + }); + + it("Should not allow non-governor to change the dripper", async () => { + const { vault } = fixture; + + const newDripper = Wallet.createRandom().address; + + const tx = vault.setDripper(newDripper); + + await expect(tx).to.be.revertedWith("Caller is not the Governor"); + }); + it("Should allow governor to change Strategist address", async () => { const { vault, governor, josh } = fixture; diff --git a/contracts/test/vault/oeth-vault.js b/contracts/test/vault/oeth-vault.js index ddc6259356..92d7571af9 100644 --- a/contracts/test/vault/oeth-vault.js +++ b/contracts/test/vault/oeth-vault.js @@ -4,7 +4,8 @@ const hre = require("hardhat"); const { createFixtureLoader, oethDefaultFixture } = require("../_fixture"); const { parseUnits } = require("ethers/lib/utils"); const { deployWithConfirmation } = require("../../utils/deploy"); -const { oethUnits } = require("../helpers"); +const { oethUnits, advanceTime } = require("../helpers"); +const { impersonateAndFund } = require("../../utils/signers"); const addresses = require("../../utils/addresses"); const oethFixture = createFixtureLoader(oethDefaultFixture); @@ -15,10 +16,74 @@ describe("OETH Vault", function () { fixture = await oethFixture(); }); + const snapData = async (fixture) => { + const { oeth, oethVault, weth, user } = fixture; + + const oethTotalSupply = await oeth.totalSupply(); + const oethTotalValue = await oethVault.totalValue(); + const vaultCheckBalance = await oethVault.checkBalance(weth.address); + const userOeth = await oeth.balanceOf(user.address); + const userWeth = await weth.balanceOf(user.address); + const vaultWeth = await weth.balanceOf(oethVault.address); + const queue = await oethVault.withdrawalQueueMetadata(); + + return { + oethTotalSupply, + oethTotalValue, + vaultCheckBalance, + userOeth, + userWeth, + vaultWeth, + queue, + }; + }; + + const assertChangedData = async (dataBefore, delta, fixture) => { + const { oeth, oethVault, weth, user } = fixture; + + expect(await oeth.totalSupply(), "OETH Total Supply").to.equal( + dataBefore.oethTotalSupply.add(delta.oethTotalSupply) + ); + expect(await oethVault.totalValue(), "Vault Total Value").to.equal( + dataBefore.oethTotalValue.add(delta.oethTotalValue) + ); + expect( + await oethVault.checkBalance(weth.address), + "Vault Check Balance of WETH" + ).to.equal(dataBefore.vaultCheckBalance.add(delta.vaultCheckBalance)); + expect(await oeth.balanceOf(user.address), "user's OETH balance").to.equal( + dataBefore.userOeth.add(delta.userOeth) + ); + expect(await weth.balanceOf(user.address), "user's WETH balance").to.equal( + dataBefore.userWeth.add(delta.userWeth) + ); + expect( + await weth.balanceOf(oethVault.address), + "Vault WETH balance" + ).to.equal(dataBefore.vaultWeth.add(delta.vaultWeth)); + + const queueAfter = await oethVault.withdrawalQueueMetadata(); + expect(queueAfter.queued, "Queued").to.equal( + dataBefore.queue.queued.add(delta.queued) + ); + expect(queueAfter.claimable, "Claimable").to.equal( + dataBefore.queue.claimable.add(delta.claimable) + ); + expect(queueAfter.claimed, "Claimed").to.equal( + dataBefore.queue.claimed.add(delta.claimed) + ); + expect(queueAfter.nextWithdrawalIndex, "nextWithdrawalIndex").to.equal( + dataBefore.queue.nextWithdrawalIndex.add(delta.nextWithdrawalIndex) + ); + }; + describe("Mint", () => { - it("should mint with WETH", async () => { + it("Should mint with WETH", async () => { const { oethVault, weth, josh } = fixture; + const fixtureWithUser = { ...fixture, user: josh }; + const dataBefore = await snapData(fixtureWithUser); + const amount = parseUnits("1", 18); const minOeth = parseUnits("0.8", 18); @@ -31,9 +96,26 @@ describe("OETH Vault", function () { await expect(tx) .to.emit(oethVault, "Mint") .withArgs(josh.address, amount); + + await assertChangedData( + dataBefore, + { + oethTotalSupply: amount, + oethTotalValue: amount, + vaultCheckBalance: amount, + userOeth: amount, + userWeth: amount.mul(-1), + vaultWeth: amount, + queued: 0, + claimable: 0, + claimed: 0, + nextWithdrawalIndex: 0, + }, + fixtureWithUser + ); }); - it("should not mint with any other asset", async () => { + it("Fail to mint with any other asset", async () => { const { oethVault, frxETH, stETH, reth, josh } = fixture; const amount = parseUnits("1", 18); @@ -47,14 +129,14 @@ describe("OETH Vault", function () { } }); - it("should revert if mint amount is zero", async () => { + it("Fail to mint if amount is zero", async () => { const { oethVault, weth, josh } = fixture; const tx = oethVault.connect(josh).mint(weth.address, "0", "0"); await expect(tx).to.be.revertedWith("Amount must be greater than 0"); }); - it("should revert if capital is paused", async () => { + it("Fail to mint if capital is paused", async () => { const { oethVault, weth, governor } = fixture; await oethVault.connect(governor).pauseCapital(); @@ -75,18 +157,40 @@ describe("OETH Vault", function () { .connect(governor) .setAssetDefaultStrategy(weth.address, mockStrategy.address); + const fixtureWithUser = { ...fixture, user: domen }; + const dataBefore = await snapData(fixtureWithUser); + // Mint some WETH await weth.connect(domen).approve(oethVault.address, oethUnits("10000")); - await oethVault.connect(domen).mint(weth.address, oethUnits("100"), "0"); + const mintAmount = oethUnits("100"); + await oethVault.connect(domen).mint(weth.address, mintAmount, "0"); expect(await weth.balanceOf(mockStrategy.address)).to.eq( - oethUnits("100") + mintAmount, + "Strategy has the WETH" + ); + + await assertChangedData( + dataBefore, + { + oethTotalSupply: mintAmount, + oethTotalValue: mintAmount, + vaultCheckBalance: mintAmount, + userOeth: mintAmount, + userWeth: mintAmount.mul(-1), + vaultWeth: 0, + queued: 0, + claimable: 0, + claimed: 0, + nextWithdrawalIndex: 0, + }, + fixtureWithUser ); }); }); describe("Redeem", () => { - it("should return only WETH in redeem calculations", async () => { + it("Should return only WETH in redeem calculations", async () => { const { oethVault, weth } = fixture; const outputs = await oethVault.calculateRedeemOutputs( @@ -104,7 +208,7 @@ describe("OETH Vault", function () { } }); - it("should revert if WETH index isn't cached", async () => { + it("Fail to calculateRedeemOutputs if WETH index isn't cached", async () => { const { frxETH, weth } = fixture; await deployWithConfirmation("MockOETHVault", [weth.address]); @@ -116,7 +220,7 @@ describe("OETH Vault", function () { await expect(tx).to.be.revertedWith("WETH Asset index not cached"); }); - it("should update total supply correctly", async () => { + it("Should update total supply correctly without redeem fee", async () => { const { oethVault, oeth, weth, daniel } = fixture; await oethVault.connect(daniel).mint(weth.address, oethUnits("10"), "0"); @@ -136,7 +240,35 @@ describe("OETH Vault", function () { expect(supplyBefore.sub(supplyAfter)).to.eq(oethUnits("10")); }); - it("Should withdraw from strategy if necessary", async () => { + it("Should update total supply correctly with redeem fee", async () => { + const { oethVault, oeth, weth, daniel } = fixture; + await oethVault.connect(daniel).mint(weth.address, oethUnits("10"), "0"); + + await oethVault + .connect(await impersonateAndFund(await oethVault.governor())) + .setRedeemFeeBps(100); + + const userBalanceBefore = await weth.balanceOf(daniel.address); + const vaultBalanceBefore = await weth.balanceOf(oethVault.address); + const supplyBefore = await oeth.totalSupply(); + + await oethVault.connect(daniel).redeem(oethUnits("10"), "0"); + + const userBalanceAfter = await weth.balanceOf(daniel.address); + const vaultBalanceAfter = await weth.balanceOf(oethVault.address); + const supplyAfter = await oeth.totalSupply(); + + // Make sure the total supply went down + expect(userBalanceAfter.sub(userBalanceBefore)).to.eq( + oethUnits("10").sub(oethUnits("0.1")) + ); + expect(vaultBalanceBefore.sub(vaultBalanceAfter)).to.eq( + oethUnits("10").sub(oethUnits("0.1")) + ); + expect(supplyBefore.sub(supplyAfter)).to.eq(oethUnits("10")); + }); + + it("Fail to redeem if not enough liquidity available in the vault", async () => { const { oethVault, weth, domen, governor } = fixture; const mockStrategy = await deployWithConfirmation("MockStrategy"); @@ -152,37 +284,37 @@ describe("OETH Vault", function () { // Mint a small amount that won't get allocated to the strategy await oethVault.connect(domen).mint(weth.address, oethUnits("1.23"), "0"); - const vaultBalanceBefore = await weth.balanceOf(oethVault.address); - const stratBalanceBefore = await weth.balanceOf(mockStrategy.address); - const userBalanceBefore = await weth.balanceOf(domen.address); - // Withdraw something more than what the Vault holds - await oethVault.connect(domen).redeem(oethUnits("12.55"), "0"); - - const vaultBalanceAfter = await weth.balanceOf(oethVault.address); - const stratBalanceAfter = await weth.balanceOf(mockStrategy.address); - const userBalanceAfter = await weth.balanceOf(domen.address); + const tx = oethVault.connect(domen).redeem(oethUnits("12.55"), "0"); - expect(userBalanceAfter.sub(userBalanceBefore)).to.eq(oethUnits("12.55")); + await expect(tx).to.revertedWith("Liquidity error"); + }); - expect(stratBalanceBefore.sub(stratBalanceAfter)).to.eq( - oethUnits("12.55") - ); + it("Should redeem zero amount without revert", async () => { + const { oethVault, daniel } = fixture; - expect(vaultBalanceBefore).to.eq(vaultBalanceAfter); + await oethVault.connect(daniel).redeem(0, 0); }); - it("should revert on liquidity error", async () => { + it("Fail to redeem if not enough liquidity", async () => { const { oethVault, daniel } = fixture; const tx = oethVault .connect(daniel) .redeem(oethUnits("1023232323232"), "0"); await expect(tx).to.be.revertedWith("Liquidity error"); }); + it("Should allow every user to redeem", async () => { + const { oethVault, weth, daniel } = fixture; + await oethVault.connect(daniel).mint(weth.address, oethUnits("10"), "0"); + + await oethVault.connect(daniel).redeem(oethUnits("10"), oethUnits("0")); + + await expect(await weth.balanceOf(oethVault.address)).to.equal(0); + }); }); describe("Config", () => { - it("should allow caching WETH index", async () => { + it("Should allow caching WETH index", async () => { const { oethVault, weth, governor } = fixture; await oethVault.connect(governor).cacheWETHAssetIndex(); @@ -194,14 +326,14 @@ describe("OETH Vault", function () { expect(assets[index]).to.equal(weth.address); }); - it("should not allow anyone other than Governor to change cached index", async () => { + it("Fail to allow anyone other than Governor to change cached index", async () => { const { oethVault, strategist } = fixture; const tx = oethVault.connect(strategist).cacheWETHAssetIndex(); await expect(tx).to.be.revertedWith("Caller is not the Governor"); }); - it("should revert if WETH is not an supported asset", async () => { + it("Fail to cacheWETHAssetIndex if WETH is not a supported asset", async () => { const { frxETH, weth } = fixture; const { deployerAddr } = await hre.getNamedAccounts(); const sDeployer = hre.ethers.provider.getSigner(deployerAddr); @@ -214,10 +346,27 @@ describe("OETH Vault", function () { const tx = mockVault.connect(sDeployer).cacheWETHAssetIndex(); await expect(tx).to.be.revertedWith("Invalid WETH Asset Index"); }); + + it("Should return all strategies", async () => { + // Mostly to increase coverage + + const { oethVault, weth, governor } = fixture; + + // Empty list + await expect((await oethVault.getAllStrategies()).length).to.equal(0); + + // Add a strategy + await oethVault.connect(governor).approveStrategy(weth.address); + + // Check the strategy list + await expect(await oethVault.getAllStrategies()).to.deep.equal([ + weth.address, + ]); + }); }); describe("Remove Asset", () => { - it("should allow removing a single asset", async () => { + it("Should allow removing a single asset", async () => { const { oethVault, frxETH, governor } = fixture; const vaultAdmin = await ethers.getContractAt( @@ -250,7 +399,7 @@ describe("OETH Vault", function () { expect(config.isSupported).to.be.false; }); - it("should only allow governance to remove assets", async () => { + it("Should only allow governance to remove assets", async () => { const { oethVault, weth, strategist, josh } = fixture; for (const signer of [strategist, josh]) { @@ -262,14 +411,14 @@ describe("OETH Vault", function () { } }); - it("should revert if asset is not supported", async () => { + it("Fail to remove asset if asset is not supported", async () => { const { oethVault, dai, governor } = fixture; const tx = oethVault.connect(governor).removeAsset(dai.address); await expect(tx).to.be.revertedWith("Asset not supported"); }); - it("should revert if vault still holds the asset", async () => { + it("Fail to remove asset if vault still holds the asset", async () => { const { oethVault, weth, governor, daniel } = fixture; await oethVault.connect(daniel).mint(weth.address, oethUnits("1"), "0"); @@ -279,7 +428,7 @@ describe("OETH Vault", function () { await expect(tx).to.be.revertedWith("Vault still holds asset"); }); - it("should not revert for smaller dust", async () => { + it("Fail to revert for smaller dust", async () => { const { oethVault, weth, governor, daniel } = fixture; await oethVault.connect(daniel).mint(weth.address, "500000000000", "0"); @@ -288,5 +437,1808 @@ describe("OETH Vault", function () { await expect(tx).to.not.be.revertedWith("Vault still holds asset"); }); + + it("Should allow strategy to burnForStrategy", async () => { + const { oethVault, oeth, weth, governor, daniel } = fixture; + + await oethVault.connect(governor).setOusdMetaStrategy(daniel.address); + + // First increase netOusdMintForStrategyThreshold + await oethVault + .connect(governor) + .setNetOusdMintForStrategyThreshold(oethUnits("100")); + + // Then mint for strategy + await oethVault.connect(daniel).mint(weth.address, oethUnits("10"), "0"); + + await expect(await oeth.balanceOf(daniel.address)).to.equal( + oethUnits("10") + ); + + // Then burn for strategy + await oethVault.connect(daniel).burnForStrategy(oethUnits("10")); + + await expect(await oeth.balanceOf(daniel.address)).to.equal( + oethUnits("0") + ); + }); + + it("Fail when burnForStrategy because Amoount too high", async () => { + const { oethVault, governor, daniel } = fixture; + + await oethVault.connect(governor).setOusdMetaStrategy(daniel.address); + const tx = oethVault + .connect(daniel) + .burnForStrategy(parseUnits("10", 76)); + + await expect(tx).to.be.revertedWith("Amount too high"); + }); + + it("Fail when burnForStrategy because Attempting to burn too much OUSD.", async () => { + const { oethVault, governor, daniel } = fixture; + + await oethVault.connect(governor).setOusdMetaStrategy(daniel.address); + + // Then try to burn more than authorized + const tx = oethVault.connect(daniel).burnForStrategy(oethUnits("0")); + + await expect(tx).to.be.revertedWith("Attempting to burn too much OUSD."); + }); + }); + + describe("Allocate", () => { + const delayPeriod = 10 * 60; // 10mins + it("Shouldn't allocate as minted amount is lower than autoAllocateThreshold", async () => { + const { oethVault, weth, daniel } = fixture; + + // Set auto allocate threshold to 100 WETH + await oethVault + .connect(await impersonateAndFund(await oethVault.governor())) + .setAutoAllocateThreshold(oethUnits("100")); + + // Mint for 10 WETH + const tx = oethVault + .connect(daniel) + .mint(weth.address, oethUnits("10"), "0"); + + await expect(tx).to.not.emit(oethVault, "AssetAllocated"); + }); + it("Shouldn't allocate as no WETH available", async () => { + const { oethVault, weth, daniel } = fixture; + + // Deploy default strategy + const mockStrategy = await deployWithConfirmation("MockStrategy"); + await oethVault + .connect(await impersonateAndFund(await oethVault.governor())) + .approveStrategy(mockStrategy.address); + await oethVault + .connect(await impersonateAndFund(await oethVault.governor())) + .setAssetDefaultStrategy(weth.address, mockStrategy.address); + + // Mint will allocate all to default strategy bc no buffer, no threshold + await oethVault.connect(daniel).mint(weth.address, oethUnits("10"), "0"); + await oethVault.connect(daniel).requestWithdrawal(oethUnits("5")); + + // Deposit less than queued amount (5 WETH) => _wethAvailable() return 0 + const tx = oethVault + .connect(daniel) + .mint(weth.address, oethUnits("3", "0")); + expect(tx).to.not.emit(oethVault, "AssetAllocated"); + }); + it("Shouldn't allocate as WETH available is lower than buffer", async () => { + const { oethVault, weth, daniel } = fixture; + + await oethVault.connect(daniel).mint(weth.address, oethUnits("100"), "0"); + + // Set vault buffer to 5% + await oethVault + .connect(await impersonateAndFund(await oethVault.governor())) + .setVaultBuffer(oethUnits("0.05")); + + // OETH total supply = 100(first deposit) + 5(second deposit) = 105 + // Buffer = 105 * 5% = 5.25 WETH + // Second deposit should remain in the vault as below vault buffer + const tx = oethVault.connect(daniel).mint(oethUnits("5"), "0"); + expect(tx).to.not.emit(oethVault, "AssetAllocated"); + }); + it("Shouldn't allocate as default strategy is address null", async () => { + const { oethVault, weth, daniel } = fixture; + + const tx = oethVault + .connect(daniel) + .mint(weth.address, oethUnits("100"), "0"); + + expect(tx).to.not.emit(oethVault, "AssetAllocated"); + }); + describe("Should allocate WETH available to default strategy when: ", () => { + let mockStrategy; + beforeEach(async () => { + // Deploy default strategy + const { oethVault, weth } = fixture; + mockStrategy = await deployWithConfirmation("MockStrategy"); + await oethVault + .connect(await impersonateAndFund(await oethVault.governor())) + .approveStrategy(mockStrategy.address); + await oethVault + .connect(await impersonateAndFund(await oethVault.governor())) + .setAssetDefaultStrategy(weth.address, mockStrategy.address); + }); + it("buffer is 0%, 0 WETH in queue", async () => { + const { oethVault, daniel, weth } = fixture; + const tx = oethVault + .connect(daniel) + .mint(weth.address, oethUnits("10"), "0"); + await expect(tx) + .to.emit(oethVault, "AssetAllocated") + .withArgs(weth.address, mockStrategy.address, oethUnits("10")); + expect(await weth.balanceOf(mockStrategy.address)).to.be.equal( + oethUnits("10") + ); + }); + it("buffer is 5%", async () => { + const { oethVault, daniel, weth } = fixture; + // Set vault buffer to 5% + await oethVault + .connect(await impersonateAndFund(await oethVault.governor())) + .setVaultBuffer(oethUnits("0.05")); + + const tx = oethVault + .connect(daniel) + .mint(weth.address, oethUnits("10"), "0"); + await expect(tx) + .to.emit(oethVault, "AssetAllocated") + .withArgs(weth.address, mockStrategy.address, oethUnits("9.5")); + expect(await weth.balanceOf(mockStrategy.address)).to.be.equal( + oethUnits("9.5") + ); + }); + it("buffer is 0%, 10 WETH in queue", async () => { + const { oethVault, daniel, weth } = fixture; + await oethVault + .connect(daniel) + .mint(weth.address, oethUnits("10"), "0"); + await oethVault.connect(daniel).requestWithdrawal(oethUnits("10")); + const tx = oethVault + .connect(daniel) + .mint(weth.address, oethUnits("20"), "0"); + + // 10 WETH in the queue, 10 WETH in strat. New deposit of 20, only 10 WETH available to allocate to strategy. + await expect(tx) + .to.emit(oethVault, "AssetAllocated") + .withArgs(weth.address, mockStrategy.address, oethUnits("10")); + expect(await weth.balanceOf(mockStrategy.address)).to.be.equal( + oethUnits("20") + ); + }); + it("buffer is 0%, 20 WETH in queue, 10 WETH claimed", async () => { + const { oethVault, daniel, weth } = fixture; + await oethVault + .connect(daniel) + .mint(weth.address, oethUnits("30"), "0"); + await oethVault.connect(daniel).requestWithdrawal(oethUnits("10")); + await advanceTime(delayPeriod); + // Simulate strategist pulling back WETH to the vault. + await weth + .connect(await impersonateAndFund(mockStrategy.address)) + .transfer(oethVault.address, oethUnits("10")); + await oethVault.connect(daniel).claimWithdrawal(0); + // So far, 10 WETH queued, 10 WETH claimed, 0 WETH available, 20 WETH in strat + + await oethVault.connect(daniel).requestWithdrawal(oethUnits("10")); + // So far, 20 WETH queued, 10 WETH claimed, 0 WETH available, 20 WETH in strat + + // Deposit 35 WETH, 10 WETH should remain in the vault for withdraw, so strat should have 45WETH. + const tx = oethVault + .connect(daniel) + .mint(weth.address, oethUnits("35"), "0"); + await expect(tx) + .to.emit(oethVault, "AssetAllocated") + .withArgs(weth.address, mockStrategy.address, oethUnits("25")); + + expect(await weth.balanceOf(mockStrategy.address)).to.be.equal( + oethUnits("45") + ); + }); + it("buffer is 5%, 20 WETH in queue, 10 WETH claimed", async () => { + const { oethVault, daniel, weth } = fixture; + await oethVault + .connect(daniel) + .mint(weth.address, oethUnits("40"), "0"); + await oethVault.connect(daniel).requestWithdrawal(oethUnits("10")); + await advanceTime(delayPeriod); + // Simulate strategist pulling back WETH to the vault. + await weth + .connect(await impersonateAndFund(mockStrategy.address)) + .transfer(oethVault.address, oethUnits("10")); + await oethVault.connect(daniel).claimWithdrawal(0); + // So far, 10 WETH queued, 10 WETH claimed, 0 WETH available, 30 WETH in strat + + await oethVault.connect(daniel).requestWithdrawal(oethUnits("10")); + // So far, 20 WETH queued, 10 WETH claimed, 0 WETH available, 30 WETH in strat + + // Set vault buffer to 5% + await oethVault + .connect(await impersonateAndFund(await oethVault.governor())) + .setVaultBuffer(oethUnits("0.05")); + + // Deposit 40 WETH, 10 WETH should remain in the vault for withdraw + 3 (i.e. 20+40 *5%) + // So strat should have 57WETH. + const tx = oethVault + .connect(daniel) + .mint(weth.address, oethUnits("40"), "0"); + await expect(tx) + .to.emit(oethVault, "AssetAllocated") + .withArgs(weth.address, mockStrategy.address, oethUnits("27")); + + expect(await weth.balanceOf(mockStrategy.address)).to.be.equal( + oethUnits("57") + ); + }); + }); + }); + + describe("Withdrawal Queue", () => { + const delayPeriod = 10 * 60; // 10 minutes + describe("with all 60 WETH in the vault", () => { + beforeEach(async () => { + const { oethVault, weth, daniel, josh, matt } = fixture; + // Mint some OETH to three users + await oethVault + .connect(daniel) + .mint(weth.address, oethUnits("10"), "0"); + await oethVault.connect(josh).mint(weth.address, oethUnits("20"), "0"); + await oethVault.connect(matt).mint(weth.address, oethUnits("30"), "0"); + await oethVault + .connect(await impersonateAndFund(await oethVault.governor())) + .setMaxSupplyDiff(oethUnits("0.03")); + }); + const firstRequestAmount = oethUnits("5"); + const secondRequestAmount = oethUnits("18"); + it("Should request first withdrawal by Daniel", async () => { + const { oethVault, daniel } = fixture; + const fixtureWithUser = { ...fixture, user: daniel }; + const dataBefore = await snapData(fixtureWithUser); + + const tx = await oethVault + .connect(daniel) + .requestWithdrawal(firstRequestAmount); + + await expect(tx) + .to.emit(oethVault, "WithdrawalRequested") + .withArgs(daniel.address, 0, firstRequestAmount, firstRequestAmount); + + await assertChangedData( + dataBefore, + { + oethTotalSupply: firstRequestAmount.mul(-1), + oethTotalValue: firstRequestAmount.mul(-1), + vaultCheckBalance: firstRequestAmount.mul(-1), + userOeth: firstRequestAmount.mul(-1), + userWeth: 0, + vaultWeth: 0, + queued: firstRequestAmount, + claimable: 0, + claimed: 0, + nextWithdrawalIndex: 1, + }, + fixtureWithUser + ); + }); + it("Should request withdrawal of zero amount", async () => { + const { oethVault, josh } = fixture; + const fixtureWithUser = { ...fixture, user: josh }; + await oethVault.connect(josh).requestWithdrawal(firstRequestAmount); + const dataBefore = await snapData(fixtureWithUser); + + const tx = await oethVault.connect(josh).requestWithdrawal(0); + + await expect(tx) + .to.emit(oethVault, "WithdrawalRequested") + .withArgs(josh.address, 1, 0, firstRequestAmount); + + await assertChangedData( + dataBefore, + { + oethTotalSupply: 0, + oethTotalValue: 0, + vaultCheckBalance: 0, + userOeth: 0, + userWeth: 0, + vaultWeth: 0, + queued: 0, + claimable: 0, + claimed: 0, + nextWithdrawalIndex: 1, + }, + fixtureWithUser + ); + }); + it("Should request first and second withdrawals with no WETH in the Vault", async () => { + const { oethVault, governor, josh, matt, weth } = fixture; + const fixtureWithUser = { ...fixture, user: josh }; + + const mockStrategy = await deployWithConfirmation("MockStrategy"); + await oethVault.connect(governor).approveStrategy(mockStrategy.address); + + // Deposit all 10 + 20 + 30 = 60 WETH to strategy + await oethVault + .connect(governor) + .depositToStrategy( + mockStrategy.address, + [weth.address], + [oethUnits("60")] + ); + + const dataBefore = await snapData(fixtureWithUser); + + await oethVault.connect(josh).requestWithdrawal(firstRequestAmount); + const tx = await oethVault + .connect(matt) + .requestWithdrawal(secondRequestAmount); + + await expect(tx) + .to.emit(oethVault, "WithdrawalRequested") + .withArgs( + matt.address, + 1, + secondRequestAmount, + firstRequestAmount.add(secondRequestAmount) + ); + + await assertChangedData( + dataBefore, + { + oethTotalSupply: firstRequestAmount + .add(secondRequestAmount) + .mul(-1), + oethTotalValue: firstRequestAmount.add(secondRequestAmount).mul(-1), + vaultCheckBalance: firstRequestAmount + .add(secondRequestAmount) + .mul(-1), + userOeth: firstRequestAmount.mul(-1), + userWeth: 0, + vaultWeth: 0, + queued: firstRequestAmount.add(secondRequestAmount), + claimable: 0, + claimed: 0, + nextWithdrawalIndex: 2, + }, + fixtureWithUser + ); + }); + it("Should request second withdrawal by matt", async () => { + const { oethVault, daniel, matt } = fixture; + const fixtureWithUser = { ...fixture, user: matt }; + await oethVault.connect(daniel).requestWithdrawal(firstRequestAmount); + const dataBefore = await snapData(fixtureWithUser); + + const tx = await oethVault + .connect(matt) + .requestWithdrawal(secondRequestAmount); + + await expect(tx) + .to.emit(oethVault, "WithdrawalRequested") + .withArgs( + matt.address, + 1, + secondRequestAmount, + firstRequestAmount.add(secondRequestAmount) + ); + + await assertChangedData( + dataBefore, + { + oethTotalSupply: secondRequestAmount.mul(-1), + oethTotalValue: secondRequestAmount.mul(-1), + vaultCheckBalance: secondRequestAmount.mul(-1), + userOeth: secondRequestAmount.mul(-1), + userWeth: 0, + vaultWeth: 0, + queued: secondRequestAmount, + claimable: 0, + claimed: 0, + nextWithdrawalIndex: 1, + }, + fixtureWithUser + ); + }); + it("Should add claimable liquidity to the withdrawal queue", async () => { + const { oethVault, daniel, josh } = fixture; + const fixtureWithUser = { ...fixture, user: josh }; + await oethVault.connect(daniel).requestWithdrawal(firstRequestAmount); + await oethVault.connect(josh).requestWithdrawal(secondRequestAmount); + const dataBefore = await snapData(fixtureWithUser); + + const tx = await oethVault.connect(josh).addWithdrawalQueueLiquidity(); + + await expect(tx) + .to.emit(oethVault, "WithdrawalClaimable") + .withArgs( + firstRequestAmount.add(secondRequestAmount), + firstRequestAmount.add(secondRequestAmount) + ); + + await assertChangedData( + dataBefore, + { + oethTotalSupply: 0, + oethTotalValue: 0, + vaultCheckBalance: 0, + userOeth: 0, + userWeth: 0, + vaultWeth: 0, + queued: 0, + claimable: firstRequestAmount.add(secondRequestAmount), + claimed: 0, + nextWithdrawalIndex: 0, + }, + fixtureWithUser + ); + }); + it("Should claim second request with enough liquidity", async () => { + const { oethVault, daniel, josh } = fixture; + const fixtureWithUser = { ...fixture, user: josh }; + await oethVault.connect(daniel).requestWithdrawal(firstRequestAmount); + await oethVault.connect(josh).requestWithdrawal(secondRequestAmount); + const requestId = 1; // ids start at 0 so the second request is at index 1 + const dataBefore = await snapData(fixtureWithUser); + + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + + const tx = await oethVault.connect(josh).claimWithdrawal(requestId); + + await expect(tx) + .to.emit(oethVault, "WithdrawalClaimed") + .withArgs(josh.address, requestId, secondRequestAmount); + await expect(tx) + .to.emit(oethVault, "WithdrawalClaimable") + .withArgs( + firstRequestAmount.add(secondRequestAmount), + firstRequestAmount.add(secondRequestAmount) + ); + + await assertChangedData( + dataBefore, + { + oethTotalSupply: 0, + oethTotalValue: 0, + vaultCheckBalance: 0, + userOeth: 0, + userWeth: secondRequestAmount, + vaultWeth: secondRequestAmount.mul(-1), + queued: 0, + claimable: firstRequestAmount.add(secondRequestAmount), + claimed: secondRequestAmount, + nextWithdrawalIndex: 0, + }, + fixtureWithUser + ); + }); + it("Should claim multiple requests with enough liquidity", async () => { + const { oethVault, matt } = fixture; + const fixtureWithUser = { ...fixture, user: matt }; + await oethVault.connect(matt).requestWithdrawal(firstRequestAmount); + await oethVault.connect(matt).requestWithdrawal(secondRequestAmount); + const dataBefore = await snapData(fixtureWithUser); + + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + + const tx = await oethVault.connect(matt).claimWithdrawals([0, 1]); + + await expect(tx) + .to.emit(oethVault, "WithdrawalClaimed") + .withArgs(matt.address, 0, firstRequestAmount); + await expect(tx) + .to.emit(oethVault, "WithdrawalClaimed") + .withArgs(matt.address, 1, secondRequestAmount); + await expect(tx) + .to.emit(oethVault, "WithdrawalClaimable") + .withArgs( + firstRequestAmount.add(secondRequestAmount), + firstRequestAmount.add(secondRequestAmount) + ); + + await assertChangedData( + dataBefore, + { + oethTotalSupply: 0, + oethTotalValue: 0, + vaultCheckBalance: 0, + userOeth: 0, + userWeth: firstRequestAmount.add(secondRequestAmount), + vaultWeth: firstRequestAmount.add(secondRequestAmount).mul(-1), + queued: 0, + claimable: firstRequestAmount.add(secondRequestAmount), + claimed: firstRequestAmount.add(secondRequestAmount), + nextWithdrawalIndex: 0, + }, + fixtureWithUser + ); + }); + it("Should claim single big request as a whale", async () => { + const { oethVault, oeth, matt } = fixture; + + const oethBalanceBefore = await oeth.balanceOf(matt.address); + const totalValueBefore = await oethVault.totalValue(); + + await oethVault.connect(matt).requestWithdrawal(oethUnits("30")); + + const oethBalanceAfter = await oeth.balanceOf(matt.address); + const totalValueAfter = await oethVault.totalValue(); + await expect(oethBalanceBefore).to.equal(oethUnits("30")); + await expect(oethBalanceAfter).to.equal(oethUnits("0")); + await expect(totalValueBefore.sub(totalValueAfter)).to.equal( + oethUnits("30") + ); + + const oethTotalSupply = await oeth.totalSupply(); + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + const tx = await oethVault.connect(matt).claimWithdrawal(0); // Claim withdrawal for 50% of the supply + + await expect(tx) + .to.emit(oethVault, "WithdrawalClaimed") + .withArgs(matt.address, 0, oethUnits("30")); + + await expect(oethTotalSupply).to.equal(await oeth.totalSupply()); + await expect(totalValueAfter).to.equal(await oethVault.totalValue()); + }); + + it("Fail to claim request because of not enough time passed", async () => { + const { oethVault, daniel } = fixture; + + // Daniel requests 5 OETH to be withdrawn + await oethVault.connect(daniel).requestWithdrawal(firstRequestAmount); + const requestId = 0; + + // Daniel claimWithdraw request in the same block as the request + const tx = oethVault.connect(daniel).claimWithdrawal(requestId); + + await expect(tx).to.revertedWith("Claim delay not met"); + }); + it("Fail to request withdrawal because of solvency check too high", async () => { + const { oethVault, daniel, weth } = fixture; + + await weth.connect(daniel).transfer(oethVault.address, oethUnits("10")); + + const tx = oethVault + .connect(daniel) + .requestWithdrawal(firstRequestAmount); + + await expect(tx).to.revertedWith("Backing supply liquidity error"); + }); + it("Fail to claim request because of solvency check too high", async () => { + const { oethVault, daniel, weth } = fixture; + + // Request withdrawal of 5 OETH + await oethVault.connect(daniel).requestWithdrawal(firstRequestAmount); + + // Transfer 10 WETH to the vault + await weth.connect(daniel).transfer(oethVault.address, oethUnits("10")); + + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + + // Claim the withdrawal + const tx = oethVault.connect(daniel).claimWithdrawal(0); + + await expect(tx).to.revertedWith("Backing supply liquidity error"); + }); + it("Fail multiple claim requests because of solvency check too high", async () => { + const { oethVault, matt, weth } = fixture; + + // Request withdrawal of 5 OETH + await oethVault.connect(matt).requestWithdrawal(firstRequestAmount); + await oethVault.connect(matt).requestWithdrawal(secondRequestAmount); + + // Transfer 10 WETH to the vault + await weth.connect(matt).transfer(oethVault.address, oethUnits("10")); + + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + + // Claim the withdrawal + const tx = oethVault.connect(matt).claimWithdrawals([0, 1]); + + await expect(tx).to.revertedWith("Backing supply liquidity error"); + }); + + it("Fail request withdrawal because of solvency check too low", async () => { + const { oethVault, daniel, weth } = fixture; + + // Simulate a loss of funds from the vault + await weth + .connect(await impersonateAndFund(oethVault.address)) + .transfer(daniel.address, oethUnits("10")); + + const tx = oethVault + .connect(daniel) + .requestWithdrawal(firstRequestAmount); + + await expect(tx).to.revertedWith("Backing supply liquidity error"); + }); + + describe("when deposit 15 WETH to a strategy, leaving 60 - 15 = 45 WETH in the vault; request withdrawal of 5 + 18 = 23 OETH, leaving 45 - 23 = 22 WETH unallocated", () => { + let mockStrategy; + beforeEach(async () => { + const { oethVault, weth, governor, daniel, josh } = fixture; + + const dMockStrategy = await deployWithConfirmation("MockStrategy"); + mockStrategy = await ethers.getContractAt( + "MockStrategy", + dMockStrategy.address + ); + await mockStrategy.setWithdrawAll(weth.address, oethVault.address); + await oethVault + .connect(governor) + .approveStrategy(mockStrategy.address); + + // Deposit 15 WETH of 10 + 20 + 30 = 60 WETH to strategy + // This leave 60 - 15 = 45 WETH in the vault + await oethVault + .connect(governor) + .depositToStrategy( + mockStrategy.address, + [weth.address], + [oethUnits("15")] + ); + // Request withdrawal of 5 + 18 = 23 OETH + // This leave 45 - 23 = 22 WETH unallocated to the withdrawal queue + await oethVault.connect(daniel).requestWithdrawal(firstRequestAmount); + await oethVault.connect(josh).requestWithdrawal(secondRequestAmount); + }); + it("Fail to deposit allocated WETH to a strategy", async () => { + const { oethVault, weth, governor } = fixture; + + // WETH in the vault = 60 - 15 = 45 WETH + // unallocated WETH in the Vault = 45 - 23 = 22 WETH + // 23 WETH to deposit > the 22 WETH available so it should revert + const depositAmount = oethUnits("23"); + const tx = oethVault + .connect(governor) + .depositToStrategy( + mockStrategy.address, + [weth.address], + [depositAmount] + ); + await expect(tx).to.be.revertedWith("Not enough WETH available"); + }); + it("Fail to deposit allocated WETH during allocate", async () => { + const { oethVault, governor, weth } = fixture; + + // Set mock strategy as default strategy + await oethVault + .connect(governor) + .setAssetDefaultStrategy(weth.address, mockStrategy.address); + + // and buffer to 10% + await oethVault.connect(governor).setVaultBuffer(oethUnits("0.1")); + + // WETH in strategy = 15 WETH + // WETH in the vault = 60 - 15 = 45 WETH + // Unallocated WETH in the vault = 45 - 23 = 22 WETH + + await oethVault.connect(governor).allocate(); + + expect(await weth.balanceOf(mockStrategy.address)).to.approxEqual( + // 60 - 23 = 37 Unreserved WETH + // 90% of 37 = 33.3 WETH for allocation + oethUnits("33.3"), + "Strategy has the reserved WETH" + ); + + expect(await weth.balanceOf(oethVault.address)).to.approxEqual( + // 10% of 37 = 3.7 WETH for Vault buffer + // + 23 reserved WETH + oethUnits("23").add(oethUnits("3.7")), + "Vault doesn't have enough WETH" + ); + }); + it("Should deposit unallocated WETH to a strategy", async () => { + const { oethVault, weth, governor } = fixture; + + // WETH in the vault = 60 - 15 = 45 WETH + // unallocated WETH in the Vault = 45 - 23 = 22 WETH + const depositAmount = oethUnits("22"); + await oethVault + .connect(governor) + .depositToStrategy( + mockStrategy.address, + [weth.address], + [depositAmount] + ); + }); + it("Should claim first request with enough liquidity", async () => { + const { oethVault, daniel } = fixture; + const fixtureWithUser = { ...fixture, user: daniel }; + const dataBefore = await snapData(fixtureWithUser); + + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + + const tx = await oethVault.connect(daniel).claimWithdrawal(0); + + await expect(tx) + .to.emit(oethVault, "WithdrawalClaimed") + .withArgs(daniel.address, 0, firstRequestAmount); + + await assertChangedData( + dataBefore, + { + oethTotalSupply: 0, + oethTotalValue: 0, + vaultCheckBalance: 0, + userOeth: 0, + userWeth: firstRequestAmount, + vaultWeth: firstRequestAmount.mul(-1), + queued: 0, + claimable: firstRequestAmount.add(secondRequestAmount), + claimed: firstRequestAmount, + nextWithdrawalIndex: 0, + }, + fixtureWithUser + ); + }); + it("Should claim a new request with enough WETH liquidity", async () => { + const { oethVault, matt } = fixture; + const fixtureWithUser = { ...fixture, user: matt }; + + // Set the claimable amount to the queued amount + await oethVault.addWithdrawalQueueLiquidity(); + + // WETH in the vault = 60 - 15 = 45 WETH + // unallocated WETH in the Vault = 45 - 23 = 22 WETH + // Matt request all unallocated WETH to be withdrawn + const requestAmount = oethUnits("22"); + await oethVault.connect(matt).requestWithdrawal(requestAmount); + + const dataBefore = await snapData(fixtureWithUser); + + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + + const tx = await oethVault.connect(matt).claimWithdrawal(2); + + await expect(tx) + .to.emit(oethVault, "WithdrawalClaimed") + .withArgs(matt.address, 2, requestAmount); + + await assertChangedData( + dataBefore, + { + oethTotalSupply: 0, + oethTotalValue: 0, + vaultCheckBalance: 0, + userOeth: 0, + userWeth: requestAmount, + vaultWeth: requestAmount.mul(-1), + queued: 0, + claimable: requestAmount, + claimed: requestAmount, + nextWithdrawalIndex: 0, + }, + fixtureWithUser + ); + }); + it("Fail to claim a new request with NOT enough WETH liquidity", async () => { + const { oethVault, matt } = fixture; + + // Matt request 23 OETH to be withdrawn when only 22 WETH is unallocated to existing requests + const requestAmount = oethUnits("23"); + await oethVault.connect(matt).requestWithdrawal(requestAmount); + + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + + const tx = oethVault.connect(matt).claimWithdrawal(2); + await expect(tx).to.be.revertedWith("Queue pending liquidity"); + }); + it("Should claim a new request after withdraw from strategy adds enough liquidity", async () => { + const { oethVault, daniel, matt, strategist, weth } = fixture; + + // Set the claimable amount to the queued amount + await oethVault.addWithdrawalQueueLiquidity(); + + // Matt requests all 30 OETH to be withdrawn which is currently 8 WETH short + const requestAmount = oethUnits("30"); + await oethVault.connect(matt).requestWithdrawal(requestAmount); + + const fixtureWithUser = { ...fixture, user: daniel }; + const dataBeforeMint = await snapData(fixtureWithUser); + + // WETH in the vault = 60 - 15 = 45 WETH + // unallocated WETH in the Vault = 45 - 23 = 22 WETH + // Add another 8 WETH so the unallocated WETH is 22 + 8 = 30 WETH + const withdrawAmount = oethUnits("8"); + await oethVault + .connect(strategist) + .withdrawFromStrategy( + mockStrategy.address, + [weth.address], + [withdrawAmount] + ); + + await assertChangedData( + dataBeforeMint, + { + oethTotalSupply: 0, + oethTotalValue: 0, + vaultCheckBalance: 0, + userOeth: 0, + userWeth: 0, + vaultWeth: withdrawAmount, + queued: 0, + claimable: requestAmount, + claimed: 0, + nextWithdrawalIndex: 0, + }, + fixtureWithUser + ); + + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + + await oethVault.connect(matt).claimWithdrawal(2); + }); + it("Should claim a new request after withdrawAllFromStrategy adds enough liquidity", async () => { + const { oethVault, daniel, matt, strategist, weth } = fixture; + + // Set the claimable amount to the queued amount + await oethVault.addWithdrawalQueueLiquidity(); + + // Matt requests all 30 OETH to be withdrawn which is currently 8 WETH short + const requestAmount = oethUnits("30"); + await oethVault.connect(matt).requestWithdrawal(requestAmount); + + const fixtureWithUser = { ...fixture, user: daniel }; + const dataBeforeMint = await snapData(fixtureWithUser); + const strategyBalanceBefore = await weth.balanceOf( + mockStrategy.address + ); + + // WETH in the vault = 60 - 15 = 45 WETH + // unallocated WETH in the Vault = 45 - 23 = 22 WETH + // Add another 8 WETH so the unallocated WETH is 22 + 8 = 30 WETH + await oethVault + .connect(strategist) + .withdrawAllFromStrategy(mockStrategy.address); + + await assertChangedData( + dataBeforeMint, + { + oethTotalSupply: 0, + oethTotalValue: 0, + vaultCheckBalance: 0, + userOeth: 0, + userWeth: 0, + vaultWeth: strategyBalanceBefore, + queued: 0, + claimable: requestAmount, + claimed: 0, + nextWithdrawalIndex: 0, + }, + fixtureWithUser + ); + + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + + await oethVault.connect(matt).claimWithdrawal(2); + }); + it("Should claim a new request after withdrawAll from strategies adds enough liquidity", async () => { + const { oethVault, daniel, matt, strategist, weth } = fixture; + + // Set the claimable amount to the queued amount + await oethVault.addWithdrawalQueueLiquidity(); + + // Matt requests all 30 OETH to be withdrawn which is currently 8 WETH short + const requestAmount = oethUnits("30"); + await oethVault.connect(matt).requestWithdrawal(requestAmount); + + const fixtureWithUser = { ...fixture, user: daniel }; + const dataBeforeMint = await snapData(fixtureWithUser); + const strategyBalanceBefore = await weth.balanceOf( + mockStrategy.address + ); + + // WETH in the vault = 60 - 15 = 45 WETH + // unallocated WETH in the Vault = 45 - 23 = 22 WETH + // Add another 8 WETH so the unallocated WETH is 22 + 8 = 30 WETH + await oethVault.connect(strategist).withdrawAllFromStrategies(); + + await assertChangedData( + dataBeforeMint, + { + oethTotalSupply: 0, + oethTotalValue: 0, + vaultCheckBalance: 0, + userOeth: 0, + userWeth: 0, + vaultWeth: strategyBalanceBefore, + queued: 0, + claimable: requestAmount, + claimed: 0, + nextWithdrawalIndex: 0, + }, + fixtureWithUser + ); + + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + + await oethVault.connect(matt).claimWithdrawal(2); + }); + it("Fail to claim a new request after mint with NOT enough liquidity", async () => { + const { oethVault, daniel, matt, weth } = fixture; + + // Matt requests all 30 OETH to be withdrawn which is not enough liquidity + const requestAmount = oethUnits("30"); + await oethVault.connect(matt).requestWithdrawal(requestAmount); + + // WETH in the vault = 60 - 15 = 45 WETH + // unallocated WETH in the Vault = 45 - 23 = 22 WETH + // Add another 6 WETH so the unallocated WETH is 22 + 6 = 28 WETH + await oethVault.connect(daniel).mint(weth.address, oethUnits("6"), 0); + + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + + const tx = oethVault.connect(matt).claimWithdrawal(2); + await expect(tx).to.be.revertedWith("Queue pending liquidity"); + }); + it("Should claim a new request after mint adds enough liquidity", async () => { + const { oethVault, daniel, matt, weth } = fixture; + + // Set the claimable amount to the queued amount + await oethVault.addWithdrawalQueueLiquidity(); + + // Matt requests all 30 OETH to be withdrawn which is currently 8 WETH short + const requestAmount = oethUnits("30"); + await oethVault.connect(matt).requestWithdrawal(requestAmount); + + const fixtureWithUser = { ...fixture, user: daniel }; + const dataBeforeMint = await snapData(fixtureWithUser); + + // WETH in the vault = 60 - 15 = 45 WETH + // unallocated WETH in the Vault = 45 - 23 = 22 WETH + // Add another 8 WETH so the unallocated WETH is 22 + 8 = 30 WETH + const mintAmount = oethUnits("8"); + await oethVault.connect(daniel).mint(weth.address, mintAmount, 0); + + await assertChangedData( + dataBeforeMint, + { + oethTotalSupply: mintAmount, + oethTotalValue: mintAmount, + vaultCheckBalance: mintAmount, + userOeth: mintAmount, + userWeth: mintAmount.mul(-1), + vaultWeth: mintAmount, + queued: 0, + claimable: requestAmount, + claimed: 0, + nextWithdrawalIndex: 0, + }, + fixtureWithUser + ); + + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + + await oethVault.connect(matt).claimWithdrawal(2); + }); + }); + + describe("Fail when", () => { + it("request doesn't have enough OETH", async () => { + const { oethVault, josh } = fixture; + const fixtureWithUser = { ...fixture, user: josh }; + const dataBefore = await snapData(fixtureWithUser); + + const tx = oethVault + .connect(josh) + .requestWithdrawal(dataBefore.userOeth.add(1)); + + await expect(tx).to.revertedWith("Remove exceeds balance"); + }); + it("capital is paused", async () => { + const { oethVault, governor, josh } = fixture; + + await oethVault.connect(governor).pauseCapital(); + + const tx = oethVault + .connect(josh) + .requestWithdrawal(firstRequestAmount); + + await expect(tx).to.be.revertedWith("Capital paused"); + }); + }); + }); + describe("with 1% vault buffer, 30 WETH in the queue, 15 WETH in the vault, 85 WETH in the strategy, 5 WETH already claimed", () => { + let mockStrategy; + beforeEach(async () => { + const { governor, oethVault, weth, daniel, domen, josh, matt } = + fixture; + // Mint 105 OETH to four users + await oethVault + .connect(daniel) + .mint(weth.address, oethUnits("15"), "0"); + await oethVault.connect(josh).mint(weth.address, oethUnits("20"), "0"); + await oethVault.connect(matt).mint(weth.address, oethUnits("30"), "0"); + await oethVault.connect(domen).mint(weth.address, oethUnits("40"), "0"); + await oethVault + .connect(await impersonateAndFund(await oethVault.governor())) + .setMaxSupplyDiff(oethUnits("0.03")); + + // Request and claim 2 + 3 = 5 WETH from Vault + await oethVault.connect(daniel).requestWithdrawal(oethUnits("2")); + await oethVault.connect(josh).requestWithdrawal(oethUnits("3")); + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + await oethVault.connect(daniel).claimWithdrawal(0); + await oethVault.connect(josh).claimWithdrawal(1); + + // Deploy a mock strategy + mockStrategy = await deployWithConfirmation("MockStrategy"); + await oethVault.connect(governor).approveStrategy(mockStrategy.address); + + // Deposit 85 WETH to strategy + await oethVault + .connect(governor) + .depositToStrategy( + mockStrategy.address, + [weth.address], + [oethUnits("85")] + ); + + // Set vault buffer to 1% + await oethVault.connect(governor).setVaultBuffer(oethUnits("0.01")); + + // Have 4 + 12 + 16 = 32 WETH outstanding requests + // So a total supply of 100 - 32 = 68 OETH + await oethVault.connect(daniel).requestWithdrawal(oethUnits("4")); + await oethVault.connect(josh).requestWithdrawal(oethUnits("12")); + await oethVault.connect(matt).requestWithdrawal(oethUnits("16")); + + await oethVault.connect(josh).addWithdrawalQueueLiquidity(); + }); + describe("Fail to claim", () => { + it("a previously claimed withdrawal", async () => { + const { oethVault, daniel } = fixture; + + const tx = oethVault.connect(daniel).claimWithdrawal(0); + + await expect(tx).to.be.revertedWith("Already claimed"); + }); + it("the first withdrawal with wrong withdrawer", async () => { + const { oethVault, matt } = fixture; + + // Advance in time to ensure time delay between request and claim. + await advanceTime(delayPeriod); + + const tx = oethVault.connect(matt).claimWithdrawal(2); + + await expect(tx).to.be.revertedWith("Not requester"); + }); + it("the first withdrawal request in the queue before 30 minutes", async () => { + const { oethVault, daniel } = fixture; + + const tx = oethVault.connect(daniel).claimWithdrawal(2); + + await expect(tx).to.be.revertedWith("Claim delay not met"); + }); + }); + describe("when waited 30 minutes", () => { + beforeEach(async () => { + // Advance in time to ensure time delay between request and claim. + await advanceTime(delayPeriod); + }); + it("Fail to claim the first withdrawal with wrong withdrawer", async () => { + const { oethVault, matt } = fixture; + + const tx = oethVault.connect(matt).claimWithdrawal(2); + + await expect(tx).to.be.revertedWith("Not requester"); + }); + it("Should claim the first withdrawal request in the queue after 30 minutes", async () => { + const { oethVault, daniel } = fixture; + const fixtureWithUser = { ...fixture, user: daniel }; + const dataBefore = await snapData(fixtureWithUser); + + const tx = await oethVault.connect(daniel).claimWithdrawal(2); + + await expect(tx) + .to.emit(oethVault, "WithdrawalClaimed") + .withArgs(daniel.address, 2, oethUnits("4")); + + await assertChangedData( + dataBefore, + { + oethTotalSupply: 0, + oethTotalValue: 0, + vaultCheckBalance: 0, + userOeth: 0, + userWeth: oethUnits("4"), + vaultWeth: oethUnits("4").mul(-1), + queued: 0, + claimable: 0, + claimed: oethUnits("4"), + nextWithdrawalIndex: 0, + }, + fixtureWithUser + ); + }); + it("Fail to claim the second withdrawal request in the queue after 30 minutes", async () => { + const { oethVault, josh } = fixture; + + const tx = oethVault.connect(josh).claimWithdrawal(3); + + await expect(tx).to.be.revertedWith("Queue pending liquidity"); + }); + it("Fail to claim the last (3rd) withdrawal request in the queue", async () => { + const { oethVault, matt } = fixture; + + const tx = oethVault.connect(matt).claimWithdrawal(4); + + await expect(tx).to.be.revertedWith("Queue pending liquidity"); + }); + }); + describe("when mint covers exactly outstanding requests (32 - 15 = 17 OETH)", () => { + beforeEach(async () => { + const { oethVault, daniel, weth } = fixture; + await oethVault + .connect(daniel) + .mint(weth.address, oethUnits("17"), "0"); + + // Advance in time to ensure time delay between request and claim. + await advanceTime(delayPeriod); + }); + it("Should claim the 2nd and 3rd withdrawal requests in the queue", async () => { + const { oethVault, daniel, josh } = fixture; + const fixtureWithUser = { ...fixture, user: daniel }; + const dataBefore = await snapData(fixtureWithUser); + + const tx1 = await oethVault.connect(daniel).claimWithdrawal(2); + + await expect(tx1) + .to.emit(oethVault, "WithdrawalClaimed") + .withArgs(daniel.address, 2, oethUnits("4")); + + const tx2 = await oethVault.connect(josh).claimWithdrawal(3); + + await expect(tx2) + .to.emit(oethVault, "WithdrawalClaimed") + .withArgs(josh.address, 3, oethUnits("12")); + + await assertChangedData( + dataBefore, + { + oethTotalSupply: 0, + oethTotalValue: 0, + vaultCheckBalance: 0, + userOeth: 0, + userWeth: oethUnits("4"), + vaultWeth: oethUnits("16").mul(-1), + queued: 0, + claimable: 0, + claimed: oethUnits("16"), + nextWithdrawalIndex: 0, + }, + fixtureWithUser + ); + }); + it("Fail to deposit 1 WETH to a strategy", async () => { + const { oethVault, weth, governor } = fixture; + + const tx = oethVault + .connect(governor) + .depositToStrategy( + mockStrategy.address, + [weth.address], + [oethUnits("1")] + ); + + await expect(tx).to.be.revertedWith("Not enough WETH available"); + }); + it("Fail to allocate any WETH to the default strategy", async () => { + const { oethVault, domen } = fixture; + + const tx = await oethVault.connect(domen).allocate(); + + await expect(tx).to.not.emit(oethVault, "AssetAllocated"); + }); + }); + describe("when mint covers exactly outstanding requests and vault buffer (17 + 1 WETH)", () => { + beforeEach(async () => { + const { oethVault, daniel, weth } = fixture; + await oethVault + .connect(daniel) + .mint(weth.address, oethUnits("18"), "0"); + }); + it("Should deposit 1 WETH to a strategy which is the vault buffer", async () => { + const { oethVault, weth, governor } = fixture; + + const tx = await oethVault + .connect(governor) + .depositToStrategy( + mockStrategy.address, + [weth.address], + [oethUnits("1")] + ); + + expect(tx) + .to.emit(weth, "Transfer") + .withArgs(oethVault.address, mockStrategy.address, oethUnits("1")); + }); + it("Fail to deposit 1.1 WETH to the default strategy", async () => { + const { oethVault, weth, governor } = fixture; + + const tx = oethVault + .connect(governor) + .depositToStrategy( + mockStrategy.address, + [weth.address], + [oethUnits("1.1")] + ); + + await expect(tx).to.be.revertedWith("Not enough WETH available"); + }); + it("Fail to allocate any WETH to the default strategy", async () => { + const { oethVault, domen } = fixture; + + const tx = await oethVault.connect(domen).allocate(); + + await expect(tx).to.not.emit(oethVault, "AssetAllocated"); + }); + }); + describe("when mint more than covers outstanding requests and vault buffer (17 + 1 + 3 = 21 OETH)", () => { + beforeEach(async () => { + const { oethVault, daniel, weth } = fixture; + await oethVault + .connect(daniel) + .mint(weth.address, oethUnits("21"), "0"); + }); + it("Should deposit 4 WETH to a strategy", async () => { + const { oethVault, weth, governor } = fixture; + + const tx = await oethVault + .connect(governor) + .depositToStrategy( + mockStrategy.address, + [weth.address], + [oethUnits("4")] + ); + + expect(tx) + .to.emit(weth, "Transfer") + .withArgs(oethVault.address, mockStrategy.address, oethUnits("4")); + }); + it("Fail to deposit 5 WETH to the default strategy", async () => { + const { oethVault, weth, governor } = fixture; + + const tx = oethVault + .connect(governor) + .depositToStrategy( + mockStrategy.address, + [weth.address], + [oethUnits("5")] + ); + + await expect(tx).to.be.revertedWith("Not enough WETH available"); + }); + it("Should allocate 3 WETH to the default strategy", async () => { + const { oethVault, governor, domen, weth } = fixture; + + await oethVault + .connect(governor) + .setAssetDefaultStrategy(weth.address, mockStrategy.address); + + const vaultBalance = await weth.balanceOf(oethVault.address); + const stratBalance = await weth.balanceOf(mockStrategy.address); + + const tx = await oethVault.connect(domen).allocate(); + + // total supply is 68 starting + 21 minted = 89 OETH + // Vault buffer is 1% of 89 = 0.89 WETH + // WETH transfer amount = 4 WETH available in vault - 0.89 WETH buffer = 3.11 WETH + await expect(tx) + .to.emit(oethVault, "AssetAllocated") + .withArgs(weth.address, mockStrategy.address, oethUnits("3.11")); + + expect(await weth.balanceOf(oethVault.address)).to.eq( + vaultBalance.sub(oethUnits("3.11")) + ); + + expect(await weth.balanceOf(mockStrategy.address)).to.eq( + stratBalance.add(oethUnits("3.11")) + ); + }); + }); + }); + describe("with 40 WETH in the queue, 10 WETH in the vault, 30 WETH already claimed", () => { + beforeEach(async () => { + const { oethVault, weth, daniel, josh, matt } = fixture; + + // Mint 60 OETH to three users + await oethVault + .connect(daniel) + .mint(weth.address, oethUnits("10"), "0"); + await oethVault.connect(josh).mint(weth.address, oethUnits("20"), "0"); + await oethVault.connect(matt).mint(weth.address, oethUnits("10"), "0"); + + // Request and claim 10 WETH from Vault + await oethVault.connect(daniel).requestWithdrawal(oethUnits("10")); + await oethVault.connect(josh).requestWithdrawal(oethUnits("20")); + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + + // Claim 10 + 20 = 30 WETH from Vault + await oethVault.connect(daniel).claimWithdrawal(0); + await oethVault.connect(josh).claimWithdrawal(1); + }); + it("Should allow the last user to request the remaining 10 WETH", async () => { + const { oethVault, matt } = fixture; + const fixtureWithUser = { ...fixture, user: matt }; + const dataBefore = await snapData(fixtureWithUser); + + const tx = await oethVault + .connect(matt) + .requestWithdrawal(oethUnits("10")); + + await expect(tx) + .to.emit(oethVault, "WithdrawalRequested") + .withArgs(matt.address, 2, oethUnits("10"), oethUnits("40")); + + await assertChangedData( + dataBefore, + { + oethTotalSupply: oethUnits("10").mul(-1), + oethTotalValue: oethUnits("10").mul(-1), + vaultCheckBalance: oethUnits("10").mul(-1), + userOeth: oethUnits("10").mul(-1), + userWeth: 0, + vaultWeth: 0, + queued: oethUnits("10").mul(1), + claimable: 0, + claimed: 0, + nextWithdrawalIndex: 1, + }, + fixtureWithUser + ); + }); + it("Should allow the last user to claim the request of 10 WETH", async () => { + const { oethVault, matt } = fixture; + const fixtureWithUser = { ...fixture, user: matt }; + await oethVault.connect(matt).requestWithdrawal(oethUnits("10")); + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + + const dataBefore = await snapData(fixtureWithUser); + + const tx = await oethVault.connect(matt).claimWithdrawal(2); + + await expect(tx) + .to.emit(oethVault, "WithdrawalClaimed") + .withArgs(matt.address, 2, oethUnits("10")); + + await assertChangedData( + dataBefore, + { + oethTotalSupply: 0, + oethTotalValue: 0, + vaultCheckBalance: 0, + userOeth: 0, + userWeth: oethUnits("10"), + vaultWeth: oethUnits("10").mul(-1), + queued: 0, + claimable: oethUnits("10"), + claimed: oethUnits("10"), + nextWithdrawalIndex: 0, + }, + fixtureWithUser + ); + + expect(await oethVault.totalValue()).to.equal(0); + }); + }); + describe("with 40 WETH in the queue, 100 WETH in the vault, 0 WETH in the strategy", () => { + beforeEach(async () => { + const { oethVault, weth, daniel, josh, matt } = fixture; + // Mint 100 OETH to three users + await oethVault + .connect(daniel) + .mint(weth.address, oethUnits("10"), "0"); + await oethVault.connect(josh).mint(weth.address, oethUnits("20"), "0"); + await oethVault.connect(matt).mint(weth.address, oethUnits("70"), "0"); + + // Request 40 WETH from Vault + await oethVault.connect(matt).requestWithdrawal(oethUnits("40")); + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + }); + it("Should allow user to claim the request of 40 WETH", async () => { + const { oethVault, matt } = fixture; + const fixtureWithUser = { ...fixture, user: matt }; + const dataBefore = await snapData(fixtureWithUser); + + const tx = await oethVault.connect(matt).claimWithdrawal(0); + + await expect(tx) + .to.emit(oethVault, "WithdrawalClaimed") + .withArgs(matt.address, 0, oethUnits("40")); + + await assertChangedData( + dataBefore, + { + oethTotalSupply: 0, + oethTotalValue: 0, + vaultCheckBalance: 0, + userOeth: 0, + userWeth: oethUnits("40"), + vaultWeth: oethUnits("40").mul(-1), + queued: 0, + claimable: oethUnits("40"), + claimed: oethUnits("40"), + nextWithdrawalIndex: 0, + }, + fixtureWithUser + ); + }); + it("Should allow user to perform a new request and claim a smaller than the WETH available", async () => { + const { oethVault, josh } = fixture; + + await oethVault.connect(josh).requestWithdrawal(oethUnits("20")); + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + + const tx = await oethVault.connect(josh).claimWithdrawal(1); + + await expect(tx).to.emit(oethVault, "WithdrawalClaimed"); + }); + it("Should allow user to perform a new request and claim exactly the WETH available", async () => { + const { oethVault, oeth, josh, matt, daniel } = fixture; + await oethVault.connect(matt).claimWithdrawal(0); + // All user give OETH to another user + await oeth.connect(josh).transfer(matt.address, oethUnits("20")); + await oeth.connect(daniel).transfer(matt.address, oethUnits("10")); + + const fixtureWithUser = { ...fixture, user: matt }; + + // Matt request the remaining 60 OETH to be withdrawn + await oethVault.connect(matt).requestWithdrawal(oethUnits("60")); + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + + const dataBefore = await snapData(fixtureWithUser); + + const tx = await oethVault.connect(matt).claimWithdrawal(1); + + await expect(tx) + .to.emit(oethVault, "WithdrawalClaimed") + .withArgs(matt.address, 1, oethUnits("60")); + + await assertChangedData( + dataBefore, + { + oethTotalSupply: 0, + oethTotalValue: 0, + vaultCheckBalance: 0, + userOeth: 0, + userWeth: oethUnits("60"), + vaultWeth: oethUnits("60").mul(-1), + queued: 0, + claimable: oethUnits("60"), + claimed: oethUnits("60"), + nextWithdrawalIndex: 0, + }, + fixtureWithUser + ); + }); + it("Shouldn't allow user to perform a new request and claim more than the WETH available", async () => { + const { oethVault, oeth, weth, josh, matt, daniel } = fixture; + await oethVault.connect(matt).claimWithdrawal(0); + // All user give OETH to another user + await oeth.connect(josh).transfer(matt.address, oethUnits("20")); + await oeth.connect(daniel).transfer(matt.address, oethUnits("10")); + + // Matt request more than the remaining 60 OETH to be withdrawn + await oethVault.connect(matt).requestWithdrawal(oethUnits("60")); + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + await weth + .connect(await impersonateAndFund(oethVault.address)) + .transfer(addresses.dead, oethUnits("50")); // Vault loses 50 WETH + + const tx = oethVault.connect(matt).claimWithdrawal(1); + await expect(tx).to.be.revertedWith("Queue pending liquidity"); + }); + }); + describe("with 40 WETH in the queue, 15 WETH in the vault, 44 WETH in the strategy, vault insolvent by 5% => Slash 1 ether (1/20 = 5%), 19 WETH total value", () => { + beforeEach(async () => { + const { governor, oethVault, weth, daniel, josh, matt, strategist } = + fixture; + // Deploy a mock strategy + const mockStrategy = await deployWithConfirmation("MockStrategy"); + await oethVault.connect(governor).approveStrategy(mockStrategy.address); + await oethVault + .connect(governor) + .setAssetDefaultStrategy(weth.address, mockStrategy.address); + + // Mint 60 OETH to three users + await oethVault + .connect(daniel) + .mint(weth.address, oethUnits("10"), "0"); + await oethVault.connect(josh).mint(weth.address, oethUnits("20"), "0"); + await oethVault.connect(matt).mint(weth.address, oethUnits("30"), "0"); + + // Request and claim 10 + 20 + 10 = 40 WETH from Vault + await oethVault.connect(daniel).requestWithdrawal(oethUnits("10")); + await oethVault.connect(josh).requestWithdrawal(oethUnits("20")); + await oethVault.connect(matt).requestWithdrawal(oethUnits("10")); + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + + // Simulate slash event of 1 ethers + await weth + .connect(await impersonateAndFund(mockStrategy.address)) + .transfer(addresses.dead, oethUnits("1")); + + // Strategist sends 15 WETH to the vault + await oethVault + .connect(strategist) + .withdrawFromStrategy( + mockStrategy.address, + [weth.address], + [oethUnits("15")] + ); + + await oethVault.connect(josh).addWithdrawalQueueLiquidity(); + }); + it("Should allow first user to claim the request of 10 WETH", async () => { + const { oethVault, daniel } = fixture; + const fixtureWithUser = { ...fixture, user: daniel }; + const dataBefore = await snapData(fixtureWithUser); + + const tx = await oethVault.connect(daniel).claimWithdrawal(0); + + expect(tx) + .to.emit(oethVault, "WithdrawalClaimed") + .withArgs(daniel.address, 0, oethUnits("10")); + + await assertChangedData( + dataBefore, + { + oethTotalSupply: 0, + oethTotalValue: 0, + vaultCheckBalance: 0, + userOeth: 0, + userWeth: oethUnits("10"), + vaultWeth: oethUnits("10").mul(-1), + queued: 0, + claimable: 0, + claimed: oethUnits("10"), + nextWithdrawalIndex: 0, + }, + fixtureWithUser + ); + }); + it("Fail to allow second user to claim the request of 20 WETH, due to liquidity", async () => { + const { oethVault, josh } = fixture; + + const tx = oethVault.connect(josh).claimWithdrawal(1); + + await expect(tx).to.be.revertedWith("Queue pending liquidity"); + }); + it("Should allow a user to create a new request with solvency check off", async () => { + // maxSupplyDiff is set to 0 so no insolvency check + const { oethVault, matt } = fixture; + const fixtureWithUser = { ...fixture, user: matt }; + const dataBefore = await snapData(fixtureWithUser); + + const tx = oethVault.connect(matt).requestWithdrawal(oethUnits("10")); + + expect(tx) + .to.emit(oethVault, "WithdrawalRequested") + .withArgs(matt.address, 3, oethUnits("10"), oethUnits("50")); + + await assertChangedData( + dataBefore, + { + oethTotalSupply: oethUnits("10").mul(-1), + oethTotalValue: oethUnits("10").mul(-1), + vaultCheckBalance: oethUnits("10").mul(-1), + userOeth: oethUnits("10").mul(-1), + userWeth: 0, + vaultWeth: 0, + queued: oethUnits("10").mul(1), + claimable: 0, + claimed: 0, + nextWithdrawalIndex: 1, + }, + fixtureWithUser + ); + }); + describe("with solvency check at 3%", () => { + beforeEach(async () => { + const { oethVault } = fixture; + // Turn on insolvency check with 3% buffer + await oethVault + .connect(await impersonateAndFund(await oethVault.governor())) + .setMaxSupplyDiff(oethUnits("0.03")); + }); + it("Fail to allow user to create a new request due to insolvency check", async () => { + const { oethVault, matt } = fixture; + + const tx = oethVault.connect(matt).requestWithdrawal(oethUnits("1")); + + await expect(tx).to.be.revertedWith("Backing supply liquidity error"); + }); + it("Fail to allow first user to claim a withdrawal due to insolvency check", async () => { + const { oethVault, daniel } = fixture; + + await advanceTime(delayPeriod); + + const tx = oethVault.connect(daniel).claimWithdrawal(0); + + await expect(tx).to.be.revertedWith("Backing supply liquidity error"); + }); + }); + describe("with solvency check at 10%", () => { + beforeEach(async () => { + const { oethVault } = fixture; + // Turn on insolvency check with 10% buffer + await oethVault + .connect(await impersonateAndFund(await oethVault.governor())) + .setMaxSupplyDiff(oethUnits("0.1")); + }); + it("Should allow user to create a new request", async () => { + const { oethVault, matt } = fixture; + + const tx = await oethVault + .connect(matt) + .requestWithdrawal(oethUnits("1")); + + expect(tx) + .to.emit(oethVault, "WithdrawalRequested") + .withArgs(matt.address, 3, oethUnits("1"), oethUnits("41")); + }); + it("Should allow first user to claim the request of 10 WETH", async () => { + const { oethVault, daniel } = fixture; + + const tx = await oethVault.connect(daniel).claimWithdrawal(0); + + expect(tx) + .to.emit(oethVault, "WithdrawalClaimed") + .withArgs(daniel.address, 0, oethUnits("10")); + }); + }); + }); + describe("with 99 WETH in the queue, 40 WETH in the vault, total supply 1, 1% insolvency buffer", () => { + let mockStrategy; + beforeEach(async () => { + const { governor, oethVault, weth, daniel, josh, matt, strategist } = + fixture; + // Deploy a mock strategy + mockStrategy = await deployWithConfirmation("MockStrategy"); + await oethVault.connect(governor).approveStrategy(mockStrategy.address); + await oethVault + .connect(governor) + .setAssetDefaultStrategy(weth.address, mockStrategy.address); + + // Mint 100 OETH to three users + await oethVault + .connect(daniel) + .mint(weth.address, oethUnits("20"), "0"); + await oethVault.connect(josh).mint(weth.address, oethUnits("30"), "0"); + await oethVault.connect(matt).mint(weth.address, oethUnits("50"), "0"); + + // Request and claim 20 + 30 + 49 = 99 WETH from Vault + await oethVault.connect(daniel).requestWithdrawal(oethUnits("20")); + await oethVault.connect(josh).requestWithdrawal(oethUnits("30")); + await oethVault.connect(matt).requestWithdrawal(oethUnits("49")); + + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + + // Strategist sends 40 WETH to the vault + await oethVault + .connect(strategist) + .withdrawFromStrategy( + mockStrategy.address, + [weth.address], + [oethUnits("40")] + ); + + await oethVault.connect(josh).addWithdrawalQueueLiquidity(); + + // Turn on insolvency check with 10% buffer + await oethVault + .connect(await impersonateAndFund(await oethVault.governor())) + .setMaxSupplyDiff(oethUnits("0.01")); + }); + describe("with 2 ether slashed leaving 100 - 40 - 2 = 58 WETH in the strategy", () => { + beforeEach(async () => { + const { weth } = fixture; + + // Simulate slash event of 2 ethers + await weth + .connect(await impersonateAndFund(mockStrategy.address)) + .transfer(addresses.dead, oethUnits("2")); + }); + it("Should have total value of zero", async () => { + // 100 from mints - 99 outstanding withdrawals - 2 from slashing = -1 value which is rounder up to zero + expect(await fixture.oethVault.totalValue()).to.equal(0); + }); + it("Fail to allow user to create a new request due to too many outstanding requests", async () => { + const { oethVault, matt } = fixture; + + const tx = oethVault.connect(matt).requestWithdrawal(oethUnits("1")); + + await expect(tx).to.be.revertedWith("Too many outstanding requests"); + }); + it("Fail to allow first user to claim a withdrawal due to too many outstanding requests", async () => { + const { oethVault, daniel } = fixture; + + await advanceTime(delayPeriod); + + const tx = oethVault.connect(daniel).claimWithdrawal(0); + + await expect(tx).to.be.revertedWith("Too many outstanding requests"); + }); + }); + describe("with 1 ether slashed leaving 100 - 40 - 1 = 59 WETH in the strategy", () => { + beforeEach(async () => { + const { weth } = fixture; + + // Simulate slash event of 1 ethers + await weth + .connect(await impersonateAndFund(mockStrategy.address)) + .transfer(addresses.dead, oethUnits("1")); + }); + it("Should have total value of zero", async () => { + // 100 from mints - 99 outstanding withdrawals - 1 from slashing = 0 value + expect(await fixture.oethVault.totalValue()).to.equal(0); + }); + it("Fail to allow user to create a new request due to too many outstanding requests", async () => { + const { oethVault, matt } = fixture; + + const tx = oethVault.connect(matt).requestWithdrawal(oethUnits("1")); + + await expect(tx).to.be.revertedWith("Too many outstanding requests"); + }); + it("Fail to allow first user to claim a withdrawal due to too many outstanding requests", async () => { + const { oethVault, daniel } = fixture; + + await advanceTime(delayPeriod); + + const tx = oethVault.connect(daniel).claimWithdrawal(0); + + await expect(tx).to.be.revertedWith("Too many outstanding requests"); + }); + }); + describe("with 0.02 ether slashed leaving 100 - 40 - 0.02 = 59.98 WETH in the strategy", () => { + beforeEach(async () => { + const { weth } = fixture; + + // Simulate slash event of 0.001 ethers + await weth + .connect(await impersonateAndFund(mockStrategy.address)) + .transfer(addresses.dead, oethUnits("0.02")); + }); + it("Should have total value of zero", async () => { + // 100 from mints - 99 outstanding withdrawals - 0.001 from slashing = 0.999 total value + expect(await fixture.oethVault.totalValue()).to.equal( + oethUnits("0.98") + ); + }); + it("Fail to allow user to create a new 1 WETH request due to too many outstanding requests", async () => { + const { oethVault, matt } = fixture; + + const tx = oethVault.connect(matt).requestWithdrawal(oethUnits("1")); + + await expect(tx).to.be.revertedWith("Too many outstanding requests"); + }); + + it("Fail to allow user to create a new 0.01 WETH request due to insolvency check", async () => { + const { oethVault, matt } = fixture; + + const tx = oethVault + .connect(matt) + .requestWithdrawal(oethUnits("0.01")); + + await expect(tx).to.be.revertedWith("Backing supply liquidity error"); + }); + it("Fail to allow first user to claim a withdrawal due to insolvency check", async () => { + const { oethVault, daniel } = fixture; + + await advanceTime(delayPeriod); + + const tx = oethVault.connect(daniel).claimWithdrawal(0); + + // diff = 1 total supply / 0.98 assets = 1.020408163265306122 which is > 1 maxSupplyDiff + await expect(tx).to.be.revertedWith("Backing supply liquidity error"); + }); + }); + }); }); }); diff --git a/contracts/test/vault/oeth-vault.mainnet.fork-test.js b/contracts/test/vault/oeth-vault.mainnet.fork-test.js index fbae065dab..4b8e6c0099 100644 --- a/contracts/test/vault/oeth-vault.mainnet.fork-test.js +++ b/contracts/test/vault/oeth-vault.mainnet.fork-test.js @@ -3,7 +3,7 @@ const { formatUnits, parseUnits } = require("ethers/lib/utils"); const addresses = require("../../utils/addresses"); const { createFixtureLoader, oethDefaultFixture } = require("../_fixture"); -const { isCI, oethUnits } = require("../helpers"); +const { isCI, oethUnits, advanceTime } = require("../helpers"); const { impersonateAndFund } = require("../../utils/signers"); const { logTxDetails } = require("../../utils/txLogger"); const { @@ -66,6 +66,7 @@ describe("ForkTest: OETH Vault", function () { describe("user operations", () => { let oethWhaleSigner; + const delayPeriod = 10 * 60; // 10 minutes beforeEach(async () => { oethWhaleSigner = await impersonateAndFund(oethWhaleAddress); }); @@ -108,6 +109,33 @@ describe("ForkTest: OETH Vault", function () { .withArgs(josh.address, amount); }); + it("should mint with WETH and allocate to strategy", async () => { + const { oethVault, nativeStakingSSVStrategy, weth, josh, strategist } = + fixture; + + oethVault + .connect(strategist) + .setAssetDefaultStrategy( + weth.address, + nativeStakingSSVStrategy.address + ); + + const amount = parseUnits("11", 18); + const minOeth = parseUnits("8", 18); + + await weth.connect(josh).approve(oethVault.address, amount); + + const tx = await oethVault + .connect(josh) + .mint(weth.address, amount, minOeth); + + await logTxDetails(tx, "mint"); + + await expect(tx) + .to.emit(oethVault, "Mint") + .withArgs(josh.address, amount); + }); + it("should not mint with any other asset", async () => { const { oethVault, frxETH, stETH, reth, josh } = fixture; @@ -175,6 +203,50 @@ describe("ForkTest: OETH Vault", function () { const tx = oethVault.connect(oethWhaleSigner).redeem(oethWhaleBalance, 0); await expect(tx).to.revertedWith("Liquidity error"); }); + it("should request a withdraw by OETH whale", async () => { + const { oeth, oethVault } = fixture; + + const oethWhaleBalance = await oeth.balanceOf(oethWhaleAddress); + expect(oethWhaleBalance, "no longer an OETH whale").to.gt( + parseUnits("100", 18) + ); + + const tx = await oethVault + .connect(oethWhaleSigner) + .requestWithdrawal(oethWhaleBalance); + + await expect(tx) + .to.emit(oethVault, "WithdrawalRequested") + .withNamedArgs({ + _withdrawer: await oethWhaleSigner.getAddress(), + _amount: oethWhaleBalance, + }); + }); + it("should claim withdraw by a OETH whale", async () => { + const { oeth, oethVault } = fixture; + + let oethWhaleBalance = await oeth.balanceOf(oethWhaleAddress); + + expect(oethWhaleBalance, "no longer an OETH whale").to.gt( + parseUnits("100", 18) + ); + + oethWhaleBalance = oethUnits("50"); + + // First Request withdrawal + await oethVault + .connect(oethWhaleSigner) + .requestWithdrawal(oethWhaleBalance); + + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + + // Then Claim withdrawal + const tx = await oethVault.connect(oethWhaleSigner).claimWithdrawal(0); + + await expect(tx) + .to.emit(oethVault, "WithdrawalClaimed") + .withArgs(oethWhaleAddress, 0, oethWhaleBalance); + }); it("OETH whale can redeem after withdraw from all strategies", async () => { const { oeth, oethVault, timelock } = fixture; diff --git a/contracts/test/vault/oneinch-swapper.js b/contracts/test/vault/oneinch-swapper.js index 8855aa8966..60842e35ce 100644 --- a/contracts/test/vault/oneinch-swapper.js +++ b/contracts/test/vault/oneinch-swapper.js @@ -130,12 +130,12 @@ describe("1Inch Swapper", () => { }); it("Should allow to swap tokens", async () => { - const { weth, reth, stETH, frxETH, oethVault, strategist } = fixture; + const { weth, reth, stETH, oethVault, strategist } = fixture; const fromAmount = utils.parseEther("20"); - for (const fromAsset of [weth]) { - for (const toAsset of [reth, stETH, frxETH]) { + for (const fromAsset of [reth, stETH]) { + for (const toAsset of [weth]) { const toAmount = utils.parseEther("24"); log( `swapping 20 ${await fromAsset.symbol()} to ${await toAsset.symbol()}` @@ -173,7 +173,7 @@ describe("1Inch Swapper", () => { // Call swap method const tx = oethVault .connect(strategist) - .swapCollateral(weth.address, stETH.address, fromAmount, toAmount, []); + .swapCollateral(stETH.address, weth.address, fromAmount, toAmount, []); await expect(tx).to.be.revertedWith("Strategist slippage limit"); }); @@ -187,12 +187,12 @@ describe("1Inch Swapper", () => { // Call swap method const tx = oethVault .connect(strategist) - .swapCollateral(weth.address, stETH.address, fromAmount, toAmount, []); + .swapCollateral(stETH.address, weth.address, fromAmount, toAmount, []); await expect(tx).to.be.revertedWith("Oracle slippage limit exceeded"); }); - it("Should revert swap if value is under supply", async () => { + it.skip("Should revert swap if value is under supply", async () => { const { weth, stETH, @@ -220,7 +220,7 @@ describe("1Inch Swapper", () => { // Call swap method const tx = oethVault .connect(strategist) - .swapCollateral(weth.address, stETH.address, fromAmount, toAmount, []); + .swapCollateral(stETH.address, weth.address, fromAmount, toAmount, []); await expect(tx).to.be.revertedWith("Allowed value < supply"); @@ -255,7 +255,7 @@ describe("1Inch Swapper", () => { // Call swap method const tx = await oethVault .connect(strategist) - .swapCollateral(weth.address, stETH.address, fromAmount, toAmount, []); + .swapCollateral(stETH.address, weth.address, fromAmount, toAmount, []); await expect(tx).to.emit(oethVault, "Swapped"); @@ -277,16 +277,16 @@ describe("1Inch Swapper", () => { }); it("Should revert if toAsset is not supported", async () => { - const { weth, dai, oethVault, strategist } = fixture; + const { stETH, dai, oethVault, strategist } = fixture; const fromAmount = utils.parseEther("100"); const toAmount = utils.parseEther("100"); // Call swap method const tx = oethVault .connect(strategist) - .swapCollateral(weth.address, dai.address, fromAmount, toAmount, []); + .swapCollateral(stETH.address, dai.address, fromAmount, toAmount, []); - await expect(tx).to.be.revertedWith("To asset is not supported"); + await expect(tx).to.be.revertedWith("Only swap to WETH"); }); it("Should swap if capital is paused", async () => { @@ -303,7 +303,7 @@ describe("1Inch Swapper", () => { // Call swap method const tx = await oethVault .connect(strategist) - .swapCollateral(weth.address, stETH.address, fromAmount, toAmount, []); + .swapCollateral(stETH.address, weth.address, fromAmount, toAmount, []); expect(tx).to.emit(oethVault, "Swapped"); }); @@ -316,7 +316,7 @@ describe("1Inch Swapper", () => { // Call swap method const tx = oethVault .connect(josh) - .swapCollateral(weth.address, stETH.address, fromAmount, toAmount, []); + .swapCollateral(stETH.address, weth.address, fromAmount, toAmount, []); await expect(tx).to.be.revertedWith( "Caller is not the Strategist or Governor" diff --git a/contracts/utils/deploy.js b/contracts/utils/deploy.js index 4609e79b44..b4c27ce09f 100644 --- a/contracts/utils/deploy.js +++ b/contracts/utils/deploy.js @@ -122,6 +122,12 @@ const withConfirmation = async ( logContractAbi = false ) => { const result = await deployOrTransactionPromise; + + if (process.env.PROVIDER_URL?.includes("rpc.tenderly.co")) { + // Skip on Tenderly + return result; + } + const receipt = await hre.ethers.provider.waitForTransaction( result.receipt ? result.receipt.transactionHash : result.hash, NUM_CONFIRMATIONS