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 343ccf51a7..264bc8b46a 100644
--- a/contracts/contracts/interfaces/IVault.sol
+++ b/contracts/contracts/interfaces/IVault.sol
@@ -36,6 +36,19 @@ interface IVault {
);
event StrategyAddedToMintWhitelist(address indexed strategy);
event StrategyRemovedFromMintWhitelist(address indexed strategy);
+ 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;
@@ -205,6 +218,8 @@ interface IVault {
function netOusdMintedForStrategy() external view returns (int256);
+ function setDripper(address _dripper) external;
+
function weth() external view returns (address);
function cacheWETHAssetIndex() external;
@@ -225,4 +240,29 @@ interface IVault {
external
view
returns (bool);
+
+ // 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..009a7eec5c 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,93 @@ 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 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;
+ }
+ function _swapCollateral(
+ address,
+ address,
+ uint256,
+ uint256,
+ bytes calldata
+ ) internal pure override returns (uint256) {
+ revert("Collateral swap not supported");
+ }
}
diff --git a/contracts/contracts/vault/OETHVaultCore.sol b/contracts/contracts/vault/OETHVaultCore.sol
index 01cb3e1c9e..c437f619f5 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,349 @@ 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)
+ {
+ balance = super._checkBalance(_asset);
+
+ if (_asset == weth) {
+ WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;
+ // Need to remove WETH that is reserved for the withdrawal queue
+ if (balance + queue.claimed >= queue.queued) {
+ return balance + queue.claimed - queue.queued;
+ }
+ }
+ }
+
+ /**
+ * @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 cd15bb2aec..90f4cca26e 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();
}
@@ -221,6 +226,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);
@@ -281,14 +291,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;
@@ -416,7 +426,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 0f0a4045e7..1ec28f040e 100644
--- a/contracts/contracts/vault/VaultStorage.sol
+++ b/contracts/contracts/vault/VaultStorage.sol
@@ -53,8 +53,21 @@ contract VaultStorage is Initializable, Governable {
uint256 _fromAssetAmount,
uint256 _toAssetAmount
);
+ event DripperChanged(address indexed _dripper);
event StrategyAddedToMintWhitelist(address indexed strategy);
event StrategyRemovedFromMintWhitelist(address indexed strategy);
+ 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 {
@@ -181,8 +194,50 @@ contract VaultStorage is Initializable, Governable {
// slither-disable-next-line uninitialized-state
mapping(address => bool) public isMintWhitelistedStrategy;
+ /// @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[49] private __gap;
+ uint256[45] 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/holesky/017_upgrade_vault.js b/contracts/deploy/holesky/017_upgrade_vault.js
new file mode 100644
index 0000000000..a53c9f0b85
--- /dev/null
+++ b/contracts/deploy/holesky/017_upgrade_vault.js
@@ -0,0 +1,72 @@
+const { parseEther } = require("ethers/lib/utils");
+
+const {
+ deployWithConfirmation,
+ withConfirmation,
+} = require("../../utils/deploy");
+const { getAssetAddresses } = require("../../test/helpers.js");
+const { resolveContract } = require("../../utils/resolvers");
+
+const mainExport = async () => {
+ console.log("Running 017 deployment on Holesky...");
+
+ const { deployerAddr } = await getNamedAccounts();
+ const sDeployer = await ethers.provider.getSigner(deployerAddr);
+
+ const assetAddresses = await getAssetAddresses();
+
+ const cVaultProxy = await resolveContract("OETHVaultProxy");
+ const cVault = await resolveContract("OETHVaultProxy", "IVault");
+ const cDripper = await resolveContract("OETHDripperProxy", "OETHDripper");
+ const strategyProxy = await resolveContract("NativeStakingSSVStrategyProxy");
+
+ const dOETHVaultCore = await deployWithConfirmation("OETHVaultCore", [
+ assetAddresses.WETH,
+ ]);
+ console.log(`Deployed OETHVaultCore to ${dOETHVaultCore.address}`);
+
+ const dOETHVaultAdmin = await deployWithConfirmation("OETHVaultAdmin", [
+ assetAddresses.WETH,
+ ]);
+ console.log(`Deployed OETHVaultAdmin to ${dOETHVaultAdmin.address}`);
+
+ await withConfirmation(
+ cVaultProxy.connect(sDeployer).upgradeTo(dOETHVaultCore.address)
+ );
+ console.log(`Upgraded OETHVaultCore to ${dOETHVaultCore.address}`);
+
+ await withConfirmation(
+ cVault.connect(sDeployer).setAdminImpl(dOETHVaultAdmin.address)
+ );
+ console.log(`Set OETHVaultAdmin to ${dOETHVaultAdmin.address}`);
+
+ await withConfirmation(
+ cVault.connect(sDeployer).setDripper(cDripper.address)
+ );
+ console.log(`Set Dripper to ${cDripper.address}`);
+
+ await withConfirmation(
+ cVault
+ .connect(sDeployer)
+ .setAssetDefaultStrategy(assetAddresses.WETH, strategyProxy.address)
+ );
+ console.log(`Set WETH default strategy to ${strategyProxy.address}`);
+
+ await withConfirmation(
+ cVault.connect(sDeployer).setVaultBuffer(parseEther("0.05"))
+ );
+ console.log(`Set vault buffer to 5%`);
+
+ await withConfirmation(cVault.connect(sDeployer).allocate());
+ console.log(`Allocated assets to strategy`);
+
+ console.log("Running 017 deployment done");
+ return true;
+};
+
+mainExport.id = "017_upgrade_vault";
+mainExport.tags = [];
+mainExport.dependencies = [];
+mainExport.skip = () => false;
+
+module.exports = mainExport;
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..cc982585e8 100644
--- a/contracts/deployments/holesky/.migrations.json
+++ b/contracts/deployments/holesky/.migrations.json
@@ -13,5 +13,7 @@
"012_upgrade_strategy": 1717477122,
"013_upgrade_strategy": 1717803989,
"014_upgrade_strategy": 1717806940,
- "015_upgrade_strategy": 1721109545
+ "015_oeth_withdrawal_queue": 1720063996,
+ "016_upgrade_strategy": 1721109545,
+ "017_upgrade_vault": 1722405783
}
\ No newline at end of file
diff --git a/contracts/deployments/holesky/OETHVaultAdmin.json b/contracts/deployments/holesky/OETHVaultAdmin.json
index c58d7d080f..c0e67e313b 100644
--- a/contracts/deployments/holesky/OETHVaultAdmin.json
+++ b/contracts/deployments/holesky/OETHVaultAdmin.json
@@ -1,6 +1,17 @@
{
- "address": "0xa94c4aab0Cf9f6E79bB064DB145fBe2506b9Fa75",
+ "address": "0xdF96E53406F6E6873B20E996d7fcB8e1f61ecc5c",
"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": [
@@ -262,6 +299,19 @@
"name": "StrategistUpdated",
"type": "event"
},
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "strategy",
+ "type": "address"
+ }
+ ],
+ "name": "StrategyAddedToMintWhitelist",
+ "type": "event"
+ },
{
"anonymous": false,
"inputs": [
@@ -288,6 +338,19 @@
"name": "StrategyRemoved",
"type": "event"
},
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "strategy",
+ "type": "address"
+ }
+ ],
+ "name": "StrategyRemovedFromMintWhitelist",
+ "type": "event"
+ },
{
"anonymous": false,
"inputs": [
@@ -403,6 +466,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 +680,19 @@
"stateMutability": "nonpayable",
"type": "function"
},
+ {
+ "inputs": [],
+ "name": "dripper",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
{
"inputs": [],
"name": "governor",
@@ -568,6 +719,25 @@
"stateMutability": "view",
"type": "function"
},
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "name": "isMintWhitelistedStrategy",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
{
"inputs": [],
"name": "maxSupplyDiff",
@@ -686,6 +856,19 @@
"stateMutability": "view",
"type": "function"
},
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "_asset",
+ "type": "address"
+ }
+ ],
+ "name": "removeAsset",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
{
"inputs": [
{
@@ -743,6 +926,19 @@
"stateMutability": "nonpayable",
"type": "function"
},
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "_dripper",
+ "type": "address"
+ }
+ ],
+ "name": "setDripper",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
{
"inputs": [
{
@@ -1084,6 +1280,19 @@
"stateMutability": "view",
"type": "function"
},
+ {
+ "inputs": [],
+ "name": "weth",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
{
"inputs": [],
"name": "withdrawAllFromStrategies",
@@ -1126,45 +1335,114 @@
"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": "uint40",
+ "name": "timestamp",
+ "type": "uint40"
+ },
+ {
+ "internalType": "uint128",
+ "name": "amount",
+ "type": "uint128"
+ },
+ {
+ "internalType": "uint128",
+ "name": "queued",
+ "type": "uint128"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
}
],
- "transactionHash": "0xe29b0302a257a781d787f590e9502246b3ac3fe2f2d3c39d37d3ac9e856057eb",
+ "transactionHash": "0xc05416d8c28c0456be94ef961c09612998760be1bbb9619cafe6f3b9ddc6a528",
"receipt": {
"to": null,
"from": "0x1b94CA50D3Ad9f8368851F8526132272d1a5028C",
- "contractAddress": "0xa94c4aab0Cf9f6E79bB064DB145fBe2506b9Fa75",
- "transactionIndex": 39,
- "gasUsed": "3146556",
- "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000040000010000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000004000000000000002000000000000000000040000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000010000000000010000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000",
- "blockHash": "0x50619ec9fad9061d57a94456471009c7fa5c0cf4d68201956bf36a07a219f708",
- "transactionHash": "0xe29b0302a257a781d787f590e9502246b3ac3fe2f2d3c39d37d3ac9e856057eb",
+ "contractAddress": "0xdF96E53406F6E6873B20E996d7fcB8e1f61ecc5c",
+ "transactionIndex": 10,
+ "gasUsed": "3059471",
+ "logsBloom": "0x00000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000020000000000000000000800000000000000000000000000000000000404000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000010000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000",
+ "blockHash": "0x19b0b2c5d75856f3d8c671ac5c3c4b15ba099335ae754cf739109c97f987496a",
+ "transactionHash": "0xc05416d8c28c0456be94ef961c09612998760be1bbb9619cafe6f3b9ddc6a528",
"logs": [
{
- "transactionIndex": 39,
- "blockNumber": 1405067,
- "transactionHash": "0xe29b0302a257a781d787f590e9502246b3ac3fe2f2d3c39d37d3ac9e856057eb",
- "address": "0xa94c4aab0Cf9f6E79bB064DB145fBe2506b9Fa75",
+ "transactionIndex": 10,
+ "blockNumber": 2037165,
+ "transactionHash": "0xc05416d8c28c0456be94ef961c09612998760be1bbb9619cafe6f3b9ddc6a528",
+ "address": "0xdF96E53406F6E6873B20E996d7fcB8e1f61ecc5c",
"topics": [
"0xc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a",
"0x0000000000000000000000000000000000000000000000000000000000000000",
"0x0000000000000000000000001b94ca50d3ad9f8368851f8526132272d1a5028c"
],
"data": "0x",
- "logIndex": 121,
- "blockHash": "0x50619ec9fad9061d57a94456471009c7fa5c0cf4d68201956bf36a07a219f708"
+ "logIndex": 9,
+ "blockHash": "0x19b0b2c5d75856f3d8c671ac5c3c4b15ba099335ae754cf739109c97f987496a"
}
],
- "blockNumber": 1405067,
- "cumulativeGasUsed": "6442389",
+ "blockNumber": 2037165,
+ "cumulativeGasUsed": "4607398",
"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": 3,
+ "solcInputHash": "0d24aafc2e05d7bcc2007c274421d881",
+ "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\":true,\"internalType\":\"address\",\"name\":\"strategy\",\"type\":\"address\"}],\"name\":\"StrategyAddedToMintWhitelist\",\"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\":true,\"internalType\":\"address\",\"name\":\"strategy\",\"type\":\"address\"}],\"name\":\"StrategyRemovedFromMintWhitelist\",\"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\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"isMintWhitelistedStrategy\",\"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\":\"uint40\",\"name\":\"timestamp\",\"type\":\"uint40\"},{\"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.\"},\"withdrawalQueueMetadata()\":{\"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\"},\"withdrawalRequests(uint256)\":{\"notice\":\"Mapping of withdrawal request indices to the user withdrawal request data\"}},\"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\":\"// SPDX-License-Identifier: MIT\\npragma 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\":\"0x56a463cf0d5f2bb4bd629e23522b0c353df4c3d4fb95424828d25fb074faf365\",\"license\":\"MIT\"},\"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 StrategyAddedToMintWhitelist(address indexed strategy);\\n event StrategyRemovedFromMintWhitelist(address indexed strategy);\\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 mintToForStrategy(address receiver, uint256 _amount) external;\\n\\n function redeem(uint256 _amount, uint256 _minimumUnitAmount) external;\\n\\n function burnForStrategy(uint256 _amount) external;\\n\\n function burnFromForStrategy(address user, 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 function addStrategyToMintWhitelist(address strategyAddr) external;\\n\\n function removeStrategyFromMintWhitelist(address strategyAddr) external;\\n\\n function isMintWhitelistedStrategy(address strategyAddr)\\n external\\n view\\n returns (bool);\\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\":\"0xc0824c024eaa3ec7c9b0508848d2dd60e13250b812a39c5ee2a795fdb1817b65\",\"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 /// @dev Calculates the amount of WETH in the Vault that is not reserved for the withdrawal queue.\\n function _wethAvailable() internal view returns (uint256 wethAvailable) {\\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\\n\\n // The amount of WETH that is still to be claimed in the withdrawal queue\\n uint256 outstandingWithdrawals = queue.queued - queue.claimed;\\n\\n // The amount of sitting in WETH in the vault\\n uint256 wethBalance = IERC20(weth).balanceOf(address(this));\\n\\n // If there is more WETH in the vault than the outstanding withdrawals\\n if (wethBalance > outstandingWithdrawals) {\\n wethAvailable = wethBalance - outstandingWithdrawals;\\n }\\n }\\n\\n function _swapCollateral(\\n address,\\n address,\\n uint256,\\n uint256,\\n bytes calldata\\n ) internal pure override returns (uint256) {\\n revert(\\\"Collateral swap not supported\\\");\\n }\\n}\\n\",\"keccak256\":\"0x9aa3cabf1974b682c28a5a34bf3986bbcf4715e2e1298efc6a61a28cb10ffc10\",\"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 StrategyAddedToMintWhitelist(address indexed strategy);\\n event StrategyRemovedFromMintWhitelist(address indexed strategy);\\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 // slither-disable-next-line uninitialized-state\\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\\n // slither-disable-start constable-states\\n // slither-disable-next-line uninitialized-state\\n address public ousdMetaStrategy;\\n\\n /// @notice How much OTokens are currently minted by the strategy\\n // slither-disable-next-line uninitialized-state\\n int256 public netOusdMintedForStrategy;\\n\\n /// @notice How much net total OTokens are allowed to be minted by all strategies\\n // slither-disable-next-line uninitialized-state\\n uint256 public netOusdMintForStrategyThreshold;\\n\\n // slither-disable-end constable-states\\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 // List of strategies that can mint oTokens directly\\n // Used in OETHBaseVaultCore\\n // slither-disable-next-line uninitialized-state\\n mapping(address => bool) public isMintWhitelistedStrategy;\\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 including 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 /// @notice Global metadata for the withdrawal queue including:\\n /// queued - cumulative total of all withdrawal requests included the ones that have already been claimed\\n /// claimable - cumulative total of all the requests that can be claimed including the ones already claimed\\n /// claimed - total of all the requests that have been claimed\\n /// nextWithdrawalIndex - index of the next withdrawal request starting at 0\\n // slither-disable-next-line uninitialized-state\\n WithdrawalQueueMetadata public withdrawalQueueMetadata;\\n\\n struct WithdrawalRequest {\\n address withdrawer;\\n bool claimed;\\n uint40 timestamp; // timestamp of the withdrawal request\\n // Amount of oTokens to redeem. eg OETH\\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 /// @notice Mapping of withdrawal request indices to the user withdrawal request data\\n mapping(uint256 => WithdrawalRequest) public withdrawalRequests;\\n\\n // For future use\\n uint256[45] 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\":\"0x7f33ab25581ef4eabd8c2e3bc7dd88ff397acb95c59c7eaf1352173d8f651d6e\",\"license\":\"MIT\"}},\"version\":1}",
+ "bytecode": "0x6037805461ffff60a01b1916600160a81b179055603d80546001600160a01b0319908116909155603e805482169055603f8054909116905560e0604052600060a081905260c052604880546001600160b01b03191690553480156200006357600080fd5b50604051620036cc380380620036cc8339810160408190526200008691620000fc565b6200009e33600080516020620036ac83398151915255565b600080516020620036ac833981519152546040516001600160a01b03909116906000907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a360601b6001600160601b0319166080526200012e565b6000602082840312156200010f57600080fd5b81516001600160a01b03811681146200012757600080fd5b9392505050565b60805160601c61354a620001626000396000818161051301528181612745015281816128750152612bda015261354a6000f3fe608060405234801561001057600080fd5b506004361061038e5760003560e01c8063636e6c40116101de578063ae69f3cb1161010f578063c9919112116100ad578063e6cc54321161007c578063e6cc543214610844578063e829cc1614610858578063eb03654b1461086b578063fc0cfeee1461087e57600080fd5b8063c99191121461080d578063d38bfff414610815578063d58e3b3a14610828578063e45cc9f01461083b57600080fd5b8063b890ebf6116100e9578063b890ebf6146107d7578063bc90106b146107ea578063c5f00841146107fd578063c7af33521461080557600080fd5b8063ae69f3cb1461079e578063b2c9336d146107b1578063b888879e146107c457600080fd5b80638e510b521161017c57806394828ffd1161015657806394828ffd146107515780639c82f2a4146107595780639fa1826e1461076c578063a403e4d51461077557600080fd5b80638e510b521461068d5780638ec489a214610696578063937b2581146106a957600080fd5b8063773540b3116101b8578063773540b31461064b5780637a2202f31461065e5780637b9a709614610667578063840c4c7a1461067a57600080fd5b8063636e6c4014610612578063663e64ce146106255780636c7561e81461063857600080fd5b8063372aa224116102c35780634bed3bc011610261578063570d8e1d11610230578063570d8e1d146105d1578063597c8910146105e45780635d36b190146105f7578063603ea03b146105ff57600080fd5b80634bed3bc01461058e57806350ba711c146105a157806352d38e5d146105b457806353ca9f24146105bd57600080fd5b80633fc8cef31161029d5780633fc8cef31461050e5780634530820a1461053557806349c1d54d146105685780634a5e42b11461057b57600080fd5b8063372aa224146104e05780633b8ae397146104f35780633dbc911f1461050657600080fd5b80631edfe3da116103305780632da845a81161030a5780632da845a8146104485780632e9958ab1461045b578063362bd1a31461046e57806336b6d944146104cd57600080fd5b80631edfe3da14610425578063207134b01461042e5780632b3297f91461043757600080fd5b80630c340a241161036c5780630c340a24146103cc5780631072cbea146103ec578063175188e8146103ff57806318ce56bd1461041257600080fd5b806309f49bf51461039357806309f6442c1461039d5780630acbda75146103b9575b600080fd5b61039b610891565b005b6103a660385481565b6040519081526020015b60405180910390f35b61039b6103c73660046132c2565b61090a565b6103d46109bc565b6040516001600160a01b0390911681526020016103b0565b61039b6103fa366004613224565b6109d9565b61039b61040d366004613085565b610a86565b6045546103d4906001600160a01b031681565b6103a660395481565b6103a660435481565b6048546001600160a01b03166103d4565b61039b610456366004613085565b610d87565b61039b610469366004613085565b610df9565b604b54604c5461049a916001600160801b0380821692600160801b928390048216928183169291041684565b604080516001600160801b03958616815293851660208501529184169183019190915290911660608201526080016103b0565b61039b6104db366004613085565b610e67565b61039b6104ee366004613085565b610e97565b61039b610501366004613085565b610f09565b61039b611046565b6103d47f000000000000000000000000000000000000000000000000000000000000000081565b610558610543366004613085565b60496020526000908152604090205460ff1681565b60405190151581526020016103b0565b6042546103d4906001600160a01b031681565b61039b610589366004613085565b6110bc565b604854600160a01b900461ffff166103a6565b6103a66105af3660046130d3565b6113c9565b6103a6603b5481565b60375461055890600160a01b900460ff1681565b603f546103d4906001600160a01b031681565b61039b6105f2366004613085565b61146c565b61039b6114ad565b604a546103d4906001600160a01b031681565b61039b6106203660046132c2565b611553565b61039b6106333660046132c2565b6115b1565b61039b61064636600461324e565b61160a565b61039b610659366004613085565b611888565b6103a660475481565b61039b6106753660046131fa565b6118fa565b61039b610688366004613179565b611a30565b6103a660415481565b61039b6106a43660046132c2565b611ac9565b61070a6106b73660046132c2565b604d60205260009081526040902080546001909101546001600160a01b03821691600160a01b810460ff1691600160a81b90910464ffffffffff16906001600160801b0380821691600160801b90041685565b604080516001600160a01b039096168652931515602086015264ffffffffff909216928401929092526001600160801b03918216606084015216608082015260a0016103b0565b61039b611b7e565b61039b610767366004613085565b611bee565b6103a6603a5481565b6103d4610783366004613085565b6040602081905260009182529020546001600160a01b031681565b61039b6107ac366004613179565b611c60565b61039b6107bf3660046132c2565b611cee565b6037546103d4906001600160a01b031681565b61039b6107e53660046132c2565b611d47565b61039b6107f83660046130a0565b611da0565b61039b611fe2565b610558612058565b61039b612089565b61039b610823366004613085565b6120c9565b61039b610836366004613085565b61216d565b6103a660465481565b60375461055890600160a81b900460ff1681565b61039b6108663660046132a7565b6121df565b61039b6108793660046132c2565b61229f565b61039b61088c366004613085565b612354565b603f546001600160a01b03163314806108ad57506108ad612058565b6108d25760405162461bcd60e51b81526004016108c990613397565b60405180910390fd5b6037805460ff60a01b191690556040517fbc044409505c95b6b851433df96e1beae715c909d8e7c1d6d7ab783300d4e3b990600090a1565b610912612058565b61092e5760405162461bcd60e51b81526004016108c990613360565b6113888111156109805760405162461bcd60e51b815260206004820152601760248201527f62617369732063616e6e6f74206578636565642035302500000000000000000060448201526064016108c9565b60438190556040518181527f56287a45051933ea374811b3d5d165033047be5572cac676f7c28b8be4f746c7906020015b60405180910390a150565b60006109d46000805160206134f58339815191525490565b905090565b6109e1612058565b6109fd5760405162461bcd60e51b81526004016108c990613360565b6001600160a01b03821660009081526033602052604090205460ff1615610a665760405162461bcd60e51b815260206004820152601760248201527f4f6e6c7920756e737570706f727465642061737365747300000000000000000060448201526064016108c9565b610a82610a716109bc565b6001600160a01b03841690836123f6565b5050565b610a8e612058565b610aaa5760405162461bcd60e51b81526004016108c990613360565b6001600160a01b03811660009081526035602052604090205460ff16610b0a5760405162461bcd60e51b815260206004820152601560248201527414dd1c985d1959de481b9bdd08185c1c1c9bdd9959605a1b60448201526064016108c9565b60345460005b81811015610bc257826001600160a01b03166040600060348481548110610b3957610b396134cf565b60009182526020808320909101546001600160a01b039081168452908301939093526040909101902054161415610bb25760405162461bcd60e51b815260206004820181905260248201527f53747261746567792069732064656661756c7420666f7220616e20617373657460448201526064016108c9565b610bbb81613472565b9050610b10565b506036548060005b82811015610c2257846001600160a01b031660368281548110610bef57610bef6134cf565b6000918252602090912001546001600160a01b03161415610c1257809150610c22565b610c1b81613472565b9050610bca565b5081811015610d81576036610c3860018461342f565b81548110610c4857610c486134cf565b600091825260209091200154603680546001600160a01b039092169183908110610c7457610c746134cf565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506036805480610cb357610cb36134b9565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b03861680835260359091526040808320805460ff19169055805163429c145b60e11b81529051879363853828b6926004808201939182900301818387803b158015610d2a57600080fd5b505af1158015610d3e573d6000803e3d6000fd5b50506040516001600160a01b03881681527f09a1db4b80c32706328728508c941a6b954f31eb5affd32f236c1fd405f8fea49250602001905060405180910390a1505b50505050565b610d8f612058565b610dab5760405162461bcd60e51b81526004016108c990613360565b604280546001600160a01b0319166001600160a01b0383169081179091556040519081527f1e4af5ac389e8cde1bdaa6830881b6c987c62a45cfb3b33d27d805cde3b57750906020016109b1565b610e01612058565b610e1d5760405162461bcd60e51b81526004016108c990613360565b604a80546001600160a01b0319166001600160a01b0383169081179091556040517faf2910d9759321733de15af1827a49830692912adeb2b3646334861f2cd2eed490600090a250565b610e6f612058565b610e8b5760405162461bcd60e51b81526004016108c990613360565b610e948161244d565b50565b610e9f612058565b610ebb5760405162461bcd60e51b81526004016108c990613360565b603780546001600160a01b0319166001600160a01b0383169081179091556040519081527fb266add5f3044b17d27db796af992cecbe413921b4e8aaaee03c719e16b9806a906020016109b1565b610f11612058565b610f2d5760405162461bcd60e51b81526004016108c990613360565b6001600160a01b03811660009081526035602052604090205460ff1615610f965760405162461bcd60e51b815260206004820152601960248201527f537472617465677920616c726561647920617070726f7665640000000000000060448201526064016108c9565b6040805180820182526001808252600060208084018281526001600160a01b038716808452603583528684209551865460ff19169015151786559051948401949094556036805493840181559091527f4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b890910180546001600160a01b0319168317905591519081527f960dd94cbb79169f09a4e445d58b895df2d9bffa5b31055d0932d801724a20d191016109b1565b603f546001600160a01b03163314806110625750611062612058565b61107e5760405162461bcd60e51b81526004016108c990613397565b6037805460ff60a81b1916600160a81b1790556040517f71f0e5b62f846a22e0b4d159e516e62fa9c2b8eb570be15f83e67d98a2ee51e090600090a1565b6110c4612058565b6110e05760405162461bcd60e51b81526004016108c990613360565b6001600160a01b03811660009081526033602052604090205460ff1661113e5760405162461bcd60e51b8152602060048201526013602482015272105cdcd95d081b9bdd081cdd5c1c1bdc9d1959606a1b60448201526064016108c9565b604051632fa8a91360e11b81526001600160a01b03821660048201526509184e72a000903090635f5152269060240160206040518083038186803b15801561118557600080fd5b505afa158015611199573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111bd91906132db565b111561120b5760405162461bcd60e51b815260206004820152601760248201527f5661756c74207374696c6c20686f6c647320617373657400000000000000000060448201526064016108c9565b6034548060005b8281101561126a57836001600160a01b031660348281548110611237576112376134cf565b6000918252602090912001546001600160a01b0316141561125a5780915061126a565b61126381613472565b9050611212565b50603461127860018461342f565b81548110611288576112886134cf565b600091825260209091200154603480546001600160a01b0390921691839081106112b4576112b46134cf565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060348054806112f3576112f36134b9565b60008281526020808220600019908401810180546001600160a01b031990811690915593019093556001600160a01b038616808252604080855280832080549094169093558251908152928301527fba58ce12801c949fa65f41c46ed108671c219baf945fa48d21026cea99ff252a910160405180910390a16001600160a01b038316600081815260336020908152604091829020805464ffffffffff1916905590519182527f37803e2125c48ee96c38ddf04e826daf335b0e1603579040fd275aba6d06b6fc910160405180910390a1505050565b7f53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac453580546000919060028114156114115760405162461bcd60e51b81526004016108c9906133df565b60028255603f546001600160a01b03163314806114315750611431612058565b61144d5760405162461bcd60e51b81526004016108c990613397565b61145b898989898989612563565b600190925550979650505050505050565b603f546001600160a01b03163314806114885750611488612058565b6114a45760405162461bcd60e51b81526004016108c990613397565b610e94816125ae565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b0316146115485760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b60648201526084016108c9565b6115513361260d565b565b61155b612058565b6115775760405162461bcd60e51b81526004016108c990613360565b600060465560478190556040518181527fc29d6fedbc6bdf267a08166c2b976fbd72aca5d6a769528616f8b9224c8f197f906020016109b1565b6115b9612058565b6115d55760405162461bcd60e51b81526004016108c990613360565b60418190556040518181527f95201f9c21f26877223b1ff4073936a6484c35495649e60e55730497aeb60d93906020016109b1565b611612612058565b61162e5760405162461bcd60e51b81526004016108c990613360565b6001600160a01b03821660009081526033602052604090205460ff16156116975760405162461bcd60e51b815260206004820152601760248201527f417373657420616c726561647920737570706f7274656400000000000000000060448201526064016108c9565b60405180608001604052806001151581526020018260ff1660018111156116c0576116c06134a3565b60018111156116d1576116d16134a3565b81526000602080830182905260409283018290526001600160a01b0386168252603381529190208251815490151560ff19821681178355928401519192839161ff001990911661ffff1990911617610100836001811115611734576117346134a3565b02179055506040820151815460609093015161ffff1663010000000264ffff0000001960ff90921662010000029190911664ffffff000019909316929092179190911790556117828261244d565b603480546001810182556000919091527f46bddb1178e94d7f2892ff5f366840eb658911794f2c3a44c450aa2c505186c10180546001600160a01b0319166001600160a01b038481169182179092556037546040516315d5220f60e31b815260048101929092529091169063aea910789060240160206040518083038186803b15801561180e57600080fd5b505afa158015611822573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061184691906132db565b506040516001600160a01b03831681527f4f1ac48525e50059cc1cc6e0e1940ece0dd653a4db4841538d6aef036be2fb7b906020015b60405180910390a15050565b611890612058565b6118ac5760405162461bcd60e51b81526004016108c990613360565b603f80546001600160a01b0319166001600160a01b0383169081179091556040519081527f869e0abd13cc3a975de7b93be3df1cb2255c802b1cead85963cc79d99f131bee906020016109b1565b611902612058565b61191e5760405162461bcd60e51b81526004016108c990613360565b6001600160a01b03821660009081526033602052604090205460ff1661197c5760405162461bcd60e51b8152602060048201526013602482015272105cdcd95d081b9bdd081cdd5c1c1bdc9d1959606a1b60448201526064016108c9565b6103e88161ffff16106119c55760405162461bcd60e51b81526020600482015260116024820152700a6d8d2e0e0c2ceca40e8dede40d0d2ced607b1b60448201526064016108c9565b6001600160a01b038216600081815260336020908152604091829020805464ffff0000001916630100000061ffff8716908102919091179091558251938452908301527f8d22e9d2cbe8bb65a3c4412bd8970743864512a1a0e004e8d00fb96277b78b94910161187c565b603f546001600160a01b0316331480611a4c5750611a4c612058565b611a685760405162461bcd60e51b81526004016108c990613397565b7f53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac453580546002811415611aac5760405162461bcd60e51b81526004016108c9906133df565b60028255611abd87878787876126ce565b50600190555050505050565b603f546001600160a01b0316331480611ae55750611ae5612058565b611b015760405162461bcd60e51b81526004016108c990613397565b670de0b6b3a7640000811115611b495760405162461bcd60e51b815260206004820152600d60248201526c496e76616c69642076616c756560981b60448201526064016108c9565b60398190556040518181527f41ecb23a0e7865b25f38c268b7c3012220d822929e9edff07326e89d5bb822b5906020016109b1565b603f546001600160a01b0316331480611b9a5750611b9a612058565b611bb65760405162461bcd60e51b81526004016108c990613397565b6037805460ff60a81b191690556040517f891ebab18da80ebeeea06b1b1cede098329c4c008906a98370c2ac7a80b571cb90600090a1565b611bf6612058565b611c125760405162461bcd60e51b81526004016108c990613360565b604880546001600160a01b0319166001600160a01b0383169081179091556040519081527f7d7719313229e558c5a3893cad2eb86a86a049156d1d9ebd5c63a8eedefd1c03906020016109b1565b603f546001600160a01b0316331480611c7c5750611c7c612058565b611c985760405162461bcd60e51b81526004016108c990613397565b7f53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac453580546002811415611cdc5760405162461bcd60e51b81526004016108c9906133df565b60028255611abd308888888888612906565b611cf6612058565b611d125760405162461bcd60e51b81526004016108c990613360565b603a8190556040518181527f2ec5fb5a3d2703edc461252d92ccd2799c3c74f01d97212b20388207fa17ae45906020016109b1565b611d4f612058565b611d6b5760405162461bcd60e51b81526004016108c990613360565b603b8190556040518181527f39367850377ac04920a9a670f2180e7a94d83b15ad302e59875ec58fd10bd37d906020016109b1565b603f546001600160a01b0316331480611dbc5750611dbc612058565b611dd85760405162461bcd60e51b81526004016108c990613397565b604080516001600160a01b038085168252831660208201527fba58ce12801c949fa65f41c46ed108671c219baf945fa48d21026cea99ff252a910160405180910390a16001600160a01b03811615611fb4576001600160a01b03811660009081526035602052604090205460ff16611e8a5760405162461bcd60e51b815260206004820152601560248201527414dd1c985d1959de481b9bdd08185c1c1c9bdd9959605a1b60448201526064016108c9565b6001600160a01b038216600090815260336020526040902054819060ff16611eed5760405162461bcd60e51b8152602060048201526016602482015275105cdcd95d081a5cc81b9bdd081cdd5c1c1bdc9d195960521b60448201526064016108c9565b60405163551c457b60e11b81526001600160a01b03848116600483015282169063aa388af69060240160206040518083038186803b158015611f2e57600080fd5b505afa158015611f42573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f669190613285565b611fb25760405162461bcd60e51b815260206004820152601f60248201527f4173736574206e6f7420737570706f727465642062792053747261746567790060448201526064016108c9565b505b6001600160a01b03918216600090815260406020819052902080546001600160a01b03191691909216179055565b603f546001600160a01b0316331480611ffe5750611ffe612058565b61201a5760405162461bcd60e51b81526004016108c990613397565b6037805460ff60a01b1916600160a01b1790556040517f8cff26a5985614b3d30629cc4ab83824bf115aec971b718d8f2f99562032e97290600090a1565b60006120706000805160206134f58339815191525490565b6001600160a01b0316336001600160a01b031614905090565b603f546001600160a01b03163314806120a557506120a5612058565b6120c15760405162461bcd60e51b81526004016108c990613397565b61155161296f565b6120d1612058565b6120ed5760405162461bcd60e51b81526004016108c990613360565b612115817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166121356000805160206134f58339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b612175612058565b6121915760405162461bcd60e51b81526004016108c990613360565b604580546001600160a01b0319166001600160a01b0383169081179091556040519081527fa12850fb726e0b2b7b3c9a9342031e1268a8148d0eb06b4bea8613204ffcd2b8906020016109b1565b6121e7612058565b6122035760405162461bcd60e51b81526004016108c990613360565b6127118161ffff161061224f5760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420626173697320706f696e747360601b60448201526064016108c9565b6048805461ffff60a01b1916600160a01b61ffff8416908102919091179091556040519081527ff12c00256bee2b6facb111a88a9b1cff86e79132939b44f1353212d6f7469557906020016109b1565b6122a7612058565b6122c35760405162461bcd60e51b81526004016108c990613360565b6103e881111561231f5760405162461bcd60e51b815260206004820152602160248201527f52656465656d206665652073686f756c64206e6f74206265206f7665722031306044820152602560f81b60648201526084016108c9565b60388190556040518181527fd6c7508d6658ccee36b7b7d7fd72e5cbaeefb40c64eff24e9ae7470e846304ee906020016109b1565b61235c612058565b6123785760405162461bcd60e51b81526004016108c990613360565b803b6123d25760405162461bcd60e51b8152602060048201526024808201527f6e657720696d706c656d656e746174696f6e206973206e6f74206120636f6e746044820152631c9858dd60e21b60648201526084016108c9565b7fa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd955565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526124489084906129c6565b505050565b6001600160a01b0381166000908152603360205260409020805462010000900460ff1615612479575050565b6000826001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b1580156124b457600080fd5b505afa1580156124c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124ec91906132f4565b905060068160ff1610158015612506575060128160ff1611155b6125495760405162461bcd60e51b81526020600482015260146024820152732ab732bc3832b1ba32b210383932b1b4b9b4b7b760611b60448201526064016108c9565b815460ff909116620100000262ff00001990911617905550565b60405162461bcd60e51b815260206004820152601d60248201527f436f6c6c61746572616c2073776170206e6f7420737570706f7274656400000060448201526000906064016108c9565b6125b781612a98565b306001600160a01b031663b9b17f9f6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156125f257600080fd5b505af1158015612606573d6000803e3d6000fd5b5050505050565b6001600160a01b0381166126635760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f72206973206164647265737328302900000000000060448201526064016108c9565b806001600160a01b03166126836000805160206134f58339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a3610e94816000805160206134f583398151915255565b6001600160a01b03851660009081526035602052604090205460ff1661272c5760405162461bcd60e51b8152602060048201526013602482015272496e76616c696420746f20537472617465677960681b60448201526064016108c9565b60018314801561273c5750600181145b80156127a057507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031684846000818110612780576127806134cf565b90506020020160208101906127959190613085565b6001600160a01b0316145b6127e55760405162461bcd60e51b815260206004820152601660248201527513db9b1e4815d15512081a5cc81cdd5c1c1bdc9d195960521b60448201526064016108c9565b6127ed612b5c565b82826000818110612800576128006134cf565b9050602002013511156128555760405162461bcd60e51b815260206004820152601960248201527f4e6f7420656e6f756768205745544820617661696c61626c650000000000000060448201526064016108c9565b6128ac858383600081811061286c5761286c6134cf565b905060200201357f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166123f69092919063ffffffff16565b846001600160a01b031663de5f62686040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156128e757600080fd5b505af11580156128fb573d6000803e3d6000fd5b505050505050505050565b612914868686868686612c71565b306001600160a01b031663b9b17f9f6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561294f57600080fd5b505af1158015612963573d6000803e3d6000fd5b50505050505050505050565b612977612dff565b306001600160a01b031663b9b17f9f6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156129b257600080fd5b505af1158015610d81573d6000803e3d6000fd5b6000612a1b826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316612e919092919063ffffffff16565b8051909150156124485780806020019051810190612a399190613285565b6124485760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016108c9565b6001600160a01b03811660009081526035602052604090205460ff16612b005760405162461bcd60e51b815260206004820152601960248201527f5374726174656779206973206e6f7420737570706f727465640000000000000060448201526064016108c9565b6000819050806001600160a01b031663853828b66040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612b4057600080fd5b505af1158015612b54573d6000803e3d6000fd5b505050505050565b60408051608081018252604b546001600160801b03808216808452600160801b9283900482166020850152604c54808316958501869052929092041660608301526000928391612bac9190613407565b6040516370a0823160e01b81523060048201526001600160801b039190911691506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a082319060240160206040518083038186803b158015612c1c57600080fd5b505afa158015612c30573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c5491906132db565b905081811115612c6b57612c68828261342f565b93505b50505090565b6001600160a01b03851660009081526035602052604090205460ff16612cd15760405162461bcd60e51b8152602060048201526015602482015274496e76616c69642066726f6d20537472617465677960581b60448201526064016108c9565b828114612d205760405162461bcd60e51b815260206004820152601960248201527f506172616d65746572206c656e677468206d69736d617463680000000000000060448201526064016108c9565b8260005b81811015612df557866001600160a01b031663d9caed1289888885818110612d4e57612d4e6134cf565b9050602002016020810190612d639190613085565b878786818110612d7557612d756134cf565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b158015612dcc57600080fd5b505af1158015612de0573d6000803e3d6000fd5b5050505080612dee90613472565b9050612d24565b5050505050505050565b60365460005b81811015610a825760368181548110612e2057612e206134cf565b60009182526020822001546040805163429c145b60e11b815290516001600160a01b039092169263853828b69260048084019382900301818387803b158015612e6857600080fd5b505af1158015612e7c573d6000803e3d6000fd5b5050505080612e8a90613472565b9050612e05565b6060612ea08484600085612eaa565b90505b9392505050565b606082471015612f0b5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016108c9565b843b612f595760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016108c9565b600080866001600160a01b03168587604051612f759190613311565b60006040518083038185875af1925050503d8060008114612fb2576040519150601f19603f3d011682016040523d82523d6000602084013e612fb7565b606091505b5091509150612fc7828286612fd2565b979650505050505050565b60608315612fe1575081612ea3565b825115612ff15782518084602001fd5b8160405162461bcd60e51b81526004016108c9919061332d565b80356001600160a01b038116811461302257600080fd5b919050565b60008083601f84011261303957600080fd5b50813567ffffffffffffffff81111561305157600080fd5b6020830191508360208260051b850101111561306c57600080fd5b9250929050565b803561ffff8116811461302257600080fd5b60006020828403121561309757600080fd5b612ea38261300b565b600080604083850312156130b357600080fd5b6130bc8361300b565b91506130ca6020840161300b565b90509250929050565b60008060008060008060a087890312156130ec57600080fd5b6130f58761300b565b95506131036020880161300b565b94506040870135935060608701359250608087013567ffffffffffffffff8082111561312e57600080fd5b818901915089601f83011261314257600080fd5b81358181111561315157600080fd5b8a602082850101111561316357600080fd5b6020830194508093505050509295509295509295565b60008060008060006060868803121561319157600080fd5b61319a8661300b565b9450602086013567ffffffffffffffff808211156131b757600080fd5b6131c389838a01613027565b909650945060408801359150808211156131dc57600080fd5b506131e988828901613027565b969995985093965092949392505050565b6000806040838503121561320d57600080fd5b6132168361300b565b91506130ca60208401613073565b6000806040838503121561323757600080fd5b6132408361300b565b946020939093013593505050565b6000806040838503121561326157600080fd5b61326a8361300b565b9150602083013561327a816134e5565b809150509250929050565b60006020828403121561329757600080fd5b81518015158114612ea357600080fd5b6000602082840312156132b957600080fd5b612ea382613073565b6000602082840312156132d457600080fd5b5035919050565b6000602082840312156132ed57600080fd5b5051919050565b60006020828403121561330657600080fd5b8151612ea3816134e5565b60008251613323818460208701613446565b9190910192915050565b602081526000825180602084015261334c816040850160208701613446565b601f01601f19169190910160400192915050565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60208082526028908201527f43616c6c6572206973206e6f74207468652053747261746567697374206f722060408201526723b7bb32b93737b960c11b606082015260800190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b60006001600160801b03838116908316818110156134275761342761348d565b039392505050565b6000828210156134415761344161348d565b500390565b60005b83811015613461578181015183820152602001613449565b83811115610d815750506000910152565b60006000198214156134865761348661348d565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b60ff81168114610e9457600080fdfe7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220f9d8e9854e4711d91a89cd70983cc94f66e302856a40a1409d5cac6505f3c3da64736f6c634300080700337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a",
+ "deployedBytecode": "0x608060405234801561001057600080fd5b506004361061038e5760003560e01c8063636e6c40116101de578063ae69f3cb1161010f578063c9919112116100ad578063e6cc54321161007c578063e6cc543214610844578063e829cc1614610858578063eb03654b1461086b578063fc0cfeee1461087e57600080fd5b8063c99191121461080d578063d38bfff414610815578063d58e3b3a14610828578063e45cc9f01461083b57600080fd5b8063b890ebf6116100e9578063b890ebf6146107d7578063bc90106b146107ea578063c5f00841146107fd578063c7af33521461080557600080fd5b8063ae69f3cb1461079e578063b2c9336d146107b1578063b888879e146107c457600080fd5b80638e510b521161017c57806394828ffd1161015657806394828ffd146107515780639c82f2a4146107595780639fa1826e1461076c578063a403e4d51461077557600080fd5b80638e510b521461068d5780638ec489a214610696578063937b2581146106a957600080fd5b8063773540b3116101b8578063773540b31461064b5780637a2202f31461065e5780637b9a709614610667578063840c4c7a1461067a57600080fd5b8063636e6c4014610612578063663e64ce146106255780636c7561e81461063857600080fd5b8063372aa224116102c35780634bed3bc011610261578063570d8e1d11610230578063570d8e1d146105d1578063597c8910146105e45780635d36b190146105f7578063603ea03b146105ff57600080fd5b80634bed3bc01461058e57806350ba711c146105a157806352d38e5d146105b457806353ca9f24146105bd57600080fd5b80633fc8cef31161029d5780633fc8cef31461050e5780634530820a1461053557806349c1d54d146105685780634a5e42b11461057b57600080fd5b8063372aa224146104e05780633b8ae397146104f35780633dbc911f1461050657600080fd5b80631edfe3da116103305780632da845a81161030a5780632da845a8146104485780632e9958ab1461045b578063362bd1a31461046e57806336b6d944146104cd57600080fd5b80631edfe3da14610425578063207134b01461042e5780632b3297f91461043757600080fd5b80630c340a241161036c5780630c340a24146103cc5780631072cbea146103ec578063175188e8146103ff57806318ce56bd1461041257600080fd5b806309f49bf51461039357806309f6442c1461039d5780630acbda75146103b9575b600080fd5b61039b610891565b005b6103a660385481565b6040519081526020015b60405180910390f35b61039b6103c73660046132c2565b61090a565b6103d46109bc565b6040516001600160a01b0390911681526020016103b0565b61039b6103fa366004613224565b6109d9565b61039b61040d366004613085565b610a86565b6045546103d4906001600160a01b031681565b6103a660395481565b6103a660435481565b6048546001600160a01b03166103d4565b61039b610456366004613085565b610d87565b61039b610469366004613085565b610df9565b604b54604c5461049a916001600160801b0380821692600160801b928390048216928183169291041684565b604080516001600160801b03958616815293851660208501529184169183019190915290911660608201526080016103b0565b61039b6104db366004613085565b610e67565b61039b6104ee366004613085565b610e97565b61039b610501366004613085565b610f09565b61039b611046565b6103d47f000000000000000000000000000000000000000000000000000000000000000081565b610558610543366004613085565b60496020526000908152604090205460ff1681565b60405190151581526020016103b0565b6042546103d4906001600160a01b031681565b61039b610589366004613085565b6110bc565b604854600160a01b900461ffff166103a6565b6103a66105af3660046130d3565b6113c9565b6103a6603b5481565b60375461055890600160a01b900460ff1681565b603f546103d4906001600160a01b031681565b61039b6105f2366004613085565b61146c565b61039b6114ad565b604a546103d4906001600160a01b031681565b61039b6106203660046132c2565b611553565b61039b6106333660046132c2565b6115b1565b61039b61064636600461324e565b61160a565b61039b610659366004613085565b611888565b6103a660475481565b61039b6106753660046131fa565b6118fa565b61039b610688366004613179565b611a30565b6103a660415481565b61039b6106a43660046132c2565b611ac9565b61070a6106b73660046132c2565b604d60205260009081526040902080546001909101546001600160a01b03821691600160a01b810460ff1691600160a81b90910464ffffffffff16906001600160801b0380821691600160801b90041685565b604080516001600160a01b039096168652931515602086015264ffffffffff909216928401929092526001600160801b03918216606084015216608082015260a0016103b0565b61039b611b7e565b61039b610767366004613085565b611bee565b6103a6603a5481565b6103d4610783366004613085565b6040602081905260009182529020546001600160a01b031681565b61039b6107ac366004613179565b611c60565b61039b6107bf3660046132c2565b611cee565b6037546103d4906001600160a01b031681565b61039b6107e53660046132c2565b611d47565b61039b6107f83660046130a0565b611da0565b61039b611fe2565b610558612058565b61039b612089565b61039b610823366004613085565b6120c9565b61039b610836366004613085565b61216d565b6103a660465481565b60375461055890600160a81b900460ff1681565b61039b6108663660046132a7565b6121df565b61039b6108793660046132c2565b61229f565b61039b61088c366004613085565b612354565b603f546001600160a01b03163314806108ad57506108ad612058565b6108d25760405162461bcd60e51b81526004016108c990613397565b60405180910390fd5b6037805460ff60a01b191690556040517fbc044409505c95b6b851433df96e1beae715c909d8e7c1d6d7ab783300d4e3b990600090a1565b610912612058565b61092e5760405162461bcd60e51b81526004016108c990613360565b6113888111156109805760405162461bcd60e51b815260206004820152601760248201527f62617369732063616e6e6f74206578636565642035302500000000000000000060448201526064016108c9565b60438190556040518181527f56287a45051933ea374811b3d5d165033047be5572cac676f7c28b8be4f746c7906020015b60405180910390a150565b60006109d46000805160206134f58339815191525490565b905090565b6109e1612058565b6109fd5760405162461bcd60e51b81526004016108c990613360565b6001600160a01b03821660009081526033602052604090205460ff1615610a665760405162461bcd60e51b815260206004820152601760248201527f4f6e6c7920756e737570706f727465642061737365747300000000000000000060448201526064016108c9565b610a82610a716109bc565b6001600160a01b03841690836123f6565b5050565b610a8e612058565b610aaa5760405162461bcd60e51b81526004016108c990613360565b6001600160a01b03811660009081526035602052604090205460ff16610b0a5760405162461bcd60e51b815260206004820152601560248201527414dd1c985d1959de481b9bdd08185c1c1c9bdd9959605a1b60448201526064016108c9565b60345460005b81811015610bc257826001600160a01b03166040600060348481548110610b3957610b396134cf565b60009182526020808320909101546001600160a01b039081168452908301939093526040909101902054161415610bb25760405162461bcd60e51b815260206004820181905260248201527f53747261746567792069732064656661756c7420666f7220616e20617373657460448201526064016108c9565b610bbb81613472565b9050610b10565b506036548060005b82811015610c2257846001600160a01b031660368281548110610bef57610bef6134cf565b6000918252602090912001546001600160a01b03161415610c1257809150610c22565b610c1b81613472565b9050610bca565b5081811015610d81576036610c3860018461342f565b81548110610c4857610c486134cf565b600091825260209091200154603680546001600160a01b039092169183908110610c7457610c746134cf565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506036805480610cb357610cb36134b9565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b03861680835260359091526040808320805460ff19169055805163429c145b60e11b81529051879363853828b6926004808201939182900301818387803b158015610d2a57600080fd5b505af1158015610d3e573d6000803e3d6000fd5b50506040516001600160a01b03881681527f09a1db4b80c32706328728508c941a6b954f31eb5affd32f236c1fd405f8fea49250602001905060405180910390a1505b50505050565b610d8f612058565b610dab5760405162461bcd60e51b81526004016108c990613360565b604280546001600160a01b0319166001600160a01b0383169081179091556040519081527f1e4af5ac389e8cde1bdaa6830881b6c987c62a45cfb3b33d27d805cde3b57750906020016109b1565b610e01612058565b610e1d5760405162461bcd60e51b81526004016108c990613360565b604a80546001600160a01b0319166001600160a01b0383169081179091556040517faf2910d9759321733de15af1827a49830692912adeb2b3646334861f2cd2eed490600090a250565b610e6f612058565b610e8b5760405162461bcd60e51b81526004016108c990613360565b610e948161244d565b50565b610e9f612058565b610ebb5760405162461bcd60e51b81526004016108c990613360565b603780546001600160a01b0319166001600160a01b0383169081179091556040519081527fb266add5f3044b17d27db796af992cecbe413921b4e8aaaee03c719e16b9806a906020016109b1565b610f11612058565b610f2d5760405162461bcd60e51b81526004016108c990613360565b6001600160a01b03811660009081526035602052604090205460ff1615610f965760405162461bcd60e51b815260206004820152601960248201527f537472617465677920616c726561647920617070726f7665640000000000000060448201526064016108c9565b6040805180820182526001808252600060208084018281526001600160a01b038716808452603583528684209551865460ff19169015151786559051948401949094556036805493840181559091527f4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b890910180546001600160a01b0319168317905591519081527f960dd94cbb79169f09a4e445d58b895df2d9bffa5b31055d0932d801724a20d191016109b1565b603f546001600160a01b03163314806110625750611062612058565b61107e5760405162461bcd60e51b81526004016108c990613397565b6037805460ff60a81b1916600160a81b1790556040517f71f0e5b62f846a22e0b4d159e516e62fa9c2b8eb570be15f83e67d98a2ee51e090600090a1565b6110c4612058565b6110e05760405162461bcd60e51b81526004016108c990613360565b6001600160a01b03811660009081526033602052604090205460ff1661113e5760405162461bcd60e51b8152602060048201526013602482015272105cdcd95d081b9bdd081cdd5c1c1bdc9d1959606a1b60448201526064016108c9565b604051632fa8a91360e11b81526001600160a01b03821660048201526509184e72a000903090635f5152269060240160206040518083038186803b15801561118557600080fd5b505afa158015611199573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111bd91906132db565b111561120b5760405162461bcd60e51b815260206004820152601760248201527f5661756c74207374696c6c20686f6c647320617373657400000000000000000060448201526064016108c9565b6034548060005b8281101561126a57836001600160a01b031660348281548110611237576112376134cf565b6000918252602090912001546001600160a01b0316141561125a5780915061126a565b61126381613472565b9050611212565b50603461127860018461342f565b81548110611288576112886134cf565b600091825260209091200154603480546001600160a01b0390921691839081106112b4576112b46134cf565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060348054806112f3576112f36134b9565b60008281526020808220600019908401810180546001600160a01b031990811690915593019093556001600160a01b038616808252604080855280832080549094169093558251908152928301527fba58ce12801c949fa65f41c46ed108671c219baf945fa48d21026cea99ff252a910160405180910390a16001600160a01b038316600081815260336020908152604091829020805464ffffffffff1916905590519182527f37803e2125c48ee96c38ddf04e826daf335b0e1603579040fd275aba6d06b6fc910160405180910390a1505050565b7f53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac453580546000919060028114156114115760405162461bcd60e51b81526004016108c9906133df565b60028255603f546001600160a01b03163314806114315750611431612058565b61144d5760405162461bcd60e51b81526004016108c990613397565b61145b898989898989612563565b600190925550979650505050505050565b603f546001600160a01b03163314806114885750611488612058565b6114a45760405162461bcd60e51b81526004016108c990613397565b610e94816125ae565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b0316146115485760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b60648201526084016108c9565b6115513361260d565b565b61155b612058565b6115775760405162461bcd60e51b81526004016108c990613360565b600060465560478190556040518181527fc29d6fedbc6bdf267a08166c2b976fbd72aca5d6a769528616f8b9224c8f197f906020016109b1565b6115b9612058565b6115d55760405162461bcd60e51b81526004016108c990613360565b60418190556040518181527f95201f9c21f26877223b1ff4073936a6484c35495649e60e55730497aeb60d93906020016109b1565b611612612058565b61162e5760405162461bcd60e51b81526004016108c990613360565b6001600160a01b03821660009081526033602052604090205460ff16156116975760405162461bcd60e51b815260206004820152601760248201527f417373657420616c726561647920737570706f7274656400000000000000000060448201526064016108c9565b60405180608001604052806001151581526020018260ff1660018111156116c0576116c06134a3565b60018111156116d1576116d16134a3565b81526000602080830182905260409283018290526001600160a01b0386168252603381529190208251815490151560ff19821681178355928401519192839161ff001990911661ffff1990911617610100836001811115611734576117346134a3565b02179055506040820151815460609093015161ffff1663010000000264ffff0000001960ff90921662010000029190911664ffffff000019909316929092179190911790556117828261244d565b603480546001810182556000919091527f46bddb1178e94d7f2892ff5f366840eb658911794f2c3a44c450aa2c505186c10180546001600160a01b0319166001600160a01b038481169182179092556037546040516315d5220f60e31b815260048101929092529091169063aea910789060240160206040518083038186803b15801561180e57600080fd5b505afa158015611822573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061184691906132db565b506040516001600160a01b03831681527f4f1ac48525e50059cc1cc6e0e1940ece0dd653a4db4841538d6aef036be2fb7b906020015b60405180910390a15050565b611890612058565b6118ac5760405162461bcd60e51b81526004016108c990613360565b603f80546001600160a01b0319166001600160a01b0383169081179091556040519081527f869e0abd13cc3a975de7b93be3df1cb2255c802b1cead85963cc79d99f131bee906020016109b1565b611902612058565b61191e5760405162461bcd60e51b81526004016108c990613360565b6001600160a01b03821660009081526033602052604090205460ff1661197c5760405162461bcd60e51b8152602060048201526013602482015272105cdcd95d081b9bdd081cdd5c1c1bdc9d1959606a1b60448201526064016108c9565b6103e88161ffff16106119c55760405162461bcd60e51b81526020600482015260116024820152700a6d8d2e0e0c2ceca40e8dede40d0d2ced607b1b60448201526064016108c9565b6001600160a01b038216600081815260336020908152604091829020805464ffff0000001916630100000061ffff8716908102919091179091558251938452908301527f8d22e9d2cbe8bb65a3c4412bd8970743864512a1a0e004e8d00fb96277b78b94910161187c565b603f546001600160a01b0316331480611a4c5750611a4c612058565b611a685760405162461bcd60e51b81526004016108c990613397565b7f53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac453580546002811415611aac5760405162461bcd60e51b81526004016108c9906133df565b60028255611abd87878787876126ce565b50600190555050505050565b603f546001600160a01b0316331480611ae55750611ae5612058565b611b015760405162461bcd60e51b81526004016108c990613397565b670de0b6b3a7640000811115611b495760405162461bcd60e51b815260206004820152600d60248201526c496e76616c69642076616c756560981b60448201526064016108c9565b60398190556040518181527f41ecb23a0e7865b25f38c268b7c3012220d822929e9edff07326e89d5bb822b5906020016109b1565b603f546001600160a01b0316331480611b9a5750611b9a612058565b611bb65760405162461bcd60e51b81526004016108c990613397565b6037805460ff60a81b191690556040517f891ebab18da80ebeeea06b1b1cede098329c4c008906a98370c2ac7a80b571cb90600090a1565b611bf6612058565b611c125760405162461bcd60e51b81526004016108c990613360565b604880546001600160a01b0319166001600160a01b0383169081179091556040519081527f7d7719313229e558c5a3893cad2eb86a86a049156d1d9ebd5c63a8eedefd1c03906020016109b1565b603f546001600160a01b0316331480611c7c5750611c7c612058565b611c985760405162461bcd60e51b81526004016108c990613397565b7f53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac453580546002811415611cdc5760405162461bcd60e51b81526004016108c9906133df565b60028255611abd308888888888612906565b611cf6612058565b611d125760405162461bcd60e51b81526004016108c990613360565b603a8190556040518181527f2ec5fb5a3d2703edc461252d92ccd2799c3c74f01d97212b20388207fa17ae45906020016109b1565b611d4f612058565b611d6b5760405162461bcd60e51b81526004016108c990613360565b603b8190556040518181527f39367850377ac04920a9a670f2180e7a94d83b15ad302e59875ec58fd10bd37d906020016109b1565b603f546001600160a01b0316331480611dbc5750611dbc612058565b611dd85760405162461bcd60e51b81526004016108c990613397565b604080516001600160a01b038085168252831660208201527fba58ce12801c949fa65f41c46ed108671c219baf945fa48d21026cea99ff252a910160405180910390a16001600160a01b03811615611fb4576001600160a01b03811660009081526035602052604090205460ff16611e8a5760405162461bcd60e51b815260206004820152601560248201527414dd1c985d1959de481b9bdd08185c1c1c9bdd9959605a1b60448201526064016108c9565b6001600160a01b038216600090815260336020526040902054819060ff16611eed5760405162461bcd60e51b8152602060048201526016602482015275105cdcd95d081a5cc81b9bdd081cdd5c1c1bdc9d195960521b60448201526064016108c9565b60405163551c457b60e11b81526001600160a01b03848116600483015282169063aa388af69060240160206040518083038186803b158015611f2e57600080fd5b505afa158015611f42573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f669190613285565b611fb25760405162461bcd60e51b815260206004820152601f60248201527f4173736574206e6f7420737570706f727465642062792053747261746567790060448201526064016108c9565b505b6001600160a01b03918216600090815260406020819052902080546001600160a01b03191691909216179055565b603f546001600160a01b0316331480611ffe5750611ffe612058565b61201a5760405162461bcd60e51b81526004016108c990613397565b6037805460ff60a01b1916600160a01b1790556040517f8cff26a5985614b3d30629cc4ab83824bf115aec971b718d8f2f99562032e97290600090a1565b60006120706000805160206134f58339815191525490565b6001600160a01b0316336001600160a01b031614905090565b603f546001600160a01b03163314806120a557506120a5612058565b6120c15760405162461bcd60e51b81526004016108c990613397565b61155161296f565b6120d1612058565b6120ed5760405162461bcd60e51b81526004016108c990613360565b612115817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166121356000805160206134f58339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b612175612058565b6121915760405162461bcd60e51b81526004016108c990613360565b604580546001600160a01b0319166001600160a01b0383169081179091556040519081527fa12850fb726e0b2b7b3c9a9342031e1268a8148d0eb06b4bea8613204ffcd2b8906020016109b1565b6121e7612058565b6122035760405162461bcd60e51b81526004016108c990613360565b6127118161ffff161061224f5760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420626173697320706f696e747360601b60448201526064016108c9565b6048805461ffff60a01b1916600160a01b61ffff8416908102919091179091556040519081527ff12c00256bee2b6facb111a88a9b1cff86e79132939b44f1353212d6f7469557906020016109b1565b6122a7612058565b6122c35760405162461bcd60e51b81526004016108c990613360565b6103e881111561231f5760405162461bcd60e51b815260206004820152602160248201527f52656465656d206665652073686f756c64206e6f74206265206f7665722031306044820152602560f81b60648201526084016108c9565b60388190556040518181527fd6c7508d6658ccee36b7b7d7fd72e5cbaeefb40c64eff24e9ae7470e846304ee906020016109b1565b61235c612058565b6123785760405162461bcd60e51b81526004016108c990613360565b803b6123d25760405162461bcd60e51b8152602060048201526024808201527f6e657720696d706c656d656e746174696f6e206973206e6f74206120636f6e746044820152631c9858dd60e21b60648201526084016108c9565b7fa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd955565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526124489084906129c6565b505050565b6001600160a01b0381166000908152603360205260409020805462010000900460ff1615612479575050565b6000826001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b1580156124b457600080fd5b505afa1580156124c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124ec91906132f4565b905060068160ff1610158015612506575060128160ff1611155b6125495760405162461bcd60e51b81526020600482015260146024820152732ab732bc3832b1ba32b210383932b1b4b9b4b7b760611b60448201526064016108c9565b815460ff909116620100000262ff00001990911617905550565b60405162461bcd60e51b815260206004820152601d60248201527f436f6c6c61746572616c2073776170206e6f7420737570706f7274656400000060448201526000906064016108c9565b6125b781612a98565b306001600160a01b031663b9b17f9f6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156125f257600080fd5b505af1158015612606573d6000803e3d6000fd5b5050505050565b6001600160a01b0381166126635760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f72206973206164647265737328302900000000000060448201526064016108c9565b806001600160a01b03166126836000805160206134f58339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a3610e94816000805160206134f583398151915255565b6001600160a01b03851660009081526035602052604090205460ff1661272c5760405162461bcd60e51b8152602060048201526013602482015272496e76616c696420746f20537472617465677960681b60448201526064016108c9565b60018314801561273c5750600181145b80156127a057507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031684846000818110612780576127806134cf565b90506020020160208101906127959190613085565b6001600160a01b0316145b6127e55760405162461bcd60e51b815260206004820152601660248201527513db9b1e4815d15512081a5cc81cdd5c1c1bdc9d195960521b60448201526064016108c9565b6127ed612b5c565b82826000818110612800576128006134cf565b9050602002013511156128555760405162461bcd60e51b815260206004820152601960248201527f4e6f7420656e6f756768205745544820617661696c61626c650000000000000060448201526064016108c9565b6128ac858383600081811061286c5761286c6134cf565b905060200201357f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166123f69092919063ffffffff16565b846001600160a01b031663de5f62686040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156128e757600080fd5b505af11580156128fb573d6000803e3d6000fd5b505050505050505050565b612914868686868686612c71565b306001600160a01b031663b9b17f9f6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561294f57600080fd5b505af1158015612963573d6000803e3d6000fd5b50505050505050505050565b612977612dff565b306001600160a01b031663b9b17f9f6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156129b257600080fd5b505af1158015610d81573d6000803e3d6000fd5b6000612a1b826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316612e919092919063ffffffff16565b8051909150156124485780806020019051810190612a399190613285565b6124485760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016108c9565b6001600160a01b03811660009081526035602052604090205460ff16612b005760405162461bcd60e51b815260206004820152601960248201527f5374726174656779206973206e6f7420737570706f727465640000000000000060448201526064016108c9565b6000819050806001600160a01b031663853828b66040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612b4057600080fd5b505af1158015612b54573d6000803e3d6000fd5b505050505050565b60408051608081018252604b546001600160801b03808216808452600160801b9283900482166020850152604c54808316958501869052929092041660608301526000928391612bac9190613407565b6040516370a0823160e01b81523060048201526001600160801b039190911691506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a082319060240160206040518083038186803b158015612c1c57600080fd5b505afa158015612c30573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c5491906132db565b905081811115612c6b57612c68828261342f565b93505b50505090565b6001600160a01b03851660009081526035602052604090205460ff16612cd15760405162461bcd60e51b8152602060048201526015602482015274496e76616c69642066726f6d20537472617465677960581b60448201526064016108c9565b828114612d205760405162461bcd60e51b815260206004820152601960248201527f506172616d65746572206c656e677468206d69736d617463680000000000000060448201526064016108c9565b8260005b81811015612df557866001600160a01b031663d9caed1289888885818110612d4e57612d4e6134cf565b9050602002016020810190612d639190613085565b878786818110612d7557612d756134cf565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b158015612dcc57600080fd5b505af1158015612de0573d6000803e3d6000fd5b5050505080612dee90613472565b9050612d24565b5050505050505050565b60365460005b81811015610a825760368181548110612e2057612e206134cf565b60009182526020822001546040805163429c145b60e11b815290516001600160a01b039092169263853828b69260048084019382900301818387803b158015612e6857600080fd5b505af1158015612e7c573d6000803e3d6000fd5b5050505080612e8a90613472565b9050612e05565b6060612ea08484600085612eaa565b90505b9392505050565b606082471015612f0b5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016108c9565b843b612f595760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016108c9565b600080866001600160a01b03168587604051612f759190613311565b60006040518083038185875af1925050503d8060008114612fb2576040519150601f19603f3d011682016040523d82523d6000602084013e612fb7565b606091505b5091509150612fc7828286612fd2565b979650505050505050565b60608315612fe1575081612ea3565b825115612ff15782518084602001fd5b8160405162461bcd60e51b81526004016108c9919061332d565b80356001600160a01b038116811461302257600080fd5b919050565b60008083601f84011261303957600080fd5b50813567ffffffffffffffff81111561305157600080fd5b6020830191508360208260051b850101111561306c57600080fd5b9250929050565b803561ffff8116811461302257600080fd5b60006020828403121561309757600080fd5b612ea38261300b565b600080604083850312156130b357600080fd5b6130bc8361300b565b91506130ca6020840161300b565b90509250929050565b60008060008060008060a087890312156130ec57600080fd5b6130f58761300b565b95506131036020880161300b565b94506040870135935060608701359250608087013567ffffffffffffffff8082111561312e57600080fd5b818901915089601f83011261314257600080fd5b81358181111561315157600080fd5b8a602082850101111561316357600080fd5b6020830194508093505050509295509295509295565b60008060008060006060868803121561319157600080fd5b61319a8661300b565b9450602086013567ffffffffffffffff808211156131b757600080fd5b6131c389838a01613027565b909650945060408801359150808211156131dc57600080fd5b506131e988828901613027565b969995985093965092949392505050565b6000806040838503121561320d57600080fd5b6132168361300b565b91506130ca60208401613073565b6000806040838503121561323757600080fd5b6132408361300b565b946020939093013593505050565b6000806040838503121561326157600080fd5b61326a8361300b565b9150602083013561327a816134e5565b809150509250929050565b60006020828403121561329757600080fd5b81518015158114612ea357600080fd5b6000602082840312156132b957600080fd5b612ea382613073565b6000602082840312156132d457600080fd5b5035919050565b6000602082840312156132ed57600080fd5b5051919050565b60006020828403121561330657600080fd5b8151612ea3816134e5565b60008251613323818460208701613446565b9190910192915050565b602081526000825180602084015261334c816040850160208701613446565b601f01601f19169190910160400192915050565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60208082526028908201527f43616c6c6572206973206e6f74207468652053747261746567697374206f722060408201526723b7bb32b93737b960c11b606082015260800190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b60006001600160801b03838116908316818110156134275761342761348d565b039392505050565b6000828210156134415761344161348d565b500390565b60005b83811015613461578181015183820152602001613449565b83811115610d815750506000910152565b60006000198214156134865761348661348d565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b60ff81168114610e9457600080fdfe7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220f9d8e9854e4711d91a89cd70983cc94f66e302856a40a1409d5cac6505f3c3da64736f6c63430008070033",
"libraries": {},
"devdoc": {
"author": "Origin Protocol Inc",
@@ -1192,6 +1470,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 +1496,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 +1623,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 +1662,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 +1677,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."
},
@@ -1463,6 +1760,12 @@
},
"withdrawFromStrategy(address,address[],uint256[])": {
"notice": "Withdraw multiple assets from the strategy to the vault."
+ },
+ "withdrawalQueueMetadata()": {
+ "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"
+ },
+ "withdrawalRequests(uint256)": {
+ "notice": "Mapping of withdrawal request indices to the user withdrawal request data"
}
},
"version": 1
@@ -1470,7 +1773,7 @@
"storageLayout": {
"storage": [
{
- "astId": 41419,
+ "astId": 24695,
"contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin",
"label": "initialized",
"offset": 0,
@@ -1478,7 +1781,7 @@
"type": "t_bool"
},
{
- "astId": 41422,
+ "astId": 24698,
"contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin",
"label": "initializing",
"offset": 1,
@@ -1486,7 +1789,7 @@
"type": "t_bool"
},
{
- "astId": 41462,
+ "astId": 24738,
"contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin",
"label": "______gap",
"offset": 0,
@@ -1494,15 +1797,15 @@
"type": "t_array(t_uint256)50_storage"
},
{
- "astId": 46069,
+ "astId": 30639,
"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)30633_storage)"
},
{
- "astId": 46073,
+ "astId": 30643,
"contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin",
"label": "allAssets",
"offset": 0,
@@ -1510,15 +1813,15 @@
"type": "t_array(t_address)dyn_storage"
},
{
- "astId": 46084,
+ "astId": 30654,
"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)30648_storage)"
},
{
- "astId": 46088,
+ "astId": 30658,
"contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin",
"label": "allStrategies",
"offset": 0,
@@ -1526,7 +1829,7 @@
"type": "t_array(t_address)dyn_storage"
},
{
- "astId": 46091,
+ "astId": 30661,
"contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin",
"label": "priceProvider",
"offset": 0,
@@ -1534,7 +1837,7 @@
"type": "t_address"
},
{
- "astId": 46095,
+ "astId": 30665,
"contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin",
"label": "rebasePaused",
"offset": 20,
@@ -1542,7 +1845,7 @@
"type": "t_bool"
},
{
- "astId": 46099,
+ "astId": 30669,
"contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin",
"label": "capitalPaused",
"offset": 21,
@@ -1550,7 +1853,7 @@
"type": "t_bool"
},
{
- "astId": 46102,
+ "astId": 30672,
"contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin",
"label": "redeemFeeBps",
"offset": 0,
@@ -1558,7 +1861,7 @@
"type": "t_uint256"
},
{
- "astId": 46105,
+ "astId": 30675,
"contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin",
"label": "vaultBuffer",
"offset": 0,
@@ -1566,7 +1869,7 @@
"type": "t_uint256"
},
{
- "astId": 46108,
+ "astId": 30678,
"contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin",
"label": "autoAllocateThreshold",
"offset": 0,
@@ -1574,7 +1877,7 @@
"type": "t_uint256"
},
{
- "astId": 46111,
+ "astId": 30681,
"contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin",
"label": "rebaseThreshold",
"offset": 0,
@@ -1582,15 +1885,15 @@
"type": "t_uint256"
},
{
- "astId": 46115,
+ "astId": 30685,
"contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin",
"label": "oUSD",
"offset": 0,
"slot": "60",
- "type": "t_contract(OUSD)40245"
+ "type": "t_contract(OUSD)24061"
},
{
- "astId": 46124,
+ "astId": 30694,
"contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin",
"label": "_deprecated_rebaseHooksAddr",
"offset": 0,
@@ -1598,7 +1901,7 @@
"type": "t_address"
},
{
- "astId": 46130,
+ "astId": 30700,
"contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin",
"label": "_deprecated_uniswapAddr",
"offset": 0,
@@ -1606,7 +1909,7 @@
"type": "t_address"
},
{
- "astId": 46137,
+ "astId": 30707,
"contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin",
"label": "strategistAddr",
"offset": 0,
@@ -1614,7 +1917,7 @@
"type": "t_address"
},
{
- "astId": 46142,
+ "astId": 30712,
"contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin",
"label": "assetDefaultStrategies",
"offset": 0,
@@ -1622,7 +1925,7 @@
"type": "t_mapping(t_address,t_address)"
},
{
- "astId": 46145,
+ "astId": 30715,
"contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin",
"label": "maxSupplyDiff",
"offset": 0,
@@ -1630,7 +1933,7 @@
"type": "t_uint256"
},
{
- "astId": 46148,
+ "astId": 30718,
"contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin",
"label": "trusteeAddress",
"offset": 0,
@@ -1638,7 +1941,7 @@
"type": "t_address"
},
{
- "astId": 46151,
+ "astId": 30721,
"contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin",
"label": "trusteeFeeBps",
"offset": 0,
@@ -1646,7 +1949,7 @@
"type": "t_uint256"
},
{
- "astId": 46155,
+ "astId": 30725,
"contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin",
"label": "_deprecated_swapTokens",
"offset": 0,
@@ -1654,7 +1957,7 @@
"type": "t_array(t_address)dyn_storage"
},
{
- "astId": 46165,
+ "astId": 30731,
"contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin",
"label": "ousdMetaStrategy",
"offset": 0,
@@ -1662,7 +1965,7 @@
"type": "t_address"
},
{
- "astId": 46169,
+ "astId": 30734,
"contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin",
"label": "netOusdMintedForStrategy",
"offset": 0,
@@ -1670,7 +1973,7 @@
"type": "t_int256"
},
{
- "astId": 46173,
+ "astId": 30737,
"contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin",
"label": "netOusdMintForStrategyThreshold",
"offset": 0,
@@ -1678,20 +1981,52 @@
"type": "t_uint256"
},
{
- "astId": 46194,
+ "astId": 30758,
"contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin",
"label": "swapConfig",
"offset": 0,
"slot": "72",
- "type": "t_struct(SwapConfig)46184_storage"
+ "type": "t_struct(SwapConfig)30748_storage"
},
{
- "astId": 46198,
+ "astId": 30762,
"contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin",
- "label": "__gap",
+ "label": "isMintWhitelistedStrategy",
"offset": 0,
"slot": "73",
- "type": "t_array(t_uint256)50_storage"
+ "type": "t_mapping(t_address,t_bool)"
+ },
+ {
+ "astId": 30765,
+ "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin",
+ "label": "dripper",
+ "offset": 0,
+ "slot": "74",
+ "type": "t_address"
+ },
+ {
+ "astId": 30778,
+ "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin",
+ "label": "withdrawalQueueMetadata",
+ "offset": 0,
+ "slot": "75",
+ "type": "t_struct(WithdrawalQueueMetadata)30774_storage"
+ },
+ {
+ "astId": 30795,
+ "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin",
+ "label": "withdrawalRequests",
+ "offset": 0,
+ "slot": "77",
+ "type": "t_mapping(t_uint256,t_struct(WithdrawalRequest)30789_storage)"
+ },
+ {
+ "astId": 30799,
+ "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin",
+ "label": "__gap",
+ "offset": 0,
+ "slot": "78",
+ "type": "t_array(t_uint256)45_storage"
}
],
"types": {
@@ -1706,6 +2041,12 @@
"label": "address[]",
"numberOfBytes": "32"
},
+ "t_array(t_uint256)45_storage": {
+ "base": "t_uint256",
+ "encoding": "inplace",
+ "label": "uint256[45]",
+ "numberOfBytes": "1440"
+ },
"t_array(t_uint256)50_storage": {
"base": "t_uint256",
"encoding": "inplace",
@@ -1717,12 +2058,12 @@
"label": "bool",
"numberOfBytes": "1"
},
- "t_contract(OUSD)40245": {
+ "t_contract(OUSD)24061": {
"encoding": "inplace",
"label": "contract OUSD",
"numberOfBytes": "20"
},
- "t_enum(UnitConversion)46053": {
+ "t_enum(UnitConversion)30623": {
"encoding": "inplace",
"label": "enum VaultStorage.UnitConversion",
"numberOfBytes": "1"
@@ -1739,26 +2080,40 @@
"numberOfBytes": "32",
"value": "t_address"
},
- "t_mapping(t_address,t_struct(Asset)46063_storage)": {
+ "t_mapping(t_address,t_bool)": {
+ "encoding": "mapping",
+ "key": "t_address",
+ "label": "mapping(address => bool)",
+ "numberOfBytes": "32",
+ "value": "t_bool"
+ },
+ "t_mapping(t_address,t_struct(Asset)30633_storage)": {
"encoding": "mapping",
"key": "t_address",
"label": "mapping(address => struct VaultStorage.Asset)",
"numberOfBytes": "32",
- "value": "t_struct(Asset)46063_storage"
+ "value": "t_struct(Asset)30633_storage"
},
- "t_mapping(t_address,t_struct(Strategy)46078_storage)": {
+ "t_mapping(t_address,t_struct(Strategy)30648_storage)": {
"encoding": "mapping",
"key": "t_address",
"label": "mapping(address => struct VaultStorage.Strategy)",
"numberOfBytes": "32",
- "value": "t_struct(Strategy)46078_storage"
+ "value": "t_struct(Strategy)30648_storage"
},
- "t_struct(Asset)46063_storage": {
+ "t_mapping(t_uint256,t_struct(WithdrawalRequest)30789_storage)": {
+ "encoding": "mapping",
+ "key": "t_uint256",
+ "label": "mapping(uint256 => struct VaultStorage.WithdrawalRequest)",
+ "numberOfBytes": "32",
+ "value": "t_struct(WithdrawalRequest)30789_storage"
+ },
+ "t_struct(Asset)30633_storage": {
"encoding": "inplace",
"label": "struct VaultStorage.Asset",
"members": [
{
- "astId": 46055,
+ "astId": 30625,
"contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin",
"label": "isSupported",
"offset": 0,
@@ -1766,15 +2121,15 @@
"type": "t_bool"
},
{
- "astId": 46058,
+ "astId": 30628,
"contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin",
"label": "unitConversion",
"offset": 1,
"slot": "0",
- "type": "t_enum(UnitConversion)46053"
+ "type": "t_enum(UnitConversion)30623"
},
{
- "astId": 46060,
+ "astId": 30630,
"contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin",
"label": "decimals",
"offset": 2,
@@ -1782,7 +2137,7 @@
"type": "t_uint8"
},
{
- "astId": 46062,
+ "astId": 30632,
"contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin",
"label": "allowedOracleSlippageBps",
"offset": 3,
@@ -1792,12 +2147,12 @@
],
"numberOfBytes": "32"
},
- "t_struct(Strategy)46078_storage": {
+ "t_struct(Strategy)30648_storage": {
"encoding": "inplace",
"label": "struct VaultStorage.Strategy",
"members": [
{
- "astId": 46075,
+ "astId": 30645,
"contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin",
"label": "isSupported",
"offset": 0,
@@ -1805,7 +2160,7 @@
"type": "t_bool"
},
{
- "astId": 46077,
+ "astId": 30647,
"contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin",
"label": "_deprecated",
"offset": 0,
@@ -1815,12 +2170,12 @@
],
"numberOfBytes": "64"
},
- "t_struct(SwapConfig)46184_storage": {
+ "t_struct(SwapConfig)30748_storage": {
"encoding": "inplace",
"label": "struct VaultStorage.SwapConfig",
"members": [
{
- "astId": 46181,
+ "astId": 30745,
"contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin",
"label": "swapper",
"offset": 0,
@@ -1828,7 +2183,7 @@
"type": "t_address"
},
{
- "astId": 46183,
+ "astId": 30747,
"contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin",
"label": "allowedUndervalueBps",
"offset": 20,
@@ -1838,6 +2193,97 @@
],
"numberOfBytes": "32"
},
+ "t_struct(WithdrawalQueueMetadata)30774_storage": {
+ "encoding": "inplace",
+ "label": "struct VaultStorage.WithdrawalQueueMetadata",
+ "members": [
+ {
+ "astId": 30767,
+ "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin",
+ "label": "queued",
+ "offset": 0,
+ "slot": "0",
+ "type": "t_uint128"
+ },
+ {
+ "astId": 30769,
+ "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin",
+ "label": "claimable",
+ "offset": 16,
+ "slot": "0",
+ "type": "t_uint128"
+ },
+ {
+ "astId": 30771,
+ "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin",
+ "label": "claimed",
+ "offset": 0,
+ "slot": "1",
+ "type": "t_uint128"
+ },
+ {
+ "astId": 30773,
+ "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin",
+ "label": "nextWithdrawalIndex",
+ "offset": 16,
+ "slot": "1",
+ "type": "t_uint128"
+ }
+ ],
+ "numberOfBytes": "64"
+ },
+ "t_struct(WithdrawalRequest)30789_storage": {
+ "encoding": "inplace",
+ "label": "struct VaultStorage.WithdrawalRequest",
+ "members": [
+ {
+ "astId": 30780,
+ "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin",
+ "label": "withdrawer",
+ "offset": 0,
+ "slot": "0",
+ "type": "t_address"
+ },
+ {
+ "astId": 30782,
+ "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin",
+ "label": "claimed",
+ "offset": 20,
+ "slot": "0",
+ "type": "t_bool"
+ },
+ {
+ "astId": 30784,
+ "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin",
+ "label": "timestamp",
+ "offset": 21,
+ "slot": "0",
+ "type": "t_uint40"
+ },
+ {
+ "astId": 30786,
+ "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin",
+ "label": "amount",
+ "offset": 0,
+ "slot": "1",
+ "type": "t_uint128"
+ },
+ {
+ "astId": 30788,
+ "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",
@@ -1848,6 +2294,11 @@
"label": "uint256",
"numberOfBytes": "32"
},
+ "t_uint40": {
+ "encoding": "inplace",
+ "label": "uint40",
+ "numberOfBytes": "5"
+ },
"t_uint8": {
"encoding": "inplace",
"label": "uint8",
diff --git a/contracts/deployments/holesky/OETHVaultCore.json b/contracts/deployments/holesky/OETHVaultCore.json
index d3580e13ac..fa1a92db1a 100644
--- a/contracts/deployments/holesky/OETHVaultCore.json
+++ b/contracts/deployments/holesky/OETHVaultCore.json
@@ -1,5 +1,5 @@
{
- "address": "0xE92e25B81E44B8377Df1362f8fFBc426A00d6ef4",
+ "address": "0xB716b6a92B77cDF2c5d0fd46eba05838E30f77c1",
"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": [
@@ -273,6 +299,19 @@
"name": "StrategistUpdated",
"type": "event"
},
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "strategy",
+ "type": "address"
+ }
+ ],
+ "name": "StrategyAddedToMintWhitelist",
+ "type": "event"
+ },
{
"anonymous": false,
"inputs": [
@@ -299,6 +338,19 @@
"name": "StrategyRemoved",
"type": "event"
},
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "strategy",
+ "type": "address"
+ }
+ ],
+ "name": "StrategyRemovedFromMintWhitelist",
+ "type": "event"
+ },
{
"anonymous": false,
"inputs": [
@@ -414,6 +466,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 +570,26 @@
"stateMutability": "nonpayable",
"type": "fallback"
},
+ {
+ "inputs": [],
+ "name": "CLAIM_DELAY",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "addWithdrawalQueueLiquidity",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
{
"inputs": [],
"name": "allocate",
@@ -560,6 +707,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",
@@ -697,6 +900,25 @@
"stateMutability": "view",
"type": "function"
},
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "name": "isMintWhitelistedStrategy",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
{
"inputs": [
{
@@ -932,6 +1154,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 +1294,122 @@
],
"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": "uint40",
+ "name": "timestamp",
+ "type": "uint40"
+ },
+ {
+ "internalType": "uint128",
+ "name": "amount",
+ "type": "uint128"
+ },
+ {
+ "internalType": "uint128",
+ "name": "queued",
+ "type": "uint128"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
}
],
- "transactionHash": "0x9f75d36ce4de616c56e32c5f1e66ea8b705994a63d163d096f71d3e5c1eecdc1",
+ "transactionHash": "0xa7ef8f7c6c56c6a647c28edb108e77bd303ade4700393a072598e209ffe63efb",
"receipt": {
"to": null,
"from": "0x1b94CA50D3Ad9f8368851F8526132272d1a5028C",
- "contractAddress": "0xE92e25B81E44B8377Df1362f8fFBc426A00d6ef4",
- "transactionIndex": 68,
- "gasUsed": "3024025",
- "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000020000000000000000000800000000000000000000000000000000000004000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000010000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000080000000000000",
- "blockHash": "0xf2aa29665c1af068ced76d7b539f3bcc67a7d534c1019c51316beecb731cbc01",
- "transactionHash": "0x9f75d36ce4de616c56e32c5f1e66ea8b705994a63d163d096f71d3e5c1eecdc1",
+ "contractAddress": "0xB716b6a92B77cDF2c5d0fd46eba05838E30f77c1",
+ "transactionIndex": 6,
+ "gasUsed": "3917277",
+ "logsBloom": "0x00000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000004000000020000002000000000000000000040000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000010000000000010000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000",
+ "blockHash": "0x1ebb1db8f440bf2959484a8c243d32d9101917ab068d585302f62b04b11d255a",
+ "transactionHash": "0xa7ef8f7c6c56c6a647c28edb108e77bd303ade4700393a072598e209ffe63efb",
"logs": [
{
- "transactionIndex": 68,
- "blockNumber": 1405063,
- "transactionHash": "0x9f75d36ce4de616c56e32c5f1e66ea8b705994a63d163d096f71d3e5c1eecdc1",
- "address": "0xE92e25B81E44B8377Df1362f8fFBc426A00d6ef4",
+ "transactionIndex": 6,
+ "blockNumber": 2037161,
+ "transactionHash": "0xa7ef8f7c6c56c6a647c28edb108e77bd303ade4700393a072598e209ffe63efb",
+ "address": "0xB716b6a92B77cDF2c5d0fd46eba05838E30f77c1",
"topics": [
"0xc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a",
"0x0000000000000000000000000000000000000000000000000000000000000000",
"0x0000000000000000000000001b94ca50d3ad9f8368851f8526132272d1a5028c"
],
"data": "0x",
- "logIndex": 80,
- "blockHash": "0xf2aa29665c1af068ced76d7b539f3bcc67a7d534c1019c51316beecb731cbc01"
+ "logIndex": 6,
+ "blockHash": "0x1ebb1db8f440bf2959484a8c243d32d9101917ab068d585302f62b04b11d255a"
}
],
- "blockNumber": 1405063,
- "cumulativeGasUsed": "14256235",
+ "blockNumber": 2037161,
+ "cumulativeGasUsed": "4247006",
"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": 3,
+ "solcInputHash": "0d24aafc2e05d7bcc2007c274421d881",
+ "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\":true,\"internalType\":\"address\",\"name\":\"strategy\",\"type\":\"address\"}],\"name\":\"StrategyAddedToMintWhitelist\",\"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\":true,\"internalType\":\"address\",\"name\":\"strategy\",\"type\":\"address\"}],\"name\":\"StrategyRemovedFromMintWhitelist\",\"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\":\"CLAIM_DELAY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"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\":\"\",\"type\":\"address\"}],\"name\":\"isMintWhitelistedStrategy\",\"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\":\"uint40\",\"name\":\"timestamp\",\"type\":\"uint40\"},{\"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\",\"totalAmount\":\"Total amount of WETH transferred to the withdrawer\"}},\"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 OETH to burn.\",\"queued\":\"Cumulative total of all WETH queued including already claimed requests.\",\"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. 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.\"},\"claimWithdrawals(uint256[])\":{\"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`.\"},\"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 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.\"},\"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.\"},\"withdrawalQueueMetadata()\":{\"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\"},\"withdrawalRequests(uint256)\":{\"notice\":\"Mapping of withdrawal request indices to the user withdrawal request data\"}},\"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/SafeCast.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeCast.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow\\n * checks.\\n *\\n * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can\\n * easily result in undesired exploitation or bugs, since developers usually\\n * assume that overflows raise errors. `SafeCast` restores this intuition by\\n * reverting the transaction when such an operation overflows.\\n *\\n * Using this library instead of the unchecked operations eliminates an entire\\n * class of bugs, so it's recommended to use it always.\\n *\\n * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing\\n * all math on `uint256` and `int256` and then downcasting.\\n */\\nlibrary SafeCast {\\n /**\\n * @dev Returns the downcasted uint224 from uint256, reverting on\\n * overflow (when the input is greater than largest uint224).\\n *\\n * Counterpart to Solidity's `uint224` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 224 bits\\n */\\n function toUint224(uint256 value) internal pure returns (uint224) {\\n require(value <= type(uint224).max, \\\"SafeCast: value doesn't fit in 224 bits\\\");\\n return uint224(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint128 from uint256, reverting on\\n * overflow (when the input is greater than largest uint128).\\n *\\n * Counterpart to Solidity's `uint128` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 128 bits\\n */\\n function toUint128(uint256 value) internal pure returns (uint128) {\\n require(value <= type(uint128).max, \\\"SafeCast: value doesn't fit in 128 bits\\\");\\n return uint128(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint96 from uint256, reverting on\\n * overflow (when the input is greater than largest uint96).\\n *\\n * Counterpart to Solidity's `uint96` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 96 bits\\n */\\n function toUint96(uint256 value) internal pure returns (uint96) {\\n require(value <= type(uint96).max, \\\"SafeCast: value doesn't fit in 96 bits\\\");\\n return uint96(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint64 from uint256, reverting on\\n * overflow (when the input is greater than largest uint64).\\n *\\n * Counterpart to Solidity's `uint64` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 64 bits\\n */\\n function toUint64(uint256 value) internal pure returns (uint64) {\\n require(value <= type(uint64).max, \\\"SafeCast: value doesn't fit in 64 bits\\\");\\n return uint64(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint32 from uint256, reverting on\\n * overflow (when the input is greater than largest uint32).\\n *\\n * Counterpart to Solidity's `uint32` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 32 bits\\n */\\n function toUint32(uint256 value) internal pure returns (uint32) {\\n require(value <= type(uint32).max, \\\"SafeCast: value doesn't fit in 32 bits\\\");\\n return uint32(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint16 from uint256, reverting on\\n * overflow (when the input is greater than largest uint16).\\n *\\n * Counterpart to Solidity's `uint16` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 16 bits\\n */\\n function toUint16(uint256 value) internal pure returns (uint16) {\\n require(value <= type(uint16).max, \\\"SafeCast: value doesn't fit in 16 bits\\\");\\n return uint16(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint8 from uint256, reverting on\\n * overflow (when the input is greater than largest uint8).\\n *\\n * Counterpart to Solidity's `uint8` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 8 bits.\\n */\\n function toUint8(uint256 value) internal pure returns (uint8) {\\n require(value <= type(uint8).max, \\\"SafeCast: value doesn't fit in 8 bits\\\");\\n return uint8(value);\\n }\\n\\n /**\\n * @dev Converts a signed int256 into an unsigned uint256.\\n *\\n * Requirements:\\n *\\n * - input must be greater than or equal to 0.\\n */\\n function toUint256(int256 value) internal pure returns (uint256) {\\n require(value >= 0, \\\"SafeCast: value must be positive\\\");\\n return uint256(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted int128 from int256, reverting on\\n * overflow (when the input is less than smallest int128 or\\n * greater than largest int128).\\n *\\n * Counterpart to Solidity's `int128` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 128 bits\\n *\\n * _Available since v3.1._\\n */\\n function toInt128(int256 value) internal pure returns (int128) {\\n require(value >= type(int128).min && value <= type(int128).max, \\\"SafeCast: value doesn't fit in 128 bits\\\");\\n return int128(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted int64 from int256, reverting on\\n * overflow (when the input is less than smallest int64 or\\n * greater than largest int64).\\n *\\n * Counterpart to Solidity's `int64` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 64 bits\\n *\\n * _Available since v3.1._\\n */\\n function toInt64(int256 value) internal pure returns (int64) {\\n require(value >= type(int64).min && value <= type(int64).max, \\\"SafeCast: value doesn't fit in 64 bits\\\");\\n return int64(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted int32 from int256, reverting on\\n * overflow (when the input is less than smallest int32 or\\n * greater than largest int32).\\n *\\n * Counterpart to Solidity's `int32` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 32 bits\\n *\\n * _Available since v3.1._\\n */\\n function toInt32(int256 value) internal pure returns (int32) {\\n require(value >= type(int32).min && value <= type(int32).max, \\\"SafeCast: value doesn't fit in 32 bits\\\");\\n return int32(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted int16 from int256, reverting on\\n * overflow (when the input is less than smallest int16 or\\n * greater than largest int16).\\n *\\n * Counterpart to Solidity's `int16` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 16 bits\\n *\\n * _Available since v3.1._\\n */\\n function toInt16(int256 value) internal pure returns (int16) {\\n require(value >= type(int16).min && value <= type(int16).max, \\\"SafeCast: value doesn't fit in 16 bits\\\");\\n return int16(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted int8 from int256, reverting on\\n * overflow (when the input is less than smallest int8 or\\n * greater than largest int8).\\n *\\n * Counterpart to Solidity's `int8` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 8 bits.\\n *\\n * _Available since v3.1._\\n */\\n function toInt8(int256 value) internal pure returns (int8) {\\n require(value >= type(int8).min && value <= type(int8).max, \\\"SafeCast: value doesn't fit in 8 bits\\\");\\n return int8(value);\\n }\\n\\n /**\\n * @dev Converts an unsigned uint256 into a signed int256.\\n *\\n * Requirements:\\n *\\n * - input must be less than or equal to maxInt256.\\n */\\n function toInt256(uint256 value) internal pure returns (int256) {\\n // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\\n require(value <= uint256(type(int256).max), \\\"SafeCast: value doesn't fit in an int256\\\");\\n return int256(value);\\n }\\n}\\n\",\"keccak256\":\"0x5c6caab697d302ad7eb59c234a4d2dbc965c1bae87709bd2850060b7695b28c7\",\"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 /// @notice 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;\\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) external;\\n}\\n\",\"keccak256\":\"0xf160a884d11a9e38ab14d504aa0c3318e78244e4d4c37b555658e0dbbe42c1ce\",\"license\":\"MIT\"},\"contracts/interfaces/IGetExchangeRateToken.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IGetExchangeRateToken {\\n function getExchangeRate() external view returns (uint256 _exchangeRate);\\n}\\n\",\"keccak256\":\"0x243be4dffe1eb453d25cae22b6c172bb64c574d80943cef058fdc30a4b9c9bfd\",\"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/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 { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport { IERC20 } from \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport { SafeCast } from \\\"@openzeppelin/contracts/utils/math/SafeCast.sol\\\";\\n\\nimport { StableMath } from \\\"../utils/StableMath.sol\\\";\\nimport { VaultCore } from \\\"./VaultCore.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 uint256 public constant CLAIM_DELAY = 10 minutes;\\n address public immutable weth;\\n uint256 public wethAssetIndex;\\n\\n // For future use (because OETHBaseVaultCore inherits from this)\\n uint256[50] private __gap;\\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 // Is there enough WETH in the Vault available after accounting for the withdrawal queue\\n require(_wethAvailable() >= amountMinusFee, \\\"Liquidity error\\\");\\n\\n // Transfer WETH minus the fee to the redeemer\\n IERC20(weth).safeTransfer(msg.sender, amountMinusFee);\\n\\n // Burn OETH from user (including fees)\\n oUSD.burn(msg.sender, _amount);\\n\\n // Prevent insolvency\\n _postRedeem(_amount);\\n }\\n\\n /**\\n * @notice Request an asynchronous withdrawal of WETH in exchange for OETH.\\n * The OETH is burned on request and the WETH is transferred to the withdrawer on claim.\\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 * There is no minimum time or block number before a request can be claimed. It just needs\\n * enough WETH liquidity in the Vault to satisfy all the outstanding requests to that point in the queue.\\n * OETH is converted to WETH at 1:1.\\n * @param _amount Amount of OETH to burn.\\n * @param requestId Unique ID for the withdrawal request\\n * @param queued Cumulative total of all WETH queued including already claimed requests.\\n */\\n function requestWithdrawal(uint256 _amount)\\n external\\n whenNotCapitalPaused\\n nonReentrant\\n returns (uint256 requestId, uint256 queued)\\n {\\n // The check that the requester has enough OETH is done in to later burn call\\n\\n requestId = withdrawalQueueMetadata.nextWithdrawalIndex;\\n queued = withdrawalQueueMetadata.queued + _amount;\\n\\n // Store the next withdrawal request\\n withdrawalQueueMetadata.nextWithdrawalIndex = SafeCast.toUint128(\\n requestId + 1\\n );\\n // Store the updated queued amount which reserves WETH in the withdrawal queue\\n // and reduces the vault's total assets\\n withdrawalQueueMetadata.queued = SafeCast.toUint128(queued);\\n // Store the user's withdrawal request\\n withdrawalRequests[requestId] = WithdrawalRequest({\\n withdrawer: msg.sender,\\n claimed: false,\\n timestamp: uint40(block.timestamp),\\n amount: SafeCast.toUint128(_amount),\\n queued: SafeCast.toUint128(queued)\\n });\\n\\n // Burn the user's OETH\\n oUSD.burn(msg.sender, _amount);\\n\\n // Prevent withdrawal if the vault is solvent by more than the the allowed percentage\\n _postRedeem(_amount);\\n\\n emit WithdrawalRequested(msg.sender, requestId, _amount, queued);\\n }\\n\\n // slither-disable-start reentrancy-no-eth\\n /**\\n * @notice Claim a previously requested withdrawal once it is claimable.\\n * This request can be claimed once the withdrawal queue's `claimable` amount\\n * is greater than or equal this request's `queued` amount and 10 minutes has passed.\\n * If the requests is not claimable, the transaction will revert with `Queue pending liquidity`.\\n * If the request is not older than 10 minutes, the transaction will revert with `Claim delay not met`.\\n * OETH is converted to WETH at 1:1.\\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 // Try and get more liquidity if there is not enough available\\n if (\\n withdrawalRequests[_requestId].queued >\\n withdrawalQueueMetadata.claimable\\n ) {\\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 _addWithdrawalQueueLiquidity();\\n }\\n\\n amount = _claimWithdrawal(_requestId);\\n\\n // transfer WETH from the vault to the withdrawer\\n IERC20(weth).safeTransfer(msg.sender, amount);\\n\\n // Prevent insolvency\\n _postRedeem(amount);\\n }\\n\\n // slither-disable-end reentrancy-no-eth\\n\\n /**\\n * @notice Claim a previously requested withdrawals once they are claimable.\\n * This requests can be claimed once the withdrawal queue's `claimable` amount\\n * is greater than or equal each request's `queued` amount and 10 minutes has passed.\\n * If one of the requests is not claimable, the whole transaction will revert with `Queue pending liquidity`.\\n * If one of the requests is not older than 10 minutes,\\n * the whole transaction will revert with `Claim delay not met`.\\n * @param _requestIds Unique ID of each withdrawal request\\n * @return amounts Amount of WETH received for each request\\n * @return totalAmount Total amount of WETH transferred to the withdrawer\\n */\\n function claimWithdrawals(uint256[] memory _requestIds)\\n external\\n whenNotCapitalPaused\\n nonReentrant\\n returns (uint256[] memory amounts, uint256 totalAmount)\\n {\\n // Just call the Dripper instead of looping through _requestIds to find the highest id\\n // and checking it's queued amount is > the queue's claimable amount.\\n\\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 _addWithdrawalQueueLiquidity();\\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 // Prevent insolvency\\n _postRedeem(totalAmount);\\n }\\n\\n function _claimWithdrawal(uint256 requestId)\\n internal\\n returns (uint256 amount)\\n {\\n // Load the structs from storage into memory\\n WithdrawalRequest memory request = withdrawalRequests[requestId];\\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\\n\\n require(\\n request.timestamp + CLAIM_DELAY <= block.timestamp,\\n \\\"Claim delay not met\\\"\\n );\\n // If there isn't enough reserved liquidity in the queue to claim\\n require(request.queued <= queue.claimable, \\\"Queue pending liquidity\\\");\\n require(request.withdrawer == msg.sender, \\\"Not requester\\\");\\n require(request.claimed == false, \\\"Already claimed\\\");\\n\\n // Store the request as claimed\\n withdrawalRequests[requestId].claimed = true;\\n // Store the updated claimed amount\\n withdrawalQueueMetadata.claimed = queue.claimed + request.amount;\\n\\n emit WithdrawalClaimed(msg.sender, requestId, request.amount);\\n\\n return request.amount;\\n }\\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 /// This assumes 1 WETH equal 1 OETH.\\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 do anything is the withdrawal queue is full funded\\n if (queueShortfall == 0) {\\n return 0;\\n }\\n\\n uint256 wethBalance = IERC20(weth).balanceOf(address(this));\\n\\n // Of the claimable withdrawal requests, how much is unclaimed?\\n // That is, the amount of WETH that is currently allocated for the withdrawal queue\\n uint256 allocatedWeth = queue.claimable - queue.claimed;\\n\\n // If there is no unallocated WETH then there is nothing to add to the queue\\n if (wethBalance <= allocatedWeth) {\\n return 0;\\n }\\n\\n uint256 unallocatedWeth = wethBalance - allocatedWeth;\\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 = SafeCast.toUint128(newClaimable);\\n\\n // emit a WithdrawalClaimable event\\n emit WithdrawalClaimable(newClaimable, addedClaimable);\\n }\\n\\n /***************************************\\n View Functions\\n ****************************************/\\n\\n /// @dev Calculate how much WETH in the vault is not reserved for the withdrawal queue.\\n // That is, it is available to be redeemed or deposited into a strategy.\\n function _wethAvailable() internal view returns (uint256 wethAvailable) {\\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\\n\\n // The amount of WETH that is still to be claimed in the withdrawal queue\\n uint256 outstandingWithdrawals = queue.queued - queue.claimed;\\n\\n // The amount of sitting in WETH in the vault\\n uint256 wethBalance = IERC20(weth).balanceOf(address(this));\\n\\n // If there is not enough WETH in the vault to cover the outstanding withdrawals\\n if (wethBalance <= outstandingWithdrawals) {\\n return 0;\\n }\\n\\n return wethBalance - outstandingWithdrawals;\\n }\\n\\n /// @dev Get the balance of an asset held in Vault and all strategies\\n /// less any WETH that is reserved for the withdrawal queue.\\n /// This will only return a non-zero balance for WETH.\\n /// All other assets will return 0 even if there is some dust amounts left in the Vault.\\n /// For example, there is 1 wei left of stETH in the OETH Vault but will return 0 in this function.\\n ///\\n /// If there is not enough WETH in the vault and all strategies to cover all outstanding\\n /// withdrawal requests then return a WETH balance of 0\\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 if (balance + queue.claimed >= queue.queued) {\\n return balance + queue.claimed - queue.queued;\\n }\\n }\\n }\\n\\n /**\\n * @notice Allocate unallocated funds on Vault to strategies.\\n **/\\n function allocate() external override whenNotCapitalPaused nonReentrant {\\n // Add any unallocated WETH to the withdrawal queue first\\n _addWithdrawalQueueLiquidity();\\n\\n _allocate();\\n }\\n\\n /// @dev Allocate WETH to the default WETH strategy if there is excess to the Vault buffer.\\n /// This is called from either `mint` or `allocate` and assumes `_addWithdrawalQueueLiquidity`\\n /// has been called before this function.\\n function _allocate() internal override {\\n // No need to do anything if no default strategy for WETH\\n address depositStrategyAddr = assetDefaultStrategies[weth];\\n if (depositStrategyAddr == address(0)) return;\\n\\n uint256 wethAvailableInVault = _wethAvailable();\\n // No need to do anything if there isn't any WETH in the vault to allocate\\n if (wethAvailableInVault == 0) return;\\n\\n // Calculate the target buffer for the vault using the total supply\\n uint256 totalSupply = oUSD.totalSupply();\\n uint256 targetBuffer = totalSupply.mulTruncate(vaultBuffer);\\n\\n // If available WETH in the Vault is below or equal the target buffer then there's nothing to allocate\\n if (wethAvailableInVault <= targetBuffer) return;\\n\\n // The amount of assets to allocate to the default strategy\\n uint256 allocateAmount = wethAvailableInVault - targetBuffer;\\n\\n IStrategy strategy = IStrategy(depositStrategyAddr);\\n // Transfer WETH to the strategy and call the strategy's deposit function\\n IERC20(weth).safeTransfer(address(strategy), allocateAmount);\\n strategy.deposit(weth, allocateAmount);\\n\\n emit AssetAllocated(weth, depositStrategyAddr, allocateAmount);\\n }\\n\\n /// @dev The total value of all assets held by the vault and all its strategies\\n /// less any WETH that is reserved for the withdrawal queue.\\n /// For OETH, this is just WETH in the vault and strategies.\\n ///\\n // If there is not enough WETH in the vault and all strategies to cover all outstanding\\n // withdrawal requests then return a total value of 0.\\n function _totalValue() internal view override returns (uint256 value) {\\n value = _totalValueInVault() + _totalValueInStrategies();\\n\\n // Need to remove WETH that is reserved for the withdrawal queue.\\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\\n // reserved for the withdrawal queue = cumulative queued total - total claimed\\n uint256 reservedForQueue = queue.queued - queue.claimed;\\n\\n if (value < reservedForQueue) {\\n // This can happen if the vault becomes insolvent enough that the\\n // total value in the vault and all strategies is less than the outstanding withdrawals.\\n // For example, there was a mass slashing event and most users request a withdrawal.\\n return 0;\\n }\\n\\n // Adjust the total value by the amount reserved for the withdrawal queue\\n return value - reservedForQueue;\\n }\\n\\n /// @dev Only WETH is supported in the OETH Vault so return the WETH balance only\\n /// Any ETH balances in the Vault will be ignored.\\n /// Amounts from previously supported vault assets will also be ignored.\\n /// For example, there is 1 wei left of stETH in the OETH Vault but is will be ignored.\\n function _totalValueInVault()\\n internal\\n view\\n override\\n returns (uint256 value)\\n {\\n value = IERC20(weth).balanceOf(address(this));\\n }\\n}\\n\",\"keccak256\":\"0x298a1268faefc59f2b88d30960e1ccb5e1813fef1565aa3518efc2b79eefd6f0\",\"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 virtual\\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 // If there are more outstanding withdrawal requests than assets in the vault and strategies\\n // then the available assets will be negative and totalUnits will be rounded up to zero.\\n // As we don't know the exact shortfall amount, we will reject all redeem and withdrawals\\n require(totalUnits > 0, \\\"Too many outstanding requests\\\");\\n\\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 virtual\\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 virtual 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\":\"0xc24c3d13d928167a456460c0aac44e364b6b76522a701fd3e2afca55394c2799\",\"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 StrategyAddedToMintWhitelist(address indexed strategy);\\n event StrategyRemovedFromMintWhitelist(address indexed strategy);\\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 // slither-disable-next-line uninitialized-state\\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\\n // slither-disable-start constable-states\\n // slither-disable-next-line uninitialized-state\\n address public ousdMetaStrategy;\\n\\n /// @notice How much OTokens are currently minted by the strategy\\n // slither-disable-next-line uninitialized-state\\n int256 public netOusdMintedForStrategy;\\n\\n /// @notice How much net total OTokens are allowed to be minted by all strategies\\n // slither-disable-next-line uninitialized-state\\n uint256 public netOusdMintForStrategyThreshold;\\n\\n // slither-disable-end constable-states\\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 // List of strategies that can mint oTokens directly\\n // Used in OETHBaseVaultCore\\n // slither-disable-next-line uninitialized-state\\n mapping(address => bool) public isMintWhitelistedStrategy;\\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 including 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 /// @notice Global metadata for the withdrawal queue including:\\n /// queued - cumulative total of all withdrawal requests included the ones that have already been claimed\\n /// claimable - cumulative total of all the requests that can be claimed including the ones already claimed\\n /// claimed - total of all the requests that have been claimed\\n /// nextWithdrawalIndex - index of the next withdrawal request starting at 0\\n // slither-disable-next-line uninitialized-state\\n WithdrawalQueueMetadata public withdrawalQueueMetadata;\\n\\n struct WithdrawalRequest {\\n address withdrawer;\\n bool claimed;\\n uint40 timestamp; // timestamp of the withdrawal request\\n // Amount of oTokens to redeem. eg OETH\\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 /// @notice Mapping of withdrawal request indices to the user withdrawal request data\\n mapping(uint256 => WithdrawalRequest) public withdrawalRequests;\\n\\n // For future use\\n uint256[45] 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\":\"0x7f33ab25581ef4eabd8c2e3bc7dd88ff397acb95c59c7eaf1352173d8f651d6e\",\"license\":\"MIT\"}},\"version\":1}",
+ "bytecode": "0x6037805461ffff60a01b1916600160a81b179055603d80546001600160a01b0319908116909155603e805482169055603f8054909116905560e0604052600060a081905260c052604880546001600160b01b03191690553480156200006357600080fd5b50604051620046b2380380620046b28339810160408190526200008691620000fc565b6200009e336000805160206200469283398151915255565b60008051602062004692833981519152546040516001600160a01b03909116906000907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a360601b6001600160601b0319166080526200012e565b6000602082840312156200010f57600080fd5b81516001600160a01b03811681146200012757600080fd5b9392505050565b60805160601c6144dc620001b66000396000818161044101528181610961015281816109d401528181610e2601528181611a5601528181611b340152818161235001528181612a3301528181612b6601528181612d7f01528181612e8601528181612f9501528181612fe00152818161304801528181613845015261397201526144dc6000f3fe608060405234801561001057600080fd5b50600436106102f15760003560e01c806367bd7ba31161019d578063abaa9916116100e9578063d38bfff4116100a2578063e45cc9f01161007c578063e45cc9f014610792578063e6cc54321461079b578063f8444436146107af578063fc0cfeee146107c2576102f1565b8063d38bfff41461076e578063d4c3eea014610781578063e18132c414610789576102f1565b8063abaa991614610733578063af14052c1461073b578063b888879e14610743578063b9b17f9f14610756578063c3b288641461075e578063c7af335214610766576102f1565b8063937b2581116101565780639fa1826e116101305780639fa1826e146106e6578063a0aead4d146106ef578063a403e4d5146106f7578063ab80dafb14610720576102f1565b8063937b2581146105ea5780639be918e6146106925780639ee679e8146106be576102f1565b806367bd7ba3146105725780636ec3ab67146105925780637136a7a6146105b25780637a2202f3146105c55780637cbc2373146105ce5780638e510b52146105e1576102f1565b80634530820a1161025c57806354c6d858116102155780635d36b190116101ef5780635d36b190146105315780635f51522614610539578063603ea03b1461054c5780636217f3ea1461055f576102f1565b806354c6d85814610502578063570d8e1d1461050b5780635b60f9fc1461051e576102f1565b80634530820a1461046b578063485cc9551461049e57806348e30f54146104b157806349c1d54d146104d257806352d38e5d146104e557806353ca9f24146104ee576102f1565b80632acada4d116102ae5780632acada4d146103ad57806331e19cfa146103c2578063362bd1a3146103ca5780633b8fe28d146104295780633fc8cef31461043c57806344c5470714610463576102f1565b806309f6442c146103375780630c340a2414610353578063156e29f61461037357806318ce56bd146103885780631edfe3da1461039b578063207134b0146103a4575b7fa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd9366000803760008036600084545af43d6000803e808015610332573d6000f35b3d6000fd5b61034060385481565b6040519081526020015b60405180910390f35b61035b6107d5565b6040516001600160a01b03909116815260200161034a565b610386610381366004613d9f565b6107f2565b005b60455461035b906001600160a01b031681565b61034060395481565b61034060435481565b6103b5610870565b60405161034a9190613f7d565b603654610340565b604b54604c546103f6916001600160801b0380821692600160801b928390048216928183169291041684565b604080516001600160801b039586168152938516602085015291841691830191909152909116606082015260800161034a565b610340610437366004613d51565b6108d2565b61035b7f000000000000000000000000000000000000000000000000000000000000000081565b61038661092d565b61048e610479366004613d51565b60496020526000908152604090205460ff1681565b604051901515815260200161034a565b6103866104ac366004613d6c565b610a76565b6104c46104bf366004613dd2565b610c78565b60405161034a929190613fdd565b60425461035b906001600160a01b031681565b610340603b5481565b60375461048e90600160a01b900460ff1681565b610340607b5481565b603f5461035b906001600160a01b031681565b61034061052c366004613d51565b610e61565b610386610e8a565b610340610547366004613d51565b610f30565b604a5461035b906001600160a01b031681565b61038661056d366004613eb9565b610f41565b610585610580366004613eb9565b6110d8565b60405161034a9190613fca565b6105a56105a0366004613d51565b6110e3565b60405161034a9190614126565b6103866105c0366004613eb9565b611189565b61034060475481565b6103866105dc366004613eeb565b611274565b61034060415481565b61064b6105f8366004613eb9565b604d60205260009081526040902080546001909101546001600160a01b03821691600160a01b810460ff1691600160a81b90910464ffffffffff16906001600160801b0380821691600160801b90041685565b604080516001600160a01b039096168652931515602086015264ffffffffff909216928401929092526001600160801b03918216606084015216608082015260a00161034a565b61048e6106a0366004613d51565b6001600160a01b031660009081526033602052604090205460ff1690565b6106d16106cc366004613eb9565b6112e7565b6040805192835260208301919091520161034a565b610340603a5481565b603454610340565b61035b610705366004613d51565b6040602081905260009182529020546001600160a01b031681565b61038661072e366004613eb9565b611552565b6103866116c9565b610386611741565b60375461035b906001600160a01b031681565b610386611787565b6103b56117f7565b61048e611857565b61038661077c366004613d51565b611888565b61034061192c565b61034061025881565b61034060465481565b60375461048e90600160a81b900460ff1681565b6103406107bd366004613eb9565b611936565b6103866107d0366004613d51565b611a90565b60006107ed6000805160206144878339815191525490565b905090565b603754600160a81b900460ff16156108255760405162461bcd60e51b815260040161081c906140d6565b60405180910390fd5b600080516020614467833981519152805460028114156108575760405162461bcd60e51b815260040161081c906140fe565b60028255610866858585611b32565b5060019055505050565b606060348054806020026020016040519081016040528092919081815260200182805480156108c857602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116108aa575b5050505050905090565b6000806108fb6108f56108e485611db3565b670de0b6b3a7640000906012611e1d565b84611e7f565b9050670de0b6b3a764000081610912856001611fdb565b61091c919061430d565b6109269190614200565b9392505050565b610935611857565b6109515760405162461bcd60e51b815260040161081c90614076565b60345460005b818110156109d1577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166034828154811061099c5761099c61443a565b6000918252602090912001546001600160a01b031614156109c157607b8190556109d1565b6109ca816143d6565b9050610957565b507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166034607b5481548110610a1157610a1161443a565b6000918252602090912001546001600160a01b031614610a735760405162461bcd60e51b815260206004820152601860248201527f496e76616c6964205745544820417373657420496e6465780000000000000000604482015260640161081c565b50565b610a7e611857565b610a9a5760405162461bcd60e51b815260040161081c90614076565b600054610100900460ff1680610ab3575060005460ff16155b610b165760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161081c565b600054610100900460ff16158015610b38576000805461ffff19166101011790555b6001600160a01b038316610b8e5760405162461bcd60e51b815260206004820152601d60248201527f507269636550726f76696465722061646472657373206973207a65726f000000604482015260640161081c565b6001600160a01b038216610bdd5760405162461bcd60e51b81526020600482015260166024820152756f546f6b656e2061646472657373206973207a65726f60501b604482015260640161081c565b603c80546001600160a01b038481166001600160a01b031990921691909117909155603780546001600160b01b03191691851691909117600160a81b17905560006038819055603981905569054b40b1f852bda00000603a55683635c9adc5dea00000603b556040805191825260208201908190529051610c6091603691613cc9565b508015610c73576000805461ff00191690555b505050565b603754606090600090600160a81b900460ff1615610ca85760405162461bcd60e51b815260040161081c906140d6565b60008051602061446783398151915280546002811415610cda5760405162461bcd60e51b815260040161081c906140fe565b60028255604a60009054906101000a90046001600160a01b03166001600160a01b031663e52253816040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610d2e57600080fd5b505af1158015610d42573d6000803e3d6000fd5b50505050610d4e6122cd565b50845167ffffffffffffffff811115610d6957610d69614450565b604051908082528060200260200182016040528015610d92578160200160208202803683370190505b50935060005b8551811015610e1857610dc3868281518110610db657610db661443a565b60200260200101516124b5565b858281518110610dd557610dd561443a565b602002602001018181525050848181518110610df357610df361443a565b602002602001015184610e0691906141e8565b9350610e11816143d6565b9050610d98565b50610e4d6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163385612757565b610e56836127ad565b600182555050915091565b600080610e736108f56108e485611db3565b9050670de0b6b3a764000081610912856000611fdb565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614610f255760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b606482015260840161081c565b610f2e33612963565b565b6000610f3b82612a24565b92915050565b603754600160a81b900460ff1615610f6b5760405162461bcd60e51b815260040161081c906140d6565b6045546001600160a01b03163314610f955760405162461bcd60e51b815260040161081c90614032565b6001600160ff1b038110610fbb5760405162461bcd60e51b815260040161081c906140ad565b7f222838db2794d11532d940e8dec38ae307ed0b63cd97c233322e221f998767a63382604051610fec929190613f64565b60405180910390a18060466000828254611006919061432c565b909155505060475460465461101a90612aeb565b106110715760405162461bcd60e51b815260206004820152602160248201527f417474656d7074696e6720746f206275726e20746f6f206d756368204f5553446044820152601760f91b606482015260840161081c565b603c54604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac906110a39033908590600401613f64565b600060405180830381600087803b1580156110bd57600080fd5b505af11580156110d1573d6000803e3d6000fd5b5050505050565b6060610f3b82612b2e565b604080516080808201835260008083526020808401829052838501829052606084018290526001600160a01b038616825260338152908490208451928301909452835460ff80821615158452939492939184019161010090910416600181111561114f5761114f614424565b600181111561116057611160614424565b8152905462010000810460ff1660208301526301000000900461ffff1660409091015292915050565b603754600160a81b900460ff16156111b35760405162461bcd60e51b815260040161081c906140d6565b600080516020614467833981519152805460028114156111e55760405162461bcd60e51b815260040161081c906140fe565b60028255603c546040516370a0823160e01b815233600482015261126c916001600160a01b0316906370a082319060240160206040518083038186803b15801561122e57600080fd5b505afa158015611242573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112669190613ed2565b84612c6f565b506001905550565b603754600160a81b900460ff161561129e5760405162461bcd60e51b815260040161081c906140d6565b600080516020614467833981519152805460028114156112d05760405162461bcd60e51b815260040161081c906140fe565b600282556112de8484612c6f565b50600190555050565b6037546000908190600160a81b900460ff16156113165760405162461bcd60e51b815260040161081c906140d6565b600080516020614467833981519152805460028114156113485760405162461bcd60e51b815260040161081c906140fe565b60028255604c54604b546001600160801b03600160801b90920482169550611372918791166141e8565b92506113876113828560016141e8565b612e13565b604c80546001600160801b03928316600160801b0292169190911790556113ad83612e13565b604b80546001600160801b0319166001600160801b03929092169190911790556040805160a081018252338152600060208201524264ffffffffff1691810191909152606081016113fd87612e13565b6001600160801b0316815260200161141485612e13565b6001600160801b039081169091526000868152604d602090815260409182902084518154928601518685015164ffffffffff16600160a81b0264ffffffffff60a81b19911515600160a01b026001600160a81b03199095166001600160a01b0393841617949094171692909217815560608501516080909501518416600160801b029490931693909317600190920191909155603c549051632770a7eb60e21b8152911690639dc29fac906114cf9033908990600401613f64565b600060405180830381600087803b1580156114e957600080fd5b505af11580156114fd573d6000803e3d6000fd5b5050505061150a856127ad565b6040805186815260208101859052859133917f38e3d972947cfef94205163d483d6287ef27eb312e20cb8e0b13a49989db232e910160405180910390a3600182555050915091565b603754600160a81b900460ff161561157c5760405162461bcd60e51b815260040161081c906140d6565b6045546001600160a01b031633146115a65760405162461bcd60e51b815260040161081c90614032565b6001600160ff1b0381106115cc5760405162461bcd60e51b815260040161081c906140ad565b7f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d412139688533826040516115fd929190613f64565b60405180910390a18060466000828254611617919061417c565b909155505060475460465461162b90612aeb565b106116975760405162461bcd60e51b815260206004820152603660248201527f4d696e746564206f75736420737572706173736564206e65744f7573644d696e6044820152753a2337b929ba3930ba32b3bcaa343932b9b437b6321760511b606482015260840161081c565b603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f19906110a39033908590600401613f64565b603754600160a81b900460ff16156116f35760405162461bcd60e51b815260040161081c906140d6565b600080516020614467833981519152805460028114156117255760405162461bcd60e51b815260040161081c906140fe565b600282556117316122cd565b5061173a612e7c565b5060019055565b600080516020614467833981519152805460028114156117735760405162461bcd60e51b815260040161081c906140fe565b6002825561177f6130b0565b505060019055565b604a60009054906101000a90046001600160a01b03166001600160a01b031663e52253816040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156117d757600080fd5b505af11580156117eb573d6000803e3d6000fd5b50505050610a736122cd565b606060368054806020026020016040519081016040528092919081815260200182805480156108c8576020028201919060005260206000209081546001600160a01b031681526001909101906020018083116108aa575050505050905090565b600061186f6000805160206144878339815191525490565b6001600160a01b0316336001600160a01b031614905090565b611890611857565b6118ac5760405162461bcd60e51b815260040161081c90614076565b6118d4817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166118f46000805160206144878339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b60006107ed6133eb565b603754600090600160a81b900460ff16156119635760405162461bcd60e51b815260040161081c906140d6565b600080516020614467833981519152805460028114156119955760405162461bcd60e51b815260040161081c906140fe565b60028255604b546000858152604d60205260409020600101546001600160801b03600160801b92839004811692909104161115611a3e57604a60009054906101000a90046001600160a01b03166001600160a01b031663e52253816040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611a1c57600080fd5b505af1158015611a30573d6000803e3d6000fd5b50505050611a3c6122cd565b505b611a47846124b5565b9250611a7d6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163385612757565b611a86836127ad565b5060019055919050565b611a98611857565b611ab45760405162461bcd60e51b815260040161081c90614076565b803b611b0e5760405162461bcd60e51b8152602060048201526024808201527f6e657720696d706c656d656e746174696f6e206973206e6f74206120636f6e746044820152631c9858dd60e21b606482015260840161081c565b7fa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd955565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b031614611bb35760405162461bcd60e51b815260206004820152601d60248201527f556e737570706f7274656420617373657420666f72206d696e74696e67000000604482015260640161081c565b60008211611c035760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e2030000000604482015260640161081c565b80821015611c535760405162461bcd60e51b815260206004820152601e60248201527f4d696e7420616d6f756e74206c6f776572207468616e206d696e696d756d0000604482015260640161081c565b7f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d41213968853383604051611c84929190613f64565b60405180910390a1603754600160a01b900460ff16158015611ca85750603b548210155b15611d1f57604a60009054906101000a90046001600160a01b03166001600160a01b031663e52253816040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611cfd57600080fd5b505af1158015611d11573d6000803e3d6000fd5b50505050611d1d6130b0565b505b603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990611d519033908690600401613f64565b600060405180830381600087803b158015611d6b57600080fd5b505af1158015611d7f573d6000803e3d6000fd5b50611d99925050506001600160a01b038416333085613485565b611da16122cd565b50603a548210610c7357610c73612e7c565b6001600160a01b03811660009081526033602052604090205462010000900460ff1680611e185760405162461bcd60e51b8152602060048201526013602482015272111958da5b585b1cc81b9bdd0818d858da1959606a1b604482015260640161081c565b919050565b600081831115611e4d57611e46611e348385614393565b611e3f90600a614265565b85906134c3565b9350611e77565b81831015611e7757611e74611e628484614393565b611e6d90600a614265565b85906134cf565b93505b509192915050565b6001600160a01b038116600090815260336020526040812054610100900460ff1681816001811115611eb357611eb3614424565b1415611ed757611ecf6012611ec785611db3565b869190611e1d565b915050610f3b565b6001816001811115611eeb57611eeb614424565b1415611f8c576000836001600160a01b031663e6aa216c6040518163ffffffff1660e01b815260040160206040518083038186803b158015611f2c57600080fd5b505afa158015611f40573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f649190613ed2565b9050670de0b6b3a7640000611f79828761430d565b611f839190614200565b92505050610f3b565b60405162461bcd60e51b815260206004820152601b60248201527f556e737570706f7274656420636f6e76657273696f6e20747970650000000000604482015260640161081c565b5092915050565b6001600160a01b038281166000818152603360205260408082205460375491516315d5220f60e31b81526004810194909452919361010090920460ff169291169063aea910789060240160206040518083038186803b15801561203d57600080fd5b505afa158015612051573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120759190613ed2565b9150600181600181111561208b5761208b614424565b141561212b576000846001600160a01b031663e6aa216c6040518163ffffffff1660e01b815260040160206040518083038186803b1580156120cc57600080fd5b505afa1580156120e0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121049190613ed2565b90508061211984670de0b6b3a764000061430d565b6121239190614200565b92505061218c565b600081600181111561213f5761213f614424565b1461218c5760405162461bcd60e51b815260206004820152601b60248201527f556e737570706f7274656420636f6e76657273696f6e20747970650000000000604482015260640161081c565b67120a871cc00200008211156121e45760405162461bcd60e51b815260206004820152601860248201527f5661756c743a2050726963652065786365656473206d61780000000000000000604482015260640161081c565b6709b6e64a8ec600008210156122355760405162461bcd60e51b81526020600482015260166024820152752b30bab63a1d10283934b1b2903ab73232b91036b4b760511b604482015260640161081c565b82156122ac57670de0b6b3a764000082111561225757670de0b6b3a764000091505b670dd99bb65dd700008210156122a75760405162461bcd60e51b815260206004820152601560248201527441737365742070726963652062656c6f772070656760581b604482015260640161081c565b611fd4565b670de0b6b3a7640000821015611fd45750670de0b6b3a76400009392505050565b60408051608081018252604b546001600160801b03808216808452600160801b92839004821660208501819052604c548084169686019690965292909404166060830152600092839161231f9161436b565b6001600160801b03169050806123385760009250505090565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561239a57600080fd5b505afa1580156123ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123d29190613ed2565b90506000836040015184602001516123ea919061436b565b6001600160801b0316905080821161240757600094505050505090565b60006124138284614393565b90508084106124225780612424565b835b955060008686602001516001600160801b031661244191906141e8565b905061244c81612e13565b604b80546001600160801b03928316600160801b0292169190911790556040517fee79a0c43d3993055690b54e074b5153e8bae8d1a872b656dedb64aa8f463333906124a49083908a90918252602082015260400190565b60405180910390a150505050505090565b6000818152604d60209081526040808320815160a08101835281546001600160a01b038116825260ff600160a01b82041615158286015264ffffffffff600160a81b90910481168285019081526001909301546001600160801b03808216606080860191909152600160801b92839004821660808087019190915287519081018852604b548084168252849004831698810198909852604c548083169789019790975291909504909416938501939093529051909291429161257b9161025891166141e8565b11156125bf5760405162461bcd60e51b815260206004820152601360248201527210db185a5b4819195b185e481b9bdd081b595d606a1b604482015260640161081c565b80602001516001600160801b031682608001516001600160801b031611156126295760405162461bcd60e51b815260206004820152601760248201527f51756575652070656e64696e67206c6971756964697479000000000000000000604482015260640161081c565b81516001600160a01b031633146126725760405162461bcd60e51b815260206004820152600d60248201526c2737ba103932b8bab2b9ba32b960991b604482015260640161081c565b6020820151156126b65760405162461bcd60e51b815260206004820152600f60248201526e105b1c9958591e4818db185a5b5959608a1b604482015260640161081c565b6000848152604d602052604090819020805460ff60a01b1916600160a01b1790556060830151908201516126ea91906141bd565b604c80546001600160801b0319166001600160801b03928316179055606083015160405191168152849033907f2d43eb174787155132b52ddb6b346e2dca99302eac3df4466dbeff953d3c84d19060200160405180910390a350606001516001600160801b031692915050565b610c738363a9059cbb60e01b8484604051602401612776929190613f64565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526134db565b6000603b5482101580156127cb5750603754600160a01b900460ff16155b156127df576127d86130b0565b90506127ea565b6127e76133eb565b90505b6041541561295f57600081116128425760405162461bcd60e51b815260206004820152601d60248201527f546f6f206d616e79206f75747374616e64696e67207265717565737473000000604482015260640161081c565b60006128d482603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561289657600080fd5b505afa1580156128aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128ce9190613ed2565b906135ad565b9050604154670de0b6b3a764000082116128ff576128fa82670de0b6b3a7640000614393565b612911565b612911670de0b6b3a764000083614393565b1115610c735760405162461bcd60e51b815260206004820152601e60248201527f4261636b696e6720737570706c79206c6971756964697479206572726f720000604482015260640161081c565b5050565b6001600160a01b0381166129b95760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f722069732061646472657373283029000000000000604482015260640161081c565b806001600160a01b03166129d96000805160206144878339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a3610a738160008051602061448783398151915255565b6000612a2f826135d6565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161415611e185760408051608081018252604b546001600160801b03808216808452600160801b9283900482166020850152604c54808316958501869052929092041660608301529091612ab890846141e8565b10612ae557805160408201516001600160801b0391821691612adb9116846141e8565b6109269190614393565b50919050565b60006001600160ff1b038212612b135760405162461bcd60e51b815260040161081c906140ad565b6000821215612b2a57612b25826143f1565b610f3b565b5090565b60385460609015612b5d57603854600090612b4d9084906127106137a5565b9050612b598184614393565b9250505b6000607b5490507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031660348281548110612ba157612ba161443a565b6000918252602090912001546001600160a01b031614612c035760405162461bcd60e51b815260206004820152601b60248201527f5745544820417373657420696e646578206e6f74206361636865640000000000604482015260640161081c565b60345467ffffffffffffffff811115612c1e57612c1e614450565b604051908082528060200260200182016040528015612c47578160200160208202803683370190505b50915082828281518110612c5d57612c5d61443a565b60200260200101818152505050919050565b7f222838db2794d11532d940e8dec38ae307ed0b63cd97c233322e221f998767a63383604051612ca0929190613f64565b60405180910390a181612cb1575050565b6000612cbc83612b2e565b607b5481518110612ccf57612ccf61443a565b6020026020010151905081811015612d295760405162461bcd60e51b815260206004820181905260248201527f52656465656d20616d6f756e74206c6f776572207468616e206d696e696d756d604482015260640161081c565b80612d326137c7565b1015612d725760405162461bcd60e51b815260206004820152600f60248201526e2634b8bab4b234ba3c9032b93937b960891b604482015260640161081c565b612da66001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163383612757565b603c54604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac90612dd89033908790600401613f64565b600060405180830381600087803b158015612df257600080fd5b505af1158015612e06573d6000803e3d6000fd5b50505050610c73836127ad565b60006001600160801b03821115612b2a5760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316044820152663238206269747360c81b606482015260840161081c565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166000908152604060208190529020541680612ebf5750565b6000612ec96137c7565b905080612ed4575050565b603c54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd916004808301926020929190829003018186803b158015612f1957600080fd5b505afa158015612f2d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f519190613ed2565b90506000612f6a603954836138e490919063ffffffff16565b9050808311612f795750505050565b6000612f858285614393565b905084612fbc6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168284612757565b6040516311f9fbc960e21b81526001600160a01b038216906347e7ef249061300a907f0000000000000000000000000000000000000000000000000000000000000000908690600401613f64565b600060405180830381600087803b15801561302457600080fd5b505af1158015613038573d6000803e3d6000fd5b5050604080516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811682528a1660208201529081018590527f41b99659f6ba0803f444aff29e5bf6e26dd86a3219aff92119d69710a956ba8d9250606001905060405180910390a1505050505050565b603754600090600160a01b900460ff16156130ff5760405162461bcd60e51b815260206004820152600f60248201526e149958985cda5b99c81c185d5cd959608a1b604482015260640161081c565b603c54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd916004808301926020929190829003018186803b15801561314457600080fd5b505afa158015613158573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061317c9190613ed2565b905060006131886133eb565b9050816131985791506133e89050565b6042546001600160a01b031680158015906131b257508282115b156132f45760006131c38484614393565b905060006131e0604354612710846137a59092919063ffffffff16565b905080821161323c5760405162461bcd60e51b815260206004820152602260248201527f466565206d757374206e6f742062652067726561746572207468616e207969656044820152611b1960f21b606482015260840161081c565b80156132a757603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f19906132749086908590600401613f64565b600060405180830381600087803b15801561328e57600080fd5b505af11580156132a2573d6000803e3d6000fd5b505050505b604080516001600160a01b0385168152602081018490529081018290527f09516ecf4a8a86e59780a9befc6dee948bc9e60a36e3be68d31ea817ee8d2c809060600160405180910390a150505b603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561334257600080fd5b505afa158015613356573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061337a9190613ed2565b9250828211156133e357603c546040516339a7919f60e01b8152600481018490526001600160a01b03909116906339a7919f90602401600060405180830381600087803b1580156133ca57600080fd5b505af11580156133de573d6000803e3d6000fd5b505050505b509150505b90565b60006133f56138f9565b6133fd61395a565b61340791906141e8565b60408051608081018252604b546001600160801b03808216808452600160801b9283900482166020850152604c5480831695850186905292909204166060830152929350916000916134589161436b565b6001600160801b03169050808310156134745760009250505090565b61347e8184614393565b9250505090565b6040516001600160a01b03808516602483015283166044820152606481018290526134bd9085906323b872dd60e01b90608401612776565b50505050565b6000610926828461430d565b60006109268284614200565b6000613530826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166139f49092919063ffffffff16565b805190915015610c73578080602001905181019061354e9190613e97565b610c735760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161081c565b6000806135c284670de0b6b3a76400006134c3565b90506135ce81846134cf565b949350505050565b6040516370a0823160e01b815230600482015260009082906001600160a01b038216906370a082319060240160206040518083038186803b15801561361a57600080fd5b505afa15801561362e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136529190613ed2565b60365490925060005b8181101561379d576000603682815481106136785761367861443a565b60009182526020909120015460405163551c457b60e11b81526001600160a01b0388811660048301529091169150819063aa388af69060240160206040518083038186803b1580156136c957600080fd5b505afa1580156136dd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137019190613e97565b1561378c57604051632fa8a91360e11b81526001600160a01b038781166004830152821690635f5152269060240160206040518083038186803b15801561374757600080fd5b505afa15801561375b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061377f9190613ed2565b61378990866141e8565b94505b50613796816143d6565b905061365b565b505050919050565b6000806137b285856134c3565b90506137be81846134cf565b95945050505050565b60408051608081018252604b546001600160801b03808216808452600160801b9283900482166020850152604c54808316958501869052929092041660608301526000928391613817919061436b565b6040516370a0823160e01b81523060048201526001600160801b039190911691506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a082319060240160206040518083038186803b15801561388757600080fd5b505afa15801561389b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138bf9190613ed2565b90508181116138d2576000935050505090565b6138dc8282614393565b935050505090565b60006109268383670de0b6b3a76400006137a5565b603654600090815b81811015613955576139396036828154811061391f5761391f61443a565b6000918252602090912001546001600160a01b0316613a03565b61394390846141e8565b925061394e816143d6565b9050613901565b505090565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b1580156139bc57600080fd5b505afa1580156139d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107ed9190613ed2565b60606135ce8484600085613b68565b6034546000908290825b8181101561379d57600060348281548110613a2a57613a2a61443a565b60009182526020909120015460405163551c457b60e11b81526001600160a01b039182166004820181905292509085169063aa388af69060240160206040518083038186803b158015613a7c57600080fd5b505afa158015613a90573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ab49190613e97565b15613b5757604051632fa8a91360e11b81526001600160a01b03828116600483015260009190861690635f5152269060240160206040518083038186803b158015613afe57600080fd5b505afa158015613b12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b369190613ed2565b90508015613b5557613b488183611e7f565b613b5290876141e8565b95505b505b50613b61816143d6565b9050613a0d565b606082471015613bc95760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161081c565b843b613c175760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161081c565b600080866001600160a01b03168587604051613c339190613f48565b60006040518083038185875af1925050503d8060008114613c70576040519150601f19603f3d011682016040523d82523d6000602084013e613c75565b606091505b5091509150613c85828286613c90565b979650505050505050565b60608315613c9f575081610926565b825115613caf5782518084602001fd5b8160405162461bcd60e51b815260040161081c9190613fff565b828054828255906000526020600020908101928215613d1e579160200282015b82811115613d1e57825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190613ce9565b50612b2a9291505b80821115612b2a5760008155600101613d26565b80356001600160a01b0381168114611e1857600080fd5b600060208284031215613d6357600080fd5b61092682613d3a565b60008060408385031215613d7f57600080fd5b613d8883613d3a565b9150613d9660208401613d3a565b90509250929050565b600080600060608486031215613db457600080fd5b613dbd84613d3a565b95602085013595506040909401359392505050565b60006020808385031215613de557600080fd5b823567ffffffffffffffff80821115613dfd57600080fd5b818501915085601f830112613e1157600080fd5b813581811115613e2357613e23614450565b8060051b604051601f19603f83011681018181108582111715613e4857613e48614450565b604052828152858101935084860182860187018a1015613e6757600080fd5b600095505b83861015613e8a578035855260019590950194938601938601613e6c565b5098975050505050505050565b600060208284031215613ea957600080fd5b8151801515811461092657600080fd5b600060208284031215613ecb57600080fd5b5035919050565b600060208284031215613ee457600080fd5b5051919050565b60008060408385031215613efe57600080fd5b50508035926020909101359150565b600081518084526020808501945080840160005b83811015613f3d57815187529582019590820190600101613f21565b509495945050505050565b60008251613f5a8184602087016143aa565b9190910192915050565b6001600160a01b03929092168252602082015260400190565b6020808252825182820181905260009190848201906040850190845b81811015613fbe5783516001600160a01b031683529284019291840191600101613f99565b50909695505050505050565b6020815260006109266020830184613f0d565b604081526000613ff06040830185613f0d565b90508260208301529392505050565b602081526000825180602084015261401e8160408501602087016143aa565b601f01601f19169190910160400192915050565b60208082526024908201527f43616c6c6572206973206e6f7420746865204f555344206d65746120737472616040820152637465677960e01b606082015260800190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b6020808252600f908201526e082dadeeadce840e8dede40d0d2ced608b1b604082015260600190565b6020808252600e908201526d10d85c1a5d185b081c185d5cd95960921b604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b815115158152602082015160808201906002811061415457634e487b7160e01b600052602160045260246000fd5b8060208401525060ff604084015116604083015261ffff606084015116606083015292915050565b600080821280156001600160ff1b038490038513161561419e5761419e61440e565b600160ff1b83900384128116156141b7576141b761440e565b50500190565b60006001600160801b038083168185168083038211156141df576141df61440e565b01949350505050565b600082198211156141fb576141fb61440e565b500190565b60008261421d57634e487b7160e01b600052601260045260246000fd5b500490565b600181815b8085111561425d5781600019048211156142435761424361440e565b8085161561425057918102915b93841c9390800290614227565b509250929050565b6000610926838360008261427b57506001610f3b565b8161428857506000610f3b565b816001811461429e57600281146142a8576142c4565b6001915050610f3b565b60ff8411156142b9576142b961440e565b50506001821b610f3b565b5060208310610133831016604e8410600b84101617156142e7575081810a610f3b565b6142f18383614222565b80600019048211156143055761430561440e565b029392505050565b60008160001904831182151516156143275761432761440e565b500290565b60008083128015600160ff1b85018412161561434a5761434a61440e565b6001600160ff1b03840183138116156143655761436561440e565b50500390565b60006001600160801b038381169083168181101561438b5761438b61440e565b039392505050565b6000828210156143a5576143a561440e565b500390565b60005b838110156143c55781810151838201526020016143ad565b838111156134bd5750506000910152565b60006000198214156143ea576143ea61440e565b5060010190565b6000600160ff1b8214156144075761440761440e565b5060000390565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fdfe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220652793cda3c7ff1da09891eecae094a2fc3c53261ed4328435ea6c420a5879a064736f6c634300080700337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a",
+ "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106102f15760003560e01c806367bd7ba31161019d578063abaa9916116100e9578063d38bfff4116100a2578063e45cc9f01161007c578063e45cc9f014610792578063e6cc54321461079b578063f8444436146107af578063fc0cfeee146107c2576102f1565b8063d38bfff41461076e578063d4c3eea014610781578063e18132c414610789576102f1565b8063abaa991614610733578063af14052c1461073b578063b888879e14610743578063b9b17f9f14610756578063c3b288641461075e578063c7af335214610766576102f1565b8063937b2581116101565780639fa1826e116101305780639fa1826e146106e6578063a0aead4d146106ef578063a403e4d5146106f7578063ab80dafb14610720576102f1565b8063937b2581146105ea5780639be918e6146106925780639ee679e8146106be576102f1565b806367bd7ba3146105725780636ec3ab67146105925780637136a7a6146105b25780637a2202f3146105c55780637cbc2373146105ce5780638e510b52146105e1576102f1565b80634530820a1161025c57806354c6d858116102155780635d36b190116101ef5780635d36b190146105315780635f51522614610539578063603ea03b1461054c5780636217f3ea1461055f576102f1565b806354c6d85814610502578063570d8e1d1461050b5780635b60f9fc1461051e576102f1565b80634530820a1461046b578063485cc9551461049e57806348e30f54146104b157806349c1d54d146104d257806352d38e5d146104e557806353ca9f24146104ee576102f1565b80632acada4d116102ae5780632acada4d146103ad57806331e19cfa146103c2578063362bd1a3146103ca5780633b8fe28d146104295780633fc8cef31461043c57806344c5470714610463576102f1565b806309f6442c146103375780630c340a2414610353578063156e29f61461037357806318ce56bd146103885780631edfe3da1461039b578063207134b0146103a4575b7fa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd9366000803760008036600084545af43d6000803e808015610332573d6000f35b3d6000fd5b61034060385481565b6040519081526020015b60405180910390f35b61035b6107d5565b6040516001600160a01b03909116815260200161034a565b610386610381366004613d9f565b6107f2565b005b60455461035b906001600160a01b031681565b61034060395481565b61034060435481565b6103b5610870565b60405161034a9190613f7d565b603654610340565b604b54604c546103f6916001600160801b0380821692600160801b928390048216928183169291041684565b604080516001600160801b039586168152938516602085015291841691830191909152909116606082015260800161034a565b610340610437366004613d51565b6108d2565b61035b7f000000000000000000000000000000000000000000000000000000000000000081565b61038661092d565b61048e610479366004613d51565b60496020526000908152604090205460ff1681565b604051901515815260200161034a565b6103866104ac366004613d6c565b610a76565b6104c46104bf366004613dd2565b610c78565b60405161034a929190613fdd565b60425461035b906001600160a01b031681565b610340603b5481565b60375461048e90600160a01b900460ff1681565b610340607b5481565b603f5461035b906001600160a01b031681565b61034061052c366004613d51565b610e61565b610386610e8a565b610340610547366004613d51565b610f30565b604a5461035b906001600160a01b031681565b61038661056d366004613eb9565b610f41565b610585610580366004613eb9565b6110d8565b60405161034a9190613fca565b6105a56105a0366004613d51565b6110e3565b60405161034a9190614126565b6103866105c0366004613eb9565b611189565b61034060475481565b6103866105dc366004613eeb565b611274565b61034060415481565b61064b6105f8366004613eb9565b604d60205260009081526040902080546001909101546001600160a01b03821691600160a01b810460ff1691600160a81b90910464ffffffffff16906001600160801b0380821691600160801b90041685565b604080516001600160a01b039096168652931515602086015264ffffffffff909216928401929092526001600160801b03918216606084015216608082015260a00161034a565b61048e6106a0366004613d51565b6001600160a01b031660009081526033602052604090205460ff1690565b6106d16106cc366004613eb9565b6112e7565b6040805192835260208301919091520161034a565b610340603a5481565b603454610340565b61035b610705366004613d51565b6040602081905260009182529020546001600160a01b031681565b61038661072e366004613eb9565b611552565b6103866116c9565b610386611741565b60375461035b906001600160a01b031681565b610386611787565b6103b56117f7565b61048e611857565b61038661077c366004613d51565b611888565b61034061192c565b61034061025881565b61034060465481565b60375461048e90600160a81b900460ff1681565b6103406107bd366004613eb9565b611936565b6103866107d0366004613d51565b611a90565b60006107ed6000805160206144878339815191525490565b905090565b603754600160a81b900460ff16156108255760405162461bcd60e51b815260040161081c906140d6565b60405180910390fd5b600080516020614467833981519152805460028114156108575760405162461bcd60e51b815260040161081c906140fe565b60028255610866858585611b32565b5060019055505050565b606060348054806020026020016040519081016040528092919081815260200182805480156108c857602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116108aa575b5050505050905090565b6000806108fb6108f56108e485611db3565b670de0b6b3a7640000906012611e1d565b84611e7f565b9050670de0b6b3a764000081610912856001611fdb565b61091c919061430d565b6109269190614200565b9392505050565b610935611857565b6109515760405162461bcd60e51b815260040161081c90614076565b60345460005b818110156109d1577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166034828154811061099c5761099c61443a565b6000918252602090912001546001600160a01b031614156109c157607b8190556109d1565b6109ca816143d6565b9050610957565b507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166034607b5481548110610a1157610a1161443a565b6000918252602090912001546001600160a01b031614610a735760405162461bcd60e51b815260206004820152601860248201527f496e76616c6964205745544820417373657420496e6465780000000000000000604482015260640161081c565b50565b610a7e611857565b610a9a5760405162461bcd60e51b815260040161081c90614076565b600054610100900460ff1680610ab3575060005460ff16155b610b165760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161081c565b600054610100900460ff16158015610b38576000805461ffff19166101011790555b6001600160a01b038316610b8e5760405162461bcd60e51b815260206004820152601d60248201527f507269636550726f76696465722061646472657373206973207a65726f000000604482015260640161081c565b6001600160a01b038216610bdd5760405162461bcd60e51b81526020600482015260166024820152756f546f6b656e2061646472657373206973207a65726f60501b604482015260640161081c565b603c80546001600160a01b038481166001600160a01b031990921691909117909155603780546001600160b01b03191691851691909117600160a81b17905560006038819055603981905569054b40b1f852bda00000603a55683635c9adc5dea00000603b556040805191825260208201908190529051610c6091603691613cc9565b508015610c73576000805461ff00191690555b505050565b603754606090600090600160a81b900460ff1615610ca85760405162461bcd60e51b815260040161081c906140d6565b60008051602061446783398151915280546002811415610cda5760405162461bcd60e51b815260040161081c906140fe565b60028255604a60009054906101000a90046001600160a01b03166001600160a01b031663e52253816040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610d2e57600080fd5b505af1158015610d42573d6000803e3d6000fd5b50505050610d4e6122cd565b50845167ffffffffffffffff811115610d6957610d69614450565b604051908082528060200260200182016040528015610d92578160200160208202803683370190505b50935060005b8551811015610e1857610dc3868281518110610db657610db661443a565b60200260200101516124b5565b858281518110610dd557610dd561443a565b602002602001018181525050848181518110610df357610df361443a565b602002602001015184610e0691906141e8565b9350610e11816143d6565b9050610d98565b50610e4d6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163385612757565b610e56836127ad565b600182555050915091565b600080610e736108f56108e485611db3565b9050670de0b6b3a764000081610912856000611fdb565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614610f255760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b606482015260840161081c565b610f2e33612963565b565b6000610f3b82612a24565b92915050565b603754600160a81b900460ff1615610f6b5760405162461bcd60e51b815260040161081c906140d6565b6045546001600160a01b03163314610f955760405162461bcd60e51b815260040161081c90614032565b6001600160ff1b038110610fbb5760405162461bcd60e51b815260040161081c906140ad565b7f222838db2794d11532d940e8dec38ae307ed0b63cd97c233322e221f998767a63382604051610fec929190613f64565b60405180910390a18060466000828254611006919061432c565b909155505060475460465461101a90612aeb565b106110715760405162461bcd60e51b815260206004820152602160248201527f417474656d7074696e6720746f206275726e20746f6f206d756368204f5553446044820152601760f91b606482015260840161081c565b603c54604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac906110a39033908590600401613f64565b600060405180830381600087803b1580156110bd57600080fd5b505af11580156110d1573d6000803e3d6000fd5b5050505050565b6060610f3b82612b2e565b604080516080808201835260008083526020808401829052838501829052606084018290526001600160a01b038616825260338152908490208451928301909452835460ff80821615158452939492939184019161010090910416600181111561114f5761114f614424565b600181111561116057611160614424565b8152905462010000810460ff1660208301526301000000900461ffff1660409091015292915050565b603754600160a81b900460ff16156111b35760405162461bcd60e51b815260040161081c906140d6565b600080516020614467833981519152805460028114156111e55760405162461bcd60e51b815260040161081c906140fe565b60028255603c546040516370a0823160e01b815233600482015261126c916001600160a01b0316906370a082319060240160206040518083038186803b15801561122e57600080fd5b505afa158015611242573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112669190613ed2565b84612c6f565b506001905550565b603754600160a81b900460ff161561129e5760405162461bcd60e51b815260040161081c906140d6565b600080516020614467833981519152805460028114156112d05760405162461bcd60e51b815260040161081c906140fe565b600282556112de8484612c6f565b50600190555050565b6037546000908190600160a81b900460ff16156113165760405162461bcd60e51b815260040161081c906140d6565b600080516020614467833981519152805460028114156113485760405162461bcd60e51b815260040161081c906140fe565b60028255604c54604b546001600160801b03600160801b90920482169550611372918791166141e8565b92506113876113828560016141e8565b612e13565b604c80546001600160801b03928316600160801b0292169190911790556113ad83612e13565b604b80546001600160801b0319166001600160801b03929092169190911790556040805160a081018252338152600060208201524264ffffffffff1691810191909152606081016113fd87612e13565b6001600160801b0316815260200161141485612e13565b6001600160801b039081169091526000868152604d602090815260409182902084518154928601518685015164ffffffffff16600160a81b0264ffffffffff60a81b19911515600160a01b026001600160a81b03199095166001600160a01b0393841617949094171692909217815560608501516080909501518416600160801b029490931693909317600190920191909155603c549051632770a7eb60e21b8152911690639dc29fac906114cf9033908990600401613f64565b600060405180830381600087803b1580156114e957600080fd5b505af11580156114fd573d6000803e3d6000fd5b5050505061150a856127ad565b6040805186815260208101859052859133917f38e3d972947cfef94205163d483d6287ef27eb312e20cb8e0b13a49989db232e910160405180910390a3600182555050915091565b603754600160a81b900460ff161561157c5760405162461bcd60e51b815260040161081c906140d6565b6045546001600160a01b031633146115a65760405162461bcd60e51b815260040161081c90614032565b6001600160ff1b0381106115cc5760405162461bcd60e51b815260040161081c906140ad565b7f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d412139688533826040516115fd929190613f64565b60405180910390a18060466000828254611617919061417c565b909155505060475460465461162b90612aeb565b106116975760405162461bcd60e51b815260206004820152603660248201527f4d696e746564206f75736420737572706173736564206e65744f7573644d696e6044820152753a2337b929ba3930ba32b3bcaa343932b9b437b6321760511b606482015260840161081c565b603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f19906110a39033908590600401613f64565b603754600160a81b900460ff16156116f35760405162461bcd60e51b815260040161081c906140d6565b600080516020614467833981519152805460028114156117255760405162461bcd60e51b815260040161081c906140fe565b600282556117316122cd565b5061173a612e7c565b5060019055565b600080516020614467833981519152805460028114156117735760405162461bcd60e51b815260040161081c906140fe565b6002825561177f6130b0565b505060019055565b604a60009054906101000a90046001600160a01b03166001600160a01b031663e52253816040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156117d757600080fd5b505af11580156117eb573d6000803e3d6000fd5b50505050610a736122cd565b606060368054806020026020016040519081016040528092919081815260200182805480156108c8576020028201919060005260206000209081546001600160a01b031681526001909101906020018083116108aa575050505050905090565b600061186f6000805160206144878339815191525490565b6001600160a01b0316336001600160a01b031614905090565b611890611857565b6118ac5760405162461bcd60e51b815260040161081c90614076565b6118d4817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166118f46000805160206144878339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b60006107ed6133eb565b603754600090600160a81b900460ff16156119635760405162461bcd60e51b815260040161081c906140d6565b600080516020614467833981519152805460028114156119955760405162461bcd60e51b815260040161081c906140fe565b60028255604b546000858152604d60205260409020600101546001600160801b03600160801b92839004811692909104161115611a3e57604a60009054906101000a90046001600160a01b03166001600160a01b031663e52253816040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611a1c57600080fd5b505af1158015611a30573d6000803e3d6000fd5b50505050611a3c6122cd565b505b611a47846124b5565b9250611a7d6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163385612757565b611a86836127ad565b5060019055919050565b611a98611857565b611ab45760405162461bcd60e51b815260040161081c90614076565b803b611b0e5760405162461bcd60e51b8152602060048201526024808201527f6e657720696d706c656d656e746174696f6e206973206e6f74206120636f6e746044820152631c9858dd60e21b606482015260840161081c565b7fa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd955565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b031614611bb35760405162461bcd60e51b815260206004820152601d60248201527f556e737570706f7274656420617373657420666f72206d696e74696e67000000604482015260640161081c565b60008211611c035760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e2030000000604482015260640161081c565b80821015611c535760405162461bcd60e51b815260206004820152601e60248201527f4d696e7420616d6f756e74206c6f776572207468616e206d696e696d756d0000604482015260640161081c565b7f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d41213968853383604051611c84929190613f64565b60405180910390a1603754600160a01b900460ff16158015611ca85750603b548210155b15611d1f57604a60009054906101000a90046001600160a01b03166001600160a01b031663e52253816040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611cfd57600080fd5b505af1158015611d11573d6000803e3d6000fd5b50505050611d1d6130b0565b505b603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990611d519033908690600401613f64565b600060405180830381600087803b158015611d6b57600080fd5b505af1158015611d7f573d6000803e3d6000fd5b50611d99925050506001600160a01b038416333085613485565b611da16122cd565b50603a548210610c7357610c73612e7c565b6001600160a01b03811660009081526033602052604090205462010000900460ff1680611e185760405162461bcd60e51b8152602060048201526013602482015272111958da5b585b1cc81b9bdd0818d858da1959606a1b604482015260640161081c565b919050565b600081831115611e4d57611e46611e348385614393565b611e3f90600a614265565b85906134c3565b9350611e77565b81831015611e7757611e74611e628484614393565b611e6d90600a614265565b85906134cf565b93505b509192915050565b6001600160a01b038116600090815260336020526040812054610100900460ff1681816001811115611eb357611eb3614424565b1415611ed757611ecf6012611ec785611db3565b869190611e1d565b915050610f3b565b6001816001811115611eeb57611eeb614424565b1415611f8c576000836001600160a01b031663e6aa216c6040518163ffffffff1660e01b815260040160206040518083038186803b158015611f2c57600080fd5b505afa158015611f40573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f649190613ed2565b9050670de0b6b3a7640000611f79828761430d565b611f839190614200565b92505050610f3b565b60405162461bcd60e51b815260206004820152601b60248201527f556e737570706f7274656420636f6e76657273696f6e20747970650000000000604482015260640161081c565b5092915050565b6001600160a01b038281166000818152603360205260408082205460375491516315d5220f60e31b81526004810194909452919361010090920460ff169291169063aea910789060240160206040518083038186803b15801561203d57600080fd5b505afa158015612051573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120759190613ed2565b9150600181600181111561208b5761208b614424565b141561212b576000846001600160a01b031663e6aa216c6040518163ffffffff1660e01b815260040160206040518083038186803b1580156120cc57600080fd5b505afa1580156120e0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121049190613ed2565b90508061211984670de0b6b3a764000061430d565b6121239190614200565b92505061218c565b600081600181111561213f5761213f614424565b1461218c5760405162461bcd60e51b815260206004820152601b60248201527f556e737570706f7274656420636f6e76657273696f6e20747970650000000000604482015260640161081c565b67120a871cc00200008211156121e45760405162461bcd60e51b815260206004820152601860248201527f5661756c743a2050726963652065786365656473206d61780000000000000000604482015260640161081c565b6709b6e64a8ec600008210156122355760405162461bcd60e51b81526020600482015260166024820152752b30bab63a1d10283934b1b2903ab73232b91036b4b760511b604482015260640161081c565b82156122ac57670de0b6b3a764000082111561225757670de0b6b3a764000091505b670dd99bb65dd700008210156122a75760405162461bcd60e51b815260206004820152601560248201527441737365742070726963652062656c6f772070656760581b604482015260640161081c565b611fd4565b670de0b6b3a7640000821015611fd45750670de0b6b3a76400009392505050565b60408051608081018252604b546001600160801b03808216808452600160801b92839004821660208501819052604c548084169686019690965292909404166060830152600092839161231f9161436b565b6001600160801b03169050806123385760009250505090565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561239a57600080fd5b505afa1580156123ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123d29190613ed2565b90506000836040015184602001516123ea919061436b565b6001600160801b0316905080821161240757600094505050505090565b60006124138284614393565b90508084106124225780612424565b835b955060008686602001516001600160801b031661244191906141e8565b905061244c81612e13565b604b80546001600160801b03928316600160801b0292169190911790556040517fee79a0c43d3993055690b54e074b5153e8bae8d1a872b656dedb64aa8f463333906124a49083908a90918252602082015260400190565b60405180910390a150505050505090565b6000818152604d60209081526040808320815160a08101835281546001600160a01b038116825260ff600160a01b82041615158286015264ffffffffff600160a81b90910481168285019081526001909301546001600160801b03808216606080860191909152600160801b92839004821660808087019190915287519081018852604b548084168252849004831698810198909852604c548083169789019790975291909504909416938501939093529051909291429161257b9161025891166141e8565b11156125bf5760405162461bcd60e51b815260206004820152601360248201527210db185a5b4819195b185e481b9bdd081b595d606a1b604482015260640161081c565b80602001516001600160801b031682608001516001600160801b031611156126295760405162461bcd60e51b815260206004820152601760248201527f51756575652070656e64696e67206c6971756964697479000000000000000000604482015260640161081c565b81516001600160a01b031633146126725760405162461bcd60e51b815260206004820152600d60248201526c2737ba103932b8bab2b9ba32b960991b604482015260640161081c565b6020820151156126b65760405162461bcd60e51b815260206004820152600f60248201526e105b1c9958591e4818db185a5b5959608a1b604482015260640161081c565b6000848152604d602052604090819020805460ff60a01b1916600160a01b1790556060830151908201516126ea91906141bd565b604c80546001600160801b0319166001600160801b03928316179055606083015160405191168152849033907f2d43eb174787155132b52ddb6b346e2dca99302eac3df4466dbeff953d3c84d19060200160405180910390a350606001516001600160801b031692915050565b610c738363a9059cbb60e01b8484604051602401612776929190613f64565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526134db565b6000603b5482101580156127cb5750603754600160a01b900460ff16155b156127df576127d86130b0565b90506127ea565b6127e76133eb565b90505b6041541561295f57600081116128425760405162461bcd60e51b815260206004820152601d60248201527f546f6f206d616e79206f75747374616e64696e67207265717565737473000000604482015260640161081c565b60006128d482603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561289657600080fd5b505afa1580156128aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128ce9190613ed2565b906135ad565b9050604154670de0b6b3a764000082116128ff576128fa82670de0b6b3a7640000614393565b612911565b612911670de0b6b3a764000083614393565b1115610c735760405162461bcd60e51b815260206004820152601e60248201527f4261636b696e6720737570706c79206c6971756964697479206572726f720000604482015260640161081c565b5050565b6001600160a01b0381166129b95760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f722069732061646472657373283029000000000000604482015260640161081c565b806001600160a01b03166129d96000805160206144878339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a3610a738160008051602061448783398151915255565b6000612a2f826135d6565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161415611e185760408051608081018252604b546001600160801b03808216808452600160801b9283900482166020850152604c54808316958501869052929092041660608301529091612ab890846141e8565b10612ae557805160408201516001600160801b0391821691612adb9116846141e8565b6109269190614393565b50919050565b60006001600160ff1b038212612b135760405162461bcd60e51b815260040161081c906140ad565b6000821215612b2a57612b25826143f1565b610f3b565b5090565b60385460609015612b5d57603854600090612b4d9084906127106137a5565b9050612b598184614393565b9250505b6000607b5490507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031660348281548110612ba157612ba161443a565b6000918252602090912001546001600160a01b031614612c035760405162461bcd60e51b815260206004820152601b60248201527f5745544820417373657420696e646578206e6f74206361636865640000000000604482015260640161081c565b60345467ffffffffffffffff811115612c1e57612c1e614450565b604051908082528060200260200182016040528015612c47578160200160208202803683370190505b50915082828281518110612c5d57612c5d61443a565b60200260200101818152505050919050565b7f222838db2794d11532d940e8dec38ae307ed0b63cd97c233322e221f998767a63383604051612ca0929190613f64565b60405180910390a181612cb1575050565b6000612cbc83612b2e565b607b5481518110612ccf57612ccf61443a565b6020026020010151905081811015612d295760405162461bcd60e51b815260206004820181905260248201527f52656465656d20616d6f756e74206c6f776572207468616e206d696e696d756d604482015260640161081c565b80612d326137c7565b1015612d725760405162461bcd60e51b815260206004820152600f60248201526e2634b8bab4b234ba3c9032b93937b960891b604482015260640161081c565b612da66001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163383612757565b603c54604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac90612dd89033908790600401613f64565b600060405180830381600087803b158015612df257600080fd5b505af1158015612e06573d6000803e3d6000fd5b50505050610c73836127ad565b60006001600160801b03821115612b2a5760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316044820152663238206269747360c81b606482015260840161081c565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166000908152604060208190529020541680612ebf5750565b6000612ec96137c7565b905080612ed4575050565b603c54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd916004808301926020929190829003018186803b158015612f1957600080fd5b505afa158015612f2d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f519190613ed2565b90506000612f6a603954836138e490919063ffffffff16565b9050808311612f795750505050565b6000612f858285614393565b905084612fbc6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168284612757565b6040516311f9fbc960e21b81526001600160a01b038216906347e7ef249061300a907f0000000000000000000000000000000000000000000000000000000000000000908690600401613f64565b600060405180830381600087803b15801561302457600080fd5b505af1158015613038573d6000803e3d6000fd5b5050604080516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811682528a1660208201529081018590527f41b99659f6ba0803f444aff29e5bf6e26dd86a3219aff92119d69710a956ba8d9250606001905060405180910390a1505050505050565b603754600090600160a01b900460ff16156130ff5760405162461bcd60e51b815260206004820152600f60248201526e149958985cda5b99c81c185d5cd959608a1b604482015260640161081c565b603c54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd916004808301926020929190829003018186803b15801561314457600080fd5b505afa158015613158573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061317c9190613ed2565b905060006131886133eb565b9050816131985791506133e89050565b6042546001600160a01b031680158015906131b257508282115b156132f45760006131c38484614393565b905060006131e0604354612710846137a59092919063ffffffff16565b905080821161323c5760405162461bcd60e51b815260206004820152602260248201527f466565206d757374206e6f742062652067726561746572207468616e207969656044820152611b1960f21b606482015260840161081c565b80156132a757603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f19906132749086908590600401613f64565b600060405180830381600087803b15801561328e57600080fd5b505af11580156132a2573d6000803e3d6000fd5b505050505b604080516001600160a01b0385168152602081018490529081018290527f09516ecf4a8a86e59780a9befc6dee948bc9e60a36e3be68d31ea817ee8d2c809060600160405180910390a150505b603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561334257600080fd5b505afa158015613356573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061337a9190613ed2565b9250828211156133e357603c546040516339a7919f60e01b8152600481018490526001600160a01b03909116906339a7919f90602401600060405180830381600087803b1580156133ca57600080fd5b505af11580156133de573d6000803e3d6000fd5b505050505b509150505b90565b60006133f56138f9565b6133fd61395a565b61340791906141e8565b60408051608081018252604b546001600160801b03808216808452600160801b9283900482166020850152604c5480831695850186905292909204166060830152929350916000916134589161436b565b6001600160801b03169050808310156134745760009250505090565b61347e8184614393565b9250505090565b6040516001600160a01b03808516602483015283166044820152606481018290526134bd9085906323b872dd60e01b90608401612776565b50505050565b6000610926828461430d565b60006109268284614200565b6000613530826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166139f49092919063ffffffff16565b805190915015610c73578080602001905181019061354e9190613e97565b610c735760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161081c565b6000806135c284670de0b6b3a76400006134c3565b90506135ce81846134cf565b949350505050565b6040516370a0823160e01b815230600482015260009082906001600160a01b038216906370a082319060240160206040518083038186803b15801561361a57600080fd5b505afa15801561362e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136529190613ed2565b60365490925060005b8181101561379d576000603682815481106136785761367861443a565b60009182526020909120015460405163551c457b60e11b81526001600160a01b0388811660048301529091169150819063aa388af69060240160206040518083038186803b1580156136c957600080fd5b505afa1580156136dd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137019190613e97565b1561378c57604051632fa8a91360e11b81526001600160a01b038781166004830152821690635f5152269060240160206040518083038186803b15801561374757600080fd5b505afa15801561375b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061377f9190613ed2565b61378990866141e8565b94505b50613796816143d6565b905061365b565b505050919050565b6000806137b285856134c3565b90506137be81846134cf565b95945050505050565b60408051608081018252604b546001600160801b03808216808452600160801b9283900482166020850152604c54808316958501869052929092041660608301526000928391613817919061436b565b6040516370a0823160e01b81523060048201526001600160801b039190911691506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a082319060240160206040518083038186803b15801561388757600080fd5b505afa15801561389b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138bf9190613ed2565b90508181116138d2576000935050505090565b6138dc8282614393565b935050505090565b60006109268383670de0b6b3a76400006137a5565b603654600090815b81811015613955576139396036828154811061391f5761391f61443a565b6000918252602090912001546001600160a01b0316613a03565b61394390846141e8565b925061394e816143d6565b9050613901565b505090565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b1580156139bc57600080fd5b505afa1580156139d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107ed9190613ed2565b60606135ce8484600085613b68565b6034546000908290825b8181101561379d57600060348281548110613a2a57613a2a61443a565b60009182526020909120015460405163551c457b60e11b81526001600160a01b039182166004820181905292509085169063aa388af69060240160206040518083038186803b158015613a7c57600080fd5b505afa158015613a90573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ab49190613e97565b15613b5757604051632fa8a91360e11b81526001600160a01b03828116600483015260009190861690635f5152269060240160206040518083038186803b158015613afe57600080fd5b505afa158015613b12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b369190613ed2565b90508015613b5557613b488183611e7f565b613b5290876141e8565b95505b505b50613b61816143d6565b9050613a0d565b606082471015613bc95760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161081c565b843b613c175760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161081c565b600080866001600160a01b03168587604051613c339190613f48565b60006040518083038185875af1925050503d8060008114613c70576040519150601f19603f3d011682016040523d82523d6000602084013e613c75565b606091505b5091509150613c85828286613c90565b979650505050505050565b60608315613c9f575081610926565b825115613caf5782518084602001fd5b8160405162461bcd60e51b815260040161081c9190613fff565b828054828255906000526020600020908101928215613d1e579160200282015b82811115613d1e57825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190613ce9565b50612b2a9291505b80821115612b2a5760008155600101613d26565b80356001600160a01b0381168114611e1857600080fd5b600060208284031215613d6357600080fd5b61092682613d3a565b60008060408385031215613d7f57600080fd5b613d8883613d3a565b9150613d9660208401613d3a565b90509250929050565b600080600060608486031215613db457600080fd5b613dbd84613d3a565b95602085013595506040909401359392505050565b60006020808385031215613de557600080fd5b823567ffffffffffffffff80821115613dfd57600080fd5b818501915085601f830112613e1157600080fd5b813581811115613e2357613e23614450565b8060051b604051601f19603f83011681018181108582111715613e4857613e48614450565b604052828152858101935084860182860187018a1015613e6757600080fd5b600095505b83861015613e8a578035855260019590950194938601938601613e6c565b5098975050505050505050565b600060208284031215613ea957600080fd5b8151801515811461092657600080fd5b600060208284031215613ecb57600080fd5b5035919050565b600060208284031215613ee457600080fd5b5051919050565b60008060408385031215613efe57600080fd5b50508035926020909101359150565b600081518084526020808501945080840160005b83811015613f3d57815187529582019590820190600101613f21565b509495945050505050565b60008251613f5a8184602087016143aa565b9190910192915050565b6001600160a01b03929092168252602082015260400190565b6020808252825182820181905260009190848201906040850190845b81811015613fbe5783516001600160a01b031683529284019291840191600101613f99565b50909695505050505050565b6020815260006109266020830184613f0d565b604081526000613ff06040830185613f0d565b90508260208301529392505050565b602081526000825180602084015261401e8160408501602087016143aa565b601f01601f19169190910160400192915050565b60208082526024908201527f43616c6c6572206973206e6f7420746865204f555344206d65746120737472616040820152637465677960e01b606082015260800190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b6020808252600f908201526e082dadeeadce840e8dede40d0d2ced608b1b604082015260600190565b6020808252600e908201526d10d85c1a5d185b081c185d5cd95960921b604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b815115158152602082015160808201906002811061415457634e487b7160e01b600052602160045260246000fd5b8060208401525060ff604084015116604083015261ffff606084015116606083015292915050565b600080821280156001600160ff1b038490038513161561419e5761419e61440e565b600160ff1b83900384128116156141b7576141b761440e565b50500190565b60006001600160801b038083168185168083038211156141df576141df61440e565b01949350505050565b600082198211156141fb576141fb61440e565b500190565b60008261421d57634e487b7160e01b600052601260045260246000fd5b500490565b600181815b8085111561425d5781600019048211156142435761424361440e565b8085161561425057918102915b93841c9390800290614227565b509250929050565b6000610926838360008261427b57506001610f3b565b8161428857506000610f3b565b816001811461429e57600281146142a8576142c4565b6001915050610f3b565b60ff8411156142b9576142b961440e565b50506001821b610f3b565b5060208310610133831016604e8410600b84101617156142e7575081810a610f3b565b6142f18383614222565b80600019048211156143055761430561440e565b029392505050565b60008160001904831182151516156143275761432761440e565b500290565b60008083128015600160ff1b85018412161561434a5761434a61440e565b6001600160ff1b03840183138116156143655761436561440e565b50500390565b60006001600160801b038381169083168181101561438b5761438b61440e565b039392505050565b6000828210156143a5576143a561440e565b500390565b60005b838110156143c55781810151838201526020016143ad565b838111156134bd5750506000910152565b60006000198214156143ea576143ea61440e565b5060010190565b6000600160ff1b8214156144075761440761440e565b5060000390565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fdfe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220652793cda3c7ff1da09891eecae094a2fc3c53261ed4328435ea6c420a5879a064736f6c63430008070033",
"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 +1427,23 @@
"_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",
+ "totalAmount": "Total amount of WETH transferred to the withdrawer"
+ }
+ },
"isSupportedAsset(address)": {
"params": {
"_asset": "address of the asset"
@@ -1158,6 +1491,13 @@
"_minimumUnitAmount": "Minimum stablecoin units to receive in return"
}
},
+ "requestWithdrawal(uint256)": {
+ "params": {
+ "_amount": "Amount of OETH to burn.",
+ "queued": "Cumulative total of all WETH queued including already claimed requests.",
+ "requestId": "Unique ID for the withdrawal request"
+ }
+ },
"setAdminImpl(address)": {
"params": {
"newImpl": "address of the implementation"
@@ -1180,6 +1520,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 +1547,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. 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."
+ },
+ "claimWithdrawals(uint256[])": {
+ "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`."
+ },
+ "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 +1625,9 @@
"redeemFeeBps()": {
"notice": "Redemption fee in basis points. eg 50 = 0.5%"
},
+ "requestWithdrawal(uint256)": {
+ "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."
+ },
"setAdminImpl(address)": {
"notice": "set the implementation for the admin, this needs to be in a base class else we cannot set it"
},
@@ -1293,6 +1648,12 @@
},
"vaultBuffer()": {
"notice": "Percentage of assets to keep in Vault to handle (most) withdrawals. 100% = 1e18."
+ },
+ "withdrawalQueueMetadata()": {
+ "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"
+ },
+ "withdrawalRequests(uint256)": {
+ "notice": "Mapping of withdrawal request indices to the user withdrawal request data"
}
},
"version": 1
@@ -1300,7 +1661,7 @@
"storageLayout": {
"storage": [
{
- "astId": 41419,
+ "astId": 24695,
"contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore",
"label": "initialized",
"offset": 0,
@@ -1308,7 +1669,7 @@
"type": "t_bool"
},
{
- "astId": 41422,
+ "astId": 24698,
"contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore",
"label": "initializing",
"offset": 1,
@@ -1316,7 +1677,7 @@
"type": "t_bool"
},
{
- "astId": 41462,
+ "astId": 24738,
"contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore",
"label": "______gap",
"offset": 0,
@@ -1324,15 +1685,15 @@
"type": "t_array(t_uint256)50_storage"
},
{
- "astId": 46069,
+ "astId": 30639,
"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)30633_storage)"
},
{
- "astId": 46073,
+ "astId": 30643,
"contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore",
"label": "allAssets",
"offset": 0,
@@ -1340,15 +1701,15 @@
"type": "t_array(t_address)dyn_storage"
},
{
- "astId": 46084,
+ "astId": 30654,
"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)30648_storage)"
},
{
- "astId": 46088,
+ "astId": 30658,
"contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore",
"label": "allStrategies",
"offset": 0,
@@ -1356,7 +1717,7 @@
"type": "t_array(t_address)dyn_storage"
},
{
- "astId": 46091,
+ "astId": 30661,
"contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore",
"label": "priceProvider",
"offset": 0,
@@ -1364,7 +1725,7 @@
"type": "t_address"
},
{
- "astId": 46095,
+ "astId": 30665,
"contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore",
"label": "rebasePaused",
"offset": 20,
@@ -1372,7 +1733,7 @@
"type": "t_bool"
},
{
- "astId": 46099,
+ "astId": 30669,
"contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore",
"label": "capitalPaused",
"offset": 21,
@@ -1380,7 +1741,7 @@
"type": "t_bool"
},
{
- "astId": 46102,
+ "astId": 30672,
"contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore",
"label": "redeemFeeBps",
"offset": 0,
@@ -1388,7 +1749,7 @@
"type": "t_uint256"
},
{
- "astId": 46105,
+ "astId": 30675,
"contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore",
"label": "vaultBuffer",
"offset": 0,
@@ -1396,7 +1757,7 @@
"type": "t_uint256"
},
{
- "astId": 46108,
+ "astId": 30678,
"contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore",
"label": "autoAllocateThreshold",
"offset": 0,
@@ -1404,7 +1765,7 @@
"type": "t_uint256"
},
{
- "astId": 46111,
+ "astId": 30681,
"contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore",
"label": "rebaseThreshold",
"offset": 0,
@@ -1412,15 +1773,15 @@
"type": "t_uint256"
},
{
- "astId": 46115,
+ "astId": 30685,
"contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore",
"label": "oUSD",
"offset": 0,
"slot": "60",
- "type": "t_contract(OUSD)40245"
+ "type": "t_contract(OUSD)24061"
},
{
- "astId": 46124,
+ "astId": 30694,
"contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore",
"label": "_deprecated_rebaseHooksAddr",
"offset": 0,
@@ -1428,7 +1789,7 @@
"type": "t_address"
},
{
- "astId": 46130,
+ "astId": 30700,
"contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore",
"label": "_deprecated_uniswapAddr",
"offset": 0,
@@ -1436,7 +1797,7 @@
"type": "t_address"
},
{
- "astId": 46137,
+ "astId": 30707,
"contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore",
"label": "strategistAddr",
"offset": 0,
@@ -1444,7 +1805,7 @@
"type": "t_address"
},
{
- "astId": 46142,
+ "astId": 30712,
"contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore",
"label": "assetDefaultStrategies",
"offset": 0,
@@ -1452,7 +1813,7 @@
"type": "t_mapping(t_address,t_address)"
},
{
- "astId": 46145,
+ "astId": 30715,
"contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore",
"label": "maxSupplyDiff",
"offset": 0,
@@ -1460,7 +1821,7 @@
"type": "t_uint256"
},
{
- "astId": 46148,
+ "astId": 30718,
"contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore",
"label": "trusteeAddress",
"offset": 0,
@@ -1468,7 +1829,7 @@
"type": "t_address"
},
{
- "astId": 46151,
+ "astId": 30721,
"contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore",
"label": "trusteeFeeBps",
"offset": 0,
@@ -1476,7 +1837,7 @@
"type": "t_uint256"
},
{
- "astId": 46155,
+ "astId": 30725,
"contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore",
"label": "_deprecated_swapTokens",
"offset": 0,
@@ -1484,7 +1845,7 @@
"type": "t_array(t_address)dyn_storage"
},
{
- "astId": 46165,
+ "astId": 30731,
"contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore",
"label": "ousdMetaStrategy",
"offset": 0,
@@ -1492,7 +1853,7 @@
"type": "t_address"
},
{
- "astId": 46169,
+ "astId": 30734,
"contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore",
"label": "netOusdMintedForStrategy",
"offset": 0,
@@ -1500,7 +1861,7 @@
"type": "t_int256"
},
{
- "astId": 46173,
+ "astId": 30737,
"contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore",
"label": "netOusdMintForStrategyThreshold",
"offset": 0,
@@ -1508,28 +1869,68 @@
"type": "t_uint256"
},
{
- "astId": 46194,
+ "astId": 30758,
"contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore",
"label": "swapConfig",
"offset": 0,
"slot": "72",
- "type": "t_struct(SwapConfig)46184_storage"
+ "type": "t_struct(SwapConfig)30748_storage"
},
{
- "astId": 46198,
+ "astId": 30762,
"contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore",
- "label": "__gap",
+ "label": "isMintWhitelistedStrategy",
"offset": 0,
"slot": "73",
- "type": "t_array(t_uint256)50_storage"
+ "type": "t_mapping(t_address,t_bool)"
+ },
+ {
+ "astId": 30765,
+ "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore",
+ "label": "dripper",
+ "offset": 0,
+ "slot": "74",
+ "type": "t_address"
},
{
- "astId": 42360,
+ "astId": 30778,
+ "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore",
+ "label": "withdrawalQueueMetadata",
+ "offset": 0,
+ "slot": "75",
+ "type": "t_struct(WithdrawalQueueMetadata)30774_storage"
+ },
+ {
+ "astId": 30795,
+ "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore",
+ "label": "withdrawalRequests",
+ "offset": 0,
+ "slot": "77",
+ "type": "t_mapping(t_uint256,t_struct(WithdrawalRequest)30789_storage)"
+ },
+ {
+ "astId": 30799,
+ "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore",
+ "label": "__gap",
+ "offset": 0,
+ "slot": "78",
+ "type": "t_array(t_uint256)45_storage"
+ },
+ {
+ "astId": 26075,
"contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore",
"label": "wethAssetIndex",
"offset": 0,
"slot": "123",
"type": "t_uint256"
+ },
+ {
+ "astId": 26079,
+ "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore",
+ "label": "__gap",
+ "offset": 0,
+ "slot": "124",
+ "type": "t_array(t_uint256)50_storage"
}
],
"types": {
@@ -1544,6 +1945,12 @@
"label": "address[]",
"numberOfBytes": "32"
},
+ "t_array(t_uint256)45_storage": {
+ "base": "t_uint256",
+ "encoding": "inplace",
+ "label": "uint256[45]",
+ "numberOfBytes": "1440"
+ },
"t_array(t_uint256)50_storage": {
"base": "t_uint256",
"encoding": "inplace",
@@ -1555,12 +1962,12 @@
"label": "bool",
"numberOfBytes": "1"
},
- "t_contract(OUSD)40245": {
+ "t_contract(OUSD)24061": {
"encoding": "inplace",
"label": "contract OUSD",
"numberOfBytes": "20"
},
- "t_enum(UnitConversion)46053": {
+ "t_enum(UnitConversion)30623": {
"encoding": "inplace",
"label": "enum VaultStorage.UnitConversion",
"numberOfBytes": "1"
@@ -1577,26 +1984,40 @@
"numberOfBytes": "32",
"value": "t_address"
},
- "t_mapping(t_address,t_struct(Asset)46063_storage)": {
+ "t_mapping(t_address,t_bool)": {
+ "encoding": "mapping",
+ "key": "t_address",
+ "label": "mapping(address => bool)",
+ "numberOfBytes": "32",
+ "value": "t_bool"
+ },
+ "t_mapping(t_address,t_struct(Asset)30633_storage)": {
"encoding": "mapping",
"key": "t_address",
"label": "mapping(address => struct VaultStorage.Asset)",
"numberOfBytes": "32",
- "value": "t_struct(Asset)46063_storage"
+ "value": "t_struct(Asset)30633_storage"
},
- "t_mapping(t_address,t_struct(Strategy)46078_storage)": {
+ "t_mapping(t_address,t_struct(Strategy)30648_storage)": {
"encoding": "mapping",
"key": "t_address",
"label": "mapping(address => struct VaultStorage.Strategy)",
"numberOfBytes": "32",
- "value": "t_struct(Strategy)46078_storage"
+ "value": "t_struct(Strategy)30648_storage"
+ },
+ "t_mapping(t_uint256,t_struct(WithdrawalRequest)30789_storage)": {
+ "encoding": "mapping",
+ "key": "t_uint256",
+ "label": "mapping(uint256 => struct VaultStorage.WithdrawalRequest)",
+ "numberOfBytes": "32",
+ "value": "t_struct(WithdrawalRequest)30789_storage"
},
- "t_struct(Asset)46063_storage": {
+ "t_struct(Asset)30633_storage": {
"encoding": "inplace",
"label": "struct VaultStorage.Asset",
"members": [
{
- "astId": 46055,
+ "astId": 30625,
"contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore",
"label": "isSupported",
"offset": 0,
@@ -1604,15 +2025,15 @@
"type": "t_bool"
},
{
- "astId": 46058,
+ "astId": 30628,
"contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore",
"label": "unitConversion",
"offset": 1,
"slot": "0",
- "type": "t_enum(UnitConversion)46053"
+ "type": "t_enum(UnitConversion)30623"
},
{
- "astId": 46060,
+ "astId": 30630,
"contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore",
"label": "decimals",
"offset": 2,
@@ -1620,7 +2041,7 @@
"type": "t_uint8"
},
{
- "astId": 46062,
+ "astId": 30632,
"contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore",
"label": "allowedOracleSlippageBps",
"offset": 3,
@@ -1630,12 +2051,12 @@
],
"numberOfBytes": "32"
},
- "t_struct(Strategy)46078_storage": {
+ "t_struct(Strategy)30648_storage": {
"encoding": "inplace",
"label": "struct VaultStorage.Strategy",
"members": [
{
- "astId": 46075,
+ "astId": 30645,
"contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore",
"label": "isSupported",
"offset": 0,
@@ -1643,7 +2064,7 @@
"type": "t_bool"
},
{
- "astId": 46077,
+ "astId": 30647,
"contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore",
"label": "_deprecated",
"offset": 0,
@@ -1653,12 +2074,12 @@
],
"numberOfBytes": "64"
},
- "t_struct(SwapConfig)46184_storage": {
+ "t_struct(SwapConfig)30748_storage": {
"encoding": "inplace",
"label": "struct VaultStorage.SwapConfig",
"members": [
{
- "astId": 46181,
+ "astId": 30745,
"contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore",
"label": "swapper",
"offset": 0,
@@ -1666,7 +2087,7 @@
"type": "t_address"
},
{
- "astId": 46183,
+ "astId": 30747,
"contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore",
"label": "allowedUndervalueBps",
"offset": 20,
@@ -1676,6 +2097,97 @@
],
"numberOfBytes": "32"
},
+ "t_struct(WithdrawalQueueMetadata)30774_storage": {
+ "encoding": "inplace",
+ "label": "struct VaultStorage.WithdrawalQueueMetadata",
+ "members": [
+ {
+ "astId": 30767,
+ "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore",
+ "label": "queued",
+ "offset": 0,
+ "slot": "0",
+ "type": "t_uint128"
+ },
+ {
+ "astId": 30769,
+ "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore",
+ "label": "claimable",
+ "offset": 16,
+ "slot": "0",
+ "type": "t_uint128"
+ },
+ {
+ "astId": 30771,
+ "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore",
+ "label": "claimed",
+ "offset": 0,
+ "slot": "1",
+ "type": "t_uint128"
+ },
+ {
+ "astId": 30773,
+ "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore",
+ "label": "nextWithdrawalIndex",
+ "offset": 16,
+ "slot": "1",
+ "type": "t_uint128"
+ }
+ ],
+ "numberOfBytes": "64"
+ },
+ "t_struct(WithdrawalRequest)30789_storage": {
+ "encoding": "inplace",
+ "label": "struct VaultStorage.WithdrawalRequest",
+ "members": [
+ {
+ "astId": 30780,
+ "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore",
+ "label": "withdrawer",
+ "offset": 0,
+ "slot": "0",
+ "type": "t_address"
+ },
+ {
+ "astId": 30782,
+ "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore",
+ "label": "claimed",
+ "offset": 20,
+ "slot": "0",
+ "type": "t_bool"
+ },
+ {
+ "astId": 30784,
+ "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore",
+ "label": "timestamp",
+ "offset": 21,
+ "slot": "0",
+ "type": "t_uint40"
+ },
+ {
+ "astId": 30786,
+ "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore",
+ "label": "amount",
+ "offset": 0,
+ "slot": "1",
+ "type": "t_uint128"
+ },
+ {
+ "astId": 30788,
+ "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",
@@ -1686,6 +2198,11 @@
"label": "uint256",
"numberOfBytes": "32"
},
+ "t_uint40": {
+ "encoding": "inplace",
+ "label": "uint40",
+ "numberOfBytes": "5"
+ },
"t_uint8": {
"encoding": "inplace",
"label": "uint8",
diff --git a/contracts/deployments/holesky/solcInputs/0d24aafc2e05d7bcc2007c274421d881.json b/contracts/deployments/holesky/solcInputs/0d24aafc2e05d7bcc2007c274421d881.json
new file mode 100644
index 0000000000..d6a8b5117e
--- /dev/null
+++ b/contracts/deployments/holesky/solcInputs/0d24aafc2e05d7bcc2007c274421d881.json
@@ -0,0 +1,356 @@
+{
+ "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/SafeCast.sol": {
+ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeCast.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow\n * checks.\n *\n * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can\n * easily result in undesired exploitation or bugs, since developers usually\n * assume that overflows raise errors. `SafeCast` restores this intuition by\n * reverting the transaction when such an operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n *\n * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing\n * all math on `uint256` and `int256` and then downcasting.\n */\nlibrary SafeCast {\n /**\n * @dev Returns the downcasted uint224 from uint256, reverting on\n * overflow (when the input is greater than largest uint224).\n *\n * Counterpart to Solidity's `uint224` operator.\n *\n * Requirements:\n *\n * - input must fit into 224 bits\n */\n function toUint224(uint256 value) internal pure returns (uint224) {\n require(value <= type(uint224).max, \"SafeCast: value doesn't fit in 224 bits\");\n return uint224(value);\n }\n\n /**\n * @dev Returns the downcasted uint128 from uint256, reverting on\n * overflow (when the input is greater than largest uint128).\n *\n * Counterpart to Solidity's `uint128` operator.\n *\n * Requirements:\n *\n * - input must fit into 128 bits\n */\n function toUint128(uint256 value) internal pure returns (uint128) {\n require(value <= type(uint128).max, \"SafeCast: value doesn't fit in 128 bits\");\n return uint128(value);\n }\n\n /**\n * @dev Returns the downcasted uint96 from uint256, reverting on\n * overflow (when the input is greater than largest uint96).\n *\n * Counterpart to Solidity's `uint96` operator.\n *\n * Requirements:\n *\n * - input must fit into 96 bits\n */\n function toUint96(uint256 value) internal pure returns (uint96) {\n require(value <= type(uint96).max, \"SafeCast: value doesn't fit in 96 bits\");\n return uint96(value);\n }\n\n /**\n * @dev Returns the downcasted uint64 from uint256, reverting on\n * overflow (when the input is greater than largest uint64).\n *\n * Counterpart to Solidity's `uint64` operator.\n *\n * Requirements:\n *\n * - input must fit into 64 bits\n */\n function toUint64(uint256 value) internal pure returns (uint64) {\n require(value <= type(uint64).max, \"SafeCast: value doesn't fit in 64 bits\");\n return uint64(value);\n }\n\n /**\n * @dev Returns the downcasted uint32 from uint256, reverting on\n * overflow (when the input is greater than largest uint32).\n *\n * Counterpart to Solidity's `uint32` operator.\n *\n * Requirements:\n *\n * - input must fit into 32 bits\n */\n function toUint32(uint256 value) internal pure returns (uint32) {\n require(value <= type(uint32).max, \"SafeCast: value doesn't fit in 32 bits\");\n return uint32(value);\n }\n\n /**\n * @dev Returns the downcasted uint16 from uint256, reverting on\n * overflow (when the input is greater than largest uint16).\n *\n * Counterpart to Solidity's `uint16` operator.\n *\n * Requirements:\n *\n * - input must fit into 16 bits\n */\n function toUint16(uint256 value) internal pure returns (uint16) {\n require(value <= type(uint16).max, \"SafeCast: value doesn't fit in 16 bits\");\n return uint16(value);\n }\n\n /**\n * @dev Returns the downcasted uint8 from uint256, reverting on\n * overflow (when the input is greater than largest uint8).\n *\n * Counterpart to Solidity's `uint8` operator.\n *\n * Requirements:\n *\n * - input must fit into 8 bits.\n */\n function toUint8(uint256 value) internal pure returns (uint8) {\n require(value <= type(uint8).max, \"SafeCast: value doesn't fit in 8 bits\");\n return uint8(value);\n }\n\n /**\n * @dev Converts a signed int256 into an unsigned uint256.\n *\n * Requirements:\n *\n * - input must be greater than or equal to 0.\n */\n function toUint256(int256 value) internal pure returns (uint256) {\n require(value >= 0, \"SafeCast: value must be positive\");\n return uint256(value);\n }\n\n /**\n * @dev Returns the downcasted int128 from int256, reverting on\n * overflow (when the input is less than smallest int128 or\n * greater than largest int128).\n *\n * Counterpart to Solidity's `int128` operator.\n *\n * Requirements:\n *\n * - input must fit into 128 bits\n *\n * _Available since v3.1._\n */\n function toInt128(int256 value) internal pure returns (int128) {\n require(value >= type(int128).min && value <= type(int128).max, \"SafeCast: value doesn't fit in 128 bits\");\n return int128(value);\n }\n\n /**\n * @dev Returns the downcasted int64 from int256, reverting on\n * overflow (when the input is less than smallest int64 or\n * greater than largest int64).\n *\n * Counterpart to Solidity's `int64` operator.\n *\n * Requirements:\n *\n * - input must fit into 64 bits\n *\n * _Available since v3.1._\n */\n function toInt64(int256 value) internal pure returns (int64) {\n require(value >= type(int64).min && value <= type(int64).max, \"SafeCast: value doesn't fit in 64 bits\");\n return int64(value);\n }\n\n /**\n * @dev Returns the downcasted int32 from int256, reverting on\n * overflow (when the input is less than smallest int32 or\n * greater than largest int32).\n *\n * Counterpart to Solidity's `int32` operator.\n *\n * Requirements:\n *\n * - input must fit into 32 bits\n *\n * _Available since v3.1._\n */\n function toInt32(int256 value) internal pure returns (int32) {\n require(value >= type(int32).min && value <= type(int32).max, \"SafeCast: value doesn't fit in 32 bits\");\n return int32(value);\n }\n\n /**\n * @dev Returns the downcasted int16 from int256, reverting on\n * overflow (when the input is less than smallest int16 or\n * greater than largest int16).\n *\n * Counterpart to Solidity's `int16` operator.\n *\n * Requirements:\n *\n * - input must fit into 16 bits\n *\n * _Available since v3.1._\n */\n function toInt16(int256 value) internal pure returns (int16) {\n require(value >= type(int16).min && value <= type(int16).max, \"SafeCast: value doesn't fit in 16 bits\");\n return int16(value);\n }\n\n /**\n * @dev Returns the downcasted int8 from int256, reverting on\n * overflow (when the input is less than smallest int8 or\n * greater than largest int8).\n *\n * Counterpart to Solidity's `int8` operator.\n *\n * Requirements:\n *\n * - input must fit into 8 bits.\n *\n * _Available since v3.1._\n */\n function toInt8(int256 value) internal pure returns (int8) {\n require(value >= type(int8).min && value <= type(int8).max, \"SafeCast: value doesn't fit in 8 bits\");\n return int8(value);\n }\n\n /**\n * @dev Converts an unsigned uint256 into a signed int256.\n *\n * Requirements:\n *\n * - input must be less than or equal to maxInt256.\n */\n function toInt256(uint256 value) internal pure returns (int256) {\n // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\n require(value <= uint256(type(int256).max), \"SafeCast: value doesn't fit in an int256\");\n return int256(value);\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/AbstractHarvester.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 AbstractHarvester 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 virtual {\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 { AbstractHarvester } from \"./AbstractHarvester.sol\";\n\ncontract Harvester is AbstractHarvester {\n constructor(address _vault, address _usdtAddress)\n AbstractHarvester(_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 { AbstractHarvester } from \"./AbstractHarvester.sol\";\n\ncontract OETHHarvester is AbstractHarvester {\n constructor(address _vault, address _wethAddress)\n AbstractHarvester(_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 /// @notice 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;\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) 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": "// SPDX-License-Identifier: MIT\npragma 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": "// SPDX-License-Identifier: MIT\npragma 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": "// SPDX-License-Identifier: MIT\npragma 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 StrategyAddedToMintWhitelist(address indexed strategy);\n event StrategyRemovedFromMintWhitelist(address indexed strategy);\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 mintToForStrategy(address receiver, uint256 _amount) external;\n\n function redeem(uint256 _amount, uint256 _minimumUnitAmount) external;\n\n function burnForStrategy(uint256 _amount) external;\n\n function burnFromForStrategy(address user, 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 function addStrategyToMintWhitelist(address strategyAddr) external;\n\n function removeStrategyFromMintWhitelist(address strategyAddr) external;\n\n function isMintWhitelistedStrategy(address strategyAddr)\n external\n view\n returns (bool);\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/MockStrategy.sol": {
+ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\ncontract MockStrategy {\n address[] public assets;\n\n address public withdrawAllAsset;\n address public withdrawAllRecipient;\n\n constructor() {}\n\n function deposit(address asset, uint256 amount) external {}\n\n function depositAll() external {}\n\n function withdraw(\n address recipient,\n address asset,\n uint256 amount\n ) external {\n IERC20(asset).transfer(recipient, amount);\n }\n\n function withdrawAll() external {\n IERC20(withdrawAllAsset).transfer(\n withdrawAllRecipient,\n IERC20(withdrawAllAsset).balanceOf(address(this))\n );\n }\n\n function checkBalance(address asset)\n external\n view\n returns (uint256 balance)\n {\n balance = IERC20(asset).balanceOf(address(this));\n }\n\n function supportsAsset(address) external view returns (bool) {\n return true;\n }\n\n function collectRewardTokens() external {}\n\n function getRewardTokenAddresses()\n external\n view\n returns (address[] memory)\n {\n return new address[](0);\n }\n\n function setWithdrawAll(address asset, address recipient) external {\n withdrawAllAsset = asset;\n withdrawAllRecipient = recipient;\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/AbstractCompoundStrategy.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 AbstractCompoundStrategy 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/AbstractConvexMetaStrategy.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, AbstractCurveStrategy, InitializableAbstractStrategy } from \"./AbstractCurveStrategy.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { Helpers } from \"../utils/Helpers.sol\";\n\nabstract contract AbstractConvexMetaStrategy is AbstractCurveStrategy {\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[AbstractCurveStrategy]\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/AbstractCurveStrategy.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 AbstractCurveStrategy 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 uint256 assetCount = assetsMapped.length;\n for (uint256 i = 0; i < assetCount; 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/balancer/AbstractAuraStrategy.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 { AbstractBalancerStrategy } from \"./AbstractBalancerStrategy.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 AbstractAuraStrategy is AbstractBalancerStrategy {\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 AbstractBalancerStrategy.__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/AbstractBalancerStrategy.sol": {
+ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title OETH 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 AbstractBalancerStrategy 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/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 { AbstractAuraStrategy, AbstractBalancerStrategy } from \"./AbstractAuraStrategy.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 AbstractAuraStrategy {\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 AbstractBalancerStrategy(_balancerConfig)\n AbstractAuraStrategy(_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/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/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 { AbstractCompoundStrategy, InitializableAbstractStrategy } from \"./AbstractCompoundStrategy.sol\";\nimport { IComptroller } from \"../interfaces/IComptroller.sol\";\nimport { IERC20 } from \"../utils/InitializableAbstractStrategy.sol\";\n\ncontract CompoundStrategy is AbstractCompoundStrategy {\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 \"./AbstractCurveStrategy.sol\";\nimport { AbstractConvexMetaStrategy } from \"./AbstractConvexMetaStrategy.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\n\ncontract ConvexGeneralizedMetaStrategy is AbstractConvexMetaStrategy {\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 \"./AbstractCurveStrategy.sol\";\nimport { AbstractConvexMetaStrategy } from \"./AbstractConvexMetaStrategy.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\n\ncontract ConvexOUSDMetaStrategy is AbstractConvexMetaStrategy {\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, AbstractCurveStrategy, InitializableAbstractStrategy } from \"./AbstractCurveStrategy.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 `AbstractCurveStrategy`\n * storage slots would break existing implementation.\n *\n * Remove this notice if ConvexStrategy is re-deployed\n */\ncontract ConvexStrategy is AbstractCurveStrategy {\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, AbstractCompoundStrategy, InitializableAbstractStrategy } from \"./AbstractCompoundStrategy.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 AbstractCompoundStrategy {\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 // Can remove SSV validators that were incorrectly registered and can not be deposited to.\n require(\n currentState == VALIDATOR_STATE.EXITING ||\n currentState == VALIDATOR_STATE.REGISTERED,\n \"Validator not regd or 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, AbstractCurveStrategy, InitializableAbstractStrategy } from \"./AbstractCurveStrategy.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 `AbstractCurveStrategy`\n * storage slots would break existing implementation.\n *\n * Remove this notice if ThreePoolStrategy is re-deployed\n */\ncontract ThreePoolStrategy is AbstractCurveStrategy {\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/OETHBaseVaultAdmin.sol": {
+ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { VaultAdmin } from \"./VaultAdmin.sol\";\n\n/**\n * @title OETH Base VaultAdmin Contract\n * @author Origin Protocol Inc\n */\ncontract OETHBaseVaultAdmin is VaultAdmin {\n /**\n * @notice Adds a strategy to the mint whitelist.\n * Reverts if strategy isn't approved on Vault.\n * @param strategyAddr Strategy address\n */\n function addStrategyToMintWhitelist(address strategyAddr)\n external\n onlyGovernor\n {\n require(strategies[strategyAddr].isSupported, \"Strategy not approved\");\n\n require(\n !isMintWhitelistedStrategy[strategyAddr],\n \"Already whitelisted\"\n );\n\n isMintWhitelistedStrategy[strategyAddr] = true;\n\n emit StrategyAddedToMintWhitelist(strategistAddr);\n }\n\n /**\n * @notice Removes a strategy from the mint whitelist.\n * @param strategyAddr Strategy address\n */\n function removeStrategyFromMintWhitelist(address strategyAddr)\n external\n onlyGovernor\n {\n // Intentionally skipping `strategies.isSupported` check since\n // we may wanna remove an address even after removing the strategy\n\n require(isMintWhitelistedStrategy[strategyAddr], \"Not whitelisted\");\n\n isMintWhitelistedStrategy[strategyAddr] = false;\n\n emit StrategyRemovedFromMintWhitelist(strategistAddr);\n }\n}\n"
+ },
+ "contracts/vault/OETHBaseVaultCore.sol": {
+ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { OETHVaultCore } from \"./OETHVaultCore.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 Base VaultCore Contract\n * @author Origin Protocol Inc\n */\ncontract OETHBaseVaultCore is OETHVaultCore {\n using SafeERC20 for IERC20;\n using StableMath for uint256;\n\n constructor(address _weth) OETHVaultCore(_weth) {}\n\n // @inheritdoc VaultCore\n function mintForStrategy(uint256 amount)\n external\n override\n whenNotCapitalPaused\n {\n require(\n strategies[msg.sender].isSupported == true,\n \"Unsupported strategy\"\n );\n require(\n isMintWhitelistedStrategy[msg.sender] == true,\n \"Not whitelisted strategy\"\n );\n\n require(amount < MAX_INT, \"Amount too high\");\n\n emit Mint(msg.sender, amount);\n\n // Mint matching amount of OTokens\n oUSD.mint(msg.sender, amount);\n }\n\n function burnForStrategy(uint256 amount)\n external\n override\n whenNotCapitalPaused\n {\n require(\n strategies[msg.sender].isSupported == true,\n \"Unsupported strategy\"\n );\n require(\n isMintWhitelistedStrategy[msg.sender] == true,\n \"Not whitelisted strategy\"\n );\n\n require(amount < MAX_INT, \"Amount too high\");\n\n emit Redeem(msg.sender, amount);\n\n // Burn OTokens\n oUSD.burn(msg.sender, amount);\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 /// @dev Calculates the amount of WETH in the Vault that is not reserved for the withdrawal queue.\n function _wethAvailable() internal view returns (uint256 wethAvailable) {\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\n\n // The amount of WETH that is still to be claimed in the withdrawal queue\n uint256 outstandingWithdrawals = queue.queued - queue.claimed;\n\n // The amount of sitting in WETH in the vault\n uint256 wethBalance = IERC20(weth).balanceOf(address(this));\n\n // If there is more WETH in the vault than the outstanding withdrawals\n if (wethBalance > outstandingWithdrawals) {\n wethAvailable = wethBalance - outstandingWithdrawals;\n }\n }\n\n function _swapCollateral(\n address,\n address,\n uint256,\n uint256,\n bytes calldata\n ) internal pure override returns (uint256) {\n revert(\"Collateral swap not supported\");\n }\n}\n"
+ },
+ "contracts/vault/OETHVaultCore.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\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\n\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { VaultCore } from \"./VaultCore.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 uint256 public constant CLAIM_DELAY = 10 minutes;\n address public immutable weth;\n uint256 public wethAssetIndex;\n\n // For future use (because OETHBaseVaultCore inherits from this)\n uint256[50] private __gap;\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 // Is there enough WETH in the Vault available after accounting for the withdrawal queue\n require(_wethAvailable() >= amountMinusFee, \"Liquidity error\");\n\n // Transfer WETH minus the fee to the redeemer\n IERC20(weth).safeTransfer(msg.sender, amountMinusFee);\n\n // Burn OETH from user (including fees)\n oUSD.burn(msg.sender, _amount);\n\n // Prevent insolvency\n _postRedeem(_amount);\n }\n\n /**\n * @notice Request an asynchronous withdrawal of WETH in exchange for OETH.\n * The OETH is burned on request and the WETH is transferred to the withdrawer on claim.\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 * There is no minimum time or block number before a request can be claimed. It just needs\n * enough WETH liquidity in the Vault to satisfy all the outstanding requests to that point in the queue.\n * OETH is converted to WETH at 1:1.\n * @param _amount Amount of OETH to burn.\n * @param requestId Unique ID for the withdrawal request\n * @param queued Cumulative total of all WETH queued including already claimed requests.\n */\n function requestWithdrawal(uint256 _amount)\n external\n whenNotCapitalPaused\n nonReentrant\n returns (uint256 requestId, uint256 queued)\n {\n // The check that the requester has enough OETH is done in to later burn call\n\n requestId = withdrawalQueueMetadata.nextWithdrawalIndex;\n queued = withdrawalQueueMetadata.queued + _amount;\n\n // Store the next withdrawal request\n withdrawalQueueMetadata.nextWithdrawalIndex = SafeCast.toUint128(\n requestId + 1\n );\n // Store the updated queued amount which reserves WETH in the withdrawal queue\n // and reduces the vault's total assets\n withdrawalQueueMetadata.queued = SafeCast.toUint128(queued);\n // Store the user's withdrawal request\n withdrawalRequests[requestId] = WithdrawalRequest({\n withdrawer: msg.sender,\n claimed: false,\n timestamp: uint40(block.timestamp),\n amount: SafeCast.toUint128(_amount),\n queued: SafeCast.toUint128(queued)\n });\n\n // Burn the user's OETH\n oUSD.burn(msg.sender, _amount);\n\n // Prevent withdrawal if the vault is solvent by more than the the allowed percentage\n _postRedeem(_amount);\n\n emit WithdrawalRequested(msg.sender, requestId, _amount, queued);\n }\n\n // slither-disable-start reentrancy-no-eth\n /**\n * @notice Claim a previously requested withdrawal once it is claimable.\n * This request can be claimed once the withdrawal queue's `claimable` amount\n * is greater than or equal this request's `queued` amount and 10 minutes has passed.\n * If the requests is not claimable, the transaction will revert with `Queue pending liquidity`.\n * If the request is not older than 10 minutes, the transaction will revert with `Claim delay not met`.\n * OETH is converted to WETH at 1:1.\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 // Try and get more liquidity if there is not enough available\n if (\n withdrawalRequests[_requestId].queued >\n withdrawalQueueMetadata.claimable\n ) {\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 _addWithdrawalQueueLiquidity();\n }\n\n amount = _claimWithdrawal(_requestId);\n\n // transfer WETH from the vault to the withdrawer\n IERC20(weth).safeTransfer(msg.sender, amount);\n\n // Prevent insolvency\n _postRedeem(amount);\n }\n\n // slither-disable-end reentrancy-no-eth\n\n /**\n * @notice Claim a previously requested withdrawals once they are claimable.\n * This requests can be claimed once the withdrawal queue's `claimable` amount\n * is greater than or equal each request's `queued` amount and 10 minutes has passed.\n * If one of the requests is not claimable, the whole transaction will revert with `Queue pending liquidity`.\n * If one of the requests is not older than 10 minutes,\n * the whole transaction will revert with `Claim delay not met`.\n * @param _requestIds Unique ID of each withdrawal request\n * @return amounts Amount of WETH received for each request\n * @return totalAmount Total amount of WETH transferred to the withdrawer\n */\n function claimWithdrawals(uint256[] memory _requestIds)\n external\n whenNotCapitalPaused\n nonReentrant\n returns (uint256[] memory amounts, uint256 totalAmount)\n {\n // Just call the Dripper instead of looping through _requestIds to find the highest id\n // and checking it's queued amount is > the queue's claimable amount.\n\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 _addWithdrawalQueueLiquidity();\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 // Prevent insolvency\n _postRedeem(totalAmount);\n }\n\n function _claimWithdrawal(uint256 requestId)\n internal\n returns (uint256 amount)\n {\n // Load the structs from storage into memory\n WithdrawalRequest memory request = withdrawalRequests[requestId];\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\n\n require(\n request.timestamp + CLAIM_DELAY <= block.timestamp,\n \"Claim delay not met\"\n );\n // If there isn't enough reserved liquidity in the queue to claim\n require(request.queued <= queue.claimable, \"Queue pending liquidity\");\n require(request.withdrawer == msg.sender, \"Not requester\");\n require(request.claimed == false, \"Already claimed\");\n\n // Store the request as claimed\n withdrawalRequests[requestId].claimed = true;\n // Store the updated claimed amount\n withdrawalQueueMetadata.claimed = queue.claimed + request.amount;\n\n emit WithdrawalClaimed(msg.sender, requestId, request.amount);\n\n return request.amount;\n }\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 /// This assumes 1 WETH equal 1 OETH.\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 do anything is the withdrawal queue is full funded\n if (queueShortfall == 0) {\n return 0;\n }\n\n uint256 wethBalance = IERC20(weth).balanceOf(address(this));\n\n // Of the claimable withdrawal requests, how much is unclaimed?\n // That is, the amount of WETH that is currently allocated for the withdrawal queue\n uint256 allocatedWeth = queue.claimable - queue.claimed;\n\n // If there is no unallocated WETH then there is nothing to add to the queue\n if (wethBalance <= allocatedWeth) {\n return 0;\n }\n\n uint256 unallocatedWeth = wethBalance - allocatedWeth;\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 = SafeCast.toUint128(newClaimable);\n\n // emit a WithdrawalClaimable event\n emit WithdrawalClaimable(newClaimable, addedClaimable);\n }\n\n /***************************************\n View Functions\n ****************************************/\n\n /// @dev Calculate how much WETH in the vault is not reserved for the withdrawal queue.\n // That is, it is available to be redeemed or deposited into a strategy.\n function _wethAvailable() internal view returns (uint256 wethAvailable) {\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\n\n // The amount of WETH that is still to be claimed in the withdrawal queue\n uint256 outstandingWithdrawals = queue.queued - queue.claimed;\n\n // The amount of sitting in WETH in the vault\n uint256 wethBalance = IERC20(weth).balanceOf(address(this));\n\n // If there is not enough WETH in the vault to cover the outstanding withdrawals\n if (wethBalance <= outstandingWithdrawals) {\n return 0;\n }\n\n return wethBalance - outstandingWithdrawals;\n }\n\n /// @dev Get the balance of an asset held in Vault and all strategies\n /// less any WETH that is reserved for the withdrawal queue.\n /// This will only return a non-zero balance for WETH.\n /// All other assets will return 0 even if there is some dust amounts left in the Vault.\n /// For example, there is 1 wei left of stETH in the OETH Vault but will return 0 in this function.\n ///\n /// If there is not enough WETH in the vault and all strategies to cover all outstanding\n /// withdrawal requests then return a WETH balance of 0\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 if (balance + queue.claimed >= queue.queued) {\n return balance + queue.claimed - queue.queued;\n }\n }\n }\n\n /**\n * @notice Allocate unallocated funds on Vault to strategies.\n **/\n function allocate() external override whenNotCapitalPaused nonReentrant {\n // Add any unallocated WETH to the withdrawal queue first\n _addWithdrawalQueueLiquidity();\n\n _allocate();\n }\n\n /// @dev Allocate WETH to the default WETH strategy if there is excess to the Vault buffer.\n /// This is called from either `mint` or `allocate` and assumes `_addWithdrawalQueueLiquidity`\n /// has been called before this function.\n function _allocate() internal override {\n // No need to do anything if no default strategy for WETH\n address depositStrategyAddr = assetDefaultStrategies[weth];\n if (depositStrategyAddr == address(0)) return;\n\n uint256 wethAvailableInVault = _wethAvailable();\n // No need to do anything if there isn't any WETH in the vault to allocate\n if (wethAvailableInVault == 0) return;\n\n // Calculate the target buffer for the vault using the total supply\n uint256 totalSupply = oUSD.totalSupply();\n uint256 targetBuffer = totalSupply.mulTruncate(vaultBuffer);\n\n // If available WETH in the Vault is below or equal the target buffer then there's nothing to allocate\n if (wethAvailableInVault <= targetBuffer) return;\n\n // The amount of assets to allocate to the default strategy\n uint256 allocateAmount = wethAvailableInVault - targetBuffer;\n\n IStrategy strategy = IStrategy(depositStrategyAddr);\n // Transfer WETH to the strategy and call the strategy's deposit function\n IERC20(weth).safeTransfer(address(strategy), allocateAmount);\n strategy.deposit(weth, allocateAmount);\n\n emit AssetAllocated(weth, depositStrategyAddr, allocateAmount);\n }\n\n /// @dev The total value of all assets held by the vault and all its strategies\n /// less any WETH that is reserved for the withdrawal queue.\n /// For OETH, this is just WETH in the vault and strategies.\n ///\n // If there is not enough WETH in the vault and all strategies to cover all outstanding\n // withdrawal requests then return a total value of 0.\n function _totalValue() internal view override returns (uint256 value) {\n value = _totalValueInVault() + _totalValueInStrategies();\n\n // Need to remove WETH that is reserved for the withdrawal queue.\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\n // reserved for the withdrawal queue = cumulative queued total - total claimed\n uint256 reservedForQueue = queue.queued - queue.claimed;\n\n if (value < reservedForQueue) {\n // This can happen if the vault becomes insolvent enough that the\n // total value in the vault and all strategies is less than the outstanding withdrawals.\n // For example, there was a mass slashing event and most users request a withdrawal.\n return 0;\n }\n\n // Adjust the total value by the amount reserved for the withdrawal queue\n return value - reservedForQueue;\n }\n\n /// @dev Only WETH is supported in the OETH Vault so return the WETH balance only\n /// Any ETH balances in the Vault will be ignored.\n /// Amounts from previously supported vault assets will also be ignored.\n /// For example, there is 1 wei left of stETH in the OETH Vault but is will be ignored.\n function _totalValueInVault()\n internal\n view\n override\n returns (uint256 value)\n {\n value = IERC20(weth).balanceOf(address(this));\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 virtual\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 // If there are more outstanding withdrawal requests than assets in the vault and strategies\n // then the available assets will be negative and totalUnits will be rounded up to zero.\n // As we don't know the exact shortfall amount, we will reject all redeem and withdrawals\n require(totalUnits > 0, \"Too many outstanding requests\");\n\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 virtual\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 virtual 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 StrategyAddedToMintWhitelist(address indexed strategy);\n event StrategyRemovedFromMintWhitelist(address indexed strategy);\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 // slither-disable-next-line uninitialized-state\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\n // slither-disable-start constable-states\n // slither-disable-next-line uninitialized-state\n address public ousdMetaStrategy;\n\n /// @notice How much OTokens are currently minted by the strategy\n // slither-disable-next-line uninitialized-state\n int256 public netOusdMintedForStrategy;\n\n /// @notice How much net total OTokens are allowed to be minted by all strategies\n // slither-disable-next-line uninitialized-state\n uint256 public netOusdMintForStrategyThreshold;\n\n // slither-disable-end constable-states\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 // List of strategies that can mint oTokens directly\n // Used in OETHBaseVaultCore\n // slither-disable-next-line uninitialized-state\n mapping(address => bool) public isMintWhitelistedStrategy;\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 including 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 /// @notice Global metadata for the withdrawal queue including:\n /// queued - cumulative total of all withdrawal requests included the ones that have already been claimed\n /// claimable - cumulative total of all the requests that can be claimed including the ones already claimed\n /// claimed - total of all the requests that have been claimed\n /// nextWithdrawalIndex - index of the next withdrawal request starting at 0\n // slither-disable-next-line uninitialized-state\n WithdrawalQueueMetadata public withdrawalQueueMetadata;\n\n struct WithdrawalRequest {\n address withdrawer;\n bool claimed;\n uint40 timestamp; // timestamp of the withdrawal request\n // Amount of oTokens to redeem. eg OETH\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 /// @notice Mapping of withdrawal request indices to the user withdrawal request data\n mapping(uint256 => WithdrawalRequest) public withdrawalRequests;\n\n // For future use\n uint256[45] 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/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/DripperHierarchy.svg b/contracts/docs/DripperHierarchy.svg
index 903646a877..0f27419ec5 100644
--- a/contracts/docs/DripperHierarchy.svg
+++ b/contracts/docs/DripperHierarchy.svg
@@ -29,109 +29,109 @@
-
+
-55
+61<<Interface>>IVault../contracts/interfaces/IVault.sol
-
+
-30->55
+30->61
-
+
-392
+710<<Interface>>IERC20../node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol
-
+
-30->392
+30->710
-
+
-207
+239VaultStorage../contracts/vault/VaultStorage.sol
-
+
-55->207
+61->239
-
+
-186
+215OUSD../contracts/token/OUSD.sol
-
+
-186->20
+215->20
-
+
-194
+224<<Abstract>>Initializable../contracts/utils/Initializable.sol
-
+
-186->194
+215->224
-
+
-197
+227<<Abstract>>InitializableERC20Detailed../contracts/utils/InitializableERC20Detailed.sol
-
+
-186->197
+215->227
-
+
-197->392
+227->710
-
+
-207->20
+239->20
-
+
-207->186
+239->215
-
+
-207->194
+239->224
diff --git a/contracts/docs/HarvesterHierarchy.svg b/contracts/docs/HarvesterHierarchy.svg
index f455ae8685..c4334d5fd1 100644
--- a/contracts/docs/HarvesterHierarchy.svg
+++ b/contracts/docs/HarvesterHierarchy.svg
@@ -19,127 +19,127 @@
26
-
+<<Abstract>>
-BaseHarvester
-../contracts/harvest/BaseHarvester.sol
+AbstractHarvester
+../contracts/harvest/AbstractHarvester.sol26->20
-
+
-
+
-48
+51<<Interface>>IOracle../contracts/interfaces/IOracle.sol
-
+
-26->48
-
-
+26->51
+
+
-
+
-52
+57<<Interface>>IStrategy../contracts/interfaces/IStrategy.sol
-
+
-26->52
+26->57
-
+
-55
+61<<Interface>>IVault../contracts/interfaces/IVault.sol
-
+
-26->55
+26->61
-
+
-214
+249<<Interface>>IBalancerVault../contracts/interfaces/balancer/IBalancerVault.sol
-
+
-26->214
+26->249
-
+
-245
+280<<Interface>>IUniswapV2Router../contracts/interfaces/uniswap/IUniswapV2Router02.sol
-
+
-26->245
-
+26->280
+
-
+
-246
+281<<Interface>>IUniswapV3Router../contracts/interfaces/uniswap/IUniswapV3Router.sol
-
+
-26->246
-
+26->281
+
-
+
-174
+199<<Interface>>ICurvePool../contracts/strategies/ICurvePool.sol
-
+
-26->174
-
-
+26->199
+
+
-
+
-392
+710<<Interface>>IERC20../node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol
-
+
-26->392
-
+26->710
+
@@ -155,81 +155,81 @@
-
+
-207
+239VaultStorage../contracts/vault/VaultStorage.sol
-
+
-55->207
+61->239
-
+
-186
+215OUSD../contracts/token/OUSD.sol
-
+
-186->20
+215->20
-
+
-194
+224<<Abstract>>Initializable../contracts/utils/Initializable.sol
-
+
-186->194
+215->224
-
+
-197
+227<<Abstract>>InitializableERC20Detailed../contracts/utils/InitializableERC20Detailed.sol
-
+
-186->197
+215->227
-
+
-197->392
+227->710
-
+
-207->20
+239->20
-
+
-207->186
+239->215
-
+
-207->194
+239->224
diff --git a/contracts/docs/HarvesterSquashed.svg b/contracts/docs/HarvesterSquashed.svg
index 80a9d1631d..1803a1e1fb 100644
--- a/contracts/docs/HarvesterSquashed.svg
+++ b/contracts/docs/HarvesterSquashed.svg
@@ -4,18 +4,18 @@
-